tests: Factor out common code into 'is_available' function.
[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     (* Opaque buffer which can contain arbitrary 8 bit data.
168      * In the C API, this is expressed as <const char *, size_t> pair.
169      * Most other languages have a string type which can contain
170      * ASCII NUL.  We use whatever type is appropriate for each
171      * language.
172      * Buffers are limited by the total message size.  To transfer
173      * large blocks of data, use FileIn/FileOut parameters instead.
174      * To return an arbitrary buffer, use RBufferOut.
175      *)
176   | BufferIn of string
177
178 type flags =
179   | ProtocolLimitWarning  (* display warning about protocol size limits *)
180   | DangerWillRobinson    (* flags particularly dangerous commands *)
181   | FishAlias of string   (* provide an alias for this cmd in guestfish *)
182   | FishOutput of fish_output_t (* how to display output in guestfish *)
183   | NotInFish             (* do not export via guestfish *)
184   | NotInDocs             (* do not add this function to documentation *)
185   | DeprecatedBy of string (* function is deprecated, use .. instead *)
186   | Optional of string    (* function is part of an optional group *)
187
188 and fish_output_t =
189   | FishOutputOctal       (* for int return, print in octal *)
190   | FishOutputHexadecimal (* for int return, print in hex *)
191
192 (* You can supply zero or as many tests as you want per API call.
193  *
194  * Note that the test environment has 3 block devices, of size 500MB,
195  * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
196  * a fourth ISO block device with some known files on it (/dev/sdd).
197  *
198  * Note for partitioning purposes, the 500MB device has 1015 cylinders.
199  * Number of cylinders was 63 for IDE emulated disks with precisely
200  * the same size.  How exactly this is calculated is a mystery.
201  *
202  * The ISO block device (/dev/sdd) comes from images/test.iso.
203  *
204  * To be able to run the tests in a reasonable amount of time,
205  * the virtual machine and block devices are reused between tests.
206  * So don't try testing kill_subprocess :-x
207  *
208  * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
209  *
210  * Don't assume anything about the previous contents of the block
211  * devices.  Use 'Init*' to create some initial scenarios.
212  *
213  * You can add a prerequisite clause to any individual test.  This
214  * is a run-time check, which, if it fails, causes the test to be
215  * skipped.  Useful if testing a command which might not work on
216  * all variations of libguestfs builds.  A test that has prerequisite
217  * of 'Always' is run unconditionally.
218  *
219  * In addition, packagers can skip individual tests by setting the
220  * environment variables:     eg:
221  *   SKIP_TEST_<CMD>_<NUM>=1  SKIP_TEST_COMMAND_3=1  (skips test #3 of command)
222  *   SKIP_TEST_<CMD>=1        SKIP_TEST_ZEROFREE=1   (skips all zerofree tests)
223  *)
224 type tests = (test_init * test_prereq * test) list
225 and test =
226     (* Run the command sequence and just expect nothing to fail. *)
227   | TestRun of seq
228
229     (* Run the command sequence and expect the output of the final
230      * command to be the string.
231      *)
232   | TestOutput of seq * string
233
234     (* Run the command sequence and expect the output of the final
235      * command to be the list of strings.
236      *)
237   | TestOutputList of seq * string list
238
239     (* Run the command sequence and expect the output of the final
240      * command to be the list of block devices (could be either
241      * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
242      * character of each string).
243      *)
244   | TestOutputListOfDevices of seq * string list
245
246     (* Run the command sequence and expect the output of the final
247      * command to be the integer.
248      *)
249   | TestOutputInt of seq * int
250
251     (* Run the command sequence and expect the output of the final
252      * command to be <op> <int>, eg. ">=", "1".
253      *)
254   | TestOutputIntOp of seq * string * int
255
256     (* Run the command sequence and expect the output of the final
257      * command to be a true value (!= 0 or != NULL).
258      *)
259   | TestOutputTrue of seq
260
261     (* Run the command sequence and expect the output of the final
262      * command to be a false value (== 0 or == NULL, but not an error).
263      *)
264   | TestOutputFalse of seq
265
266     (* Run the command sequence and expect the output of the final
267      * command to be a list of the given length (but don't care about
268      * content).
269      *)
270   | TestOutputLength of seq * int
271
272     (* Run the command sequence and expect the output of the final
273      * command to be a buffer (RBufferOut), ie. string + size.
274      *)
275   | TestOutputBuffer of seq * string
276
277     (* Run the command sequence and expect the output of the final
278      * command to be a structure.
279      *)
280   | TestOutputStruct of seq * test_field_compare list
281
282     (* Run the command sequence and expect the final command (only)
283      * to fail.
284      *)
285   | TestLastFail of seq
286
287 and test_field_compare =
288   | CompareWithInt of string * int
289   | CompareWithIntOp of string * string * int
290   | CompareWithString of string * string
291   | CompareFieldsIntEq of string * string
292   | CompareFieldsStrEq of string * string
293
294 (* Test prerequisites. *)
295 and test_prereq =
296     (* Test always runs. *)
297   | Always
298
299     (* Test is currently disabled - eg. it fails, or it tests some
300      * unimplemented feature.
301      *)
302   | Disabled
303
304     (* 'string' is some C code (a function body) that should return
305      * true or false.  The test will run if the code returns true.
306      *)
307   | If of string
308
309     (* As for 'If' but the test runs _unless_ the code returns true. *)
310   | Unless of string
311
312 (* Some initial scenarios for testing. *)
313 and test_init =
314     (* Do nothing, block devices could contain random stuff including
315      * LVM PVs, and some filesystems might be mounted.  This is usually
316      * a bad idea.
317      *)
318   | InitNone
319
320     (* Block devices are empty and no filesystems are mounted. *)
321   | InitEmpty
322
323     (* /dev/sda contains a single partition /dev/sda1, with random
324      * content.  /dev/sdb and /dev/sdc may have random content.
325      * No LVM.
326      *)
327   | InitPartition
328
329     (* /dev/sda contains a single partition /dev/sda1, which is formatted
330      * as ext2, empty [except for lost+found] and mounted on /.
331      * /dev/sdb and /dev/sdc may have random content.
332      * No LVM.
333      *)
334   | InitBasicFS
335
336     (* /dev/sda:
337      *   /dev/sda1 (is a PV):
338      *     /dev/VG/LV (size 8MB):
339      *       formatted as ext2, empty [except for lost+found], mounted on /
340      * /dev/sdb and /dev/sdc may have random content.
341      *)
342   | InitBasicFSonLVM
343
344     (* /dev/sdd (the ISO, see images/ directory in source)
345      * is mounted on /
346      *)
347   | InitISOFS
348
349 (* Sequence of commands for testing. *)
350 and seq = cmd list
351 and cmd = string list
352
353 (* Note about long descriptions: When referring to another
354  * action, use the format C<guestfs_other> (ie. the full name of
355  * the C function).  This will be replaced as appropriate in other
356  * language bindings.
357  *
358  * Apart from that, long descriptions are just perldoc paragraphs.
359  *)
360
361 (* Generate a random UUID (used in tests). *)
362 let uuidgen () =
363   let chan = open_process_in "uuidgen" in
364   let uuid = input_line chan in
365   (match close_process_in chan with
366    | WEXITED 0 -> ()
367    | WEXITED _ ->
368        failwith "uuidgen: process exited with non-zero status"
369    | WSIGNALED _ | WSTOPPED _ ->
370        failwith "uuidgen: process signalled or stopped by signal"
371   );
372   uuid
373
374 (* These test functions are used in the language binding tests. *)
375
376 let test_all_args = [
377   String "str";
378   OptString "optstr";
379   StringList "strlist";
380   Bool "b";
381   Int "integer";
382   Int64 "integer64";
383   FileIn "filein";
384   FileOut "fileout";
385   BufferIn "bufferin";
386 ]
387
388 let test_all_rets = [
389   (* except for RErr, which is tested thoroughly elsewhere *)
390   "test0rint",         RInt "valout";
391   "test0rint64",       RInt64 "valout";
392   "test0rbool",        RBool "valout";
393   "test0rconststring", RConstString "valout";
394   "test0rconstoptstring", RConstOptString "valout";
395   "test0rstring",      RString "valout";
396   "test0rstringlist",  RStringList "valout";
397   "test0rstruct",      RStruct ("valout", "lvm_pv");
398   "test0rstructlist",  RStructList ("valout", "lvm_pv");
399   "test0rhashtable",   RHashtable "valout";
400 ]
401
402 let test_functions = [
403   ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
404    [],
405    "internal test function - do not use",
406    "\
407 This is an internal test function which is used to test whether
408 the automatically generated bindings can handle every possible
409 parameter type correctly.
410
411 It echos the contents of each parameter to stdout.
412
413 You probably don't want to call this function.");
414 ] @ List.flatten (
415   List.map (
416     fun (name, ret) ->
417       [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
418         [],
419         "internal test function - do not use",
420         "\
421 This is an internal test function which is used to test whether
422 the automatically generated bindings can handle every possible
423 return type correctly.
424
425 It converts string C<val> to the return type.
426
427 You probably don't want to call this function.");
428        (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
429         [],
430         "internal test function - do not use",
431         "\
432 This is an internal test function which is used to test whether
433 the automatically generated bindings can handle every possible
434 return type correctly.
435
436 This function always returns an error.
437
438 You probably don't want to call this function.")]
439   ) test_all_rets
440 )
441
442 (* non_daemon_functions are any functions which don't get processed
443  * in the daemon, eg. functions for setting and getting local
444  * configuration values.
445  *)
446
447 let non_daemon_functions = test_functions @ [
448   ("launch", (RErr, []), -1, [FishAlias "run"],
449    [],
450    "launch the qemu subprocess",
451    "\
452 Internally libguestfs is implemented by running a virtual machine
453 using L<qemu(1)>.
454
455 You should call this after configuring the handle
456 (eg. adding drives) but before performing any actions.");
457
458   ("wait_ready", (RErr, []), -1, [NotInFish],
459    [],
460    "wait until the qemu subprocess launches (no op)",
461    "\
462 This function is a no op.
463
464 In versions of the API E<lt> 1.0.71 you had to call this function
465 just after calling C<guestfs_launch> to wait for the launch
466 to complete.  However this is no longer necessary because
467 C<guestfs_launch> now does the waiting.
468
469 If you see any calls to this function in code then you can just
470 remove them, unless you want to retain compatibility with older
471 versions of the API.");
472
473   ("kill_subprocess", (RErr, []), -1, [],
474    [],
475    "kill the qemu subprocess",
476    "\
477 This kills the qemu subprocess.  You should never need to call this.");
478
479   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
480    [],
481    "add an image to examine or modify",
482    "\
483 This function adds a virtual machine disk image C<filename> to the
484 guest.  The first time you call this function, the disk appears as IDE
485 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
486 so on.
487
488 You don't necessarily need to be root when using libguestfs.  However
489 you obviously do need sufficient permissions to access the filename
490 for whatever operations you want to perform (ie. read access if you
491 just want to read the image or write access if you want to modify the
492 image).
493
494 This is equivalent to the qemu parameter
495 C<-drive file=filename,cache=off,if=...>.
496
497 C<cache=off> is omitted in cases where it is not supported by
498 the underlying filesystem.
499
500 C<if=...> is set at compile time by the configuration option
501 C<./configure --with-drive-if=...>.  In the rare case where you
502 might need to change this at run time, use C<guestfs_add_drive_with_if>
503 or C<guestfs_add_drive_ro_with_if>.
504
505 Note that this call checks for the existence of C<filename>.  This
506 stops you from specifying other types of drive which are supported
507 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
508 the general C<guestfs_config> call instead.");
509
510   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
511    [],
512    "add a CD-ROM disk image to examine",
513    "\
514 This function adds a virtual CD-ROM disk image to the guest.
515
516 This is equivalent to the qemu parameter C<-cdrom filename>.
517
518 Notes:
519
520 =over 4
521
522 =item *
523
524 This call checks for the existence of C<filename>.  This
525 stops you from specifying other types of drive which are supported
526 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
527 the general C<guestfs_config> call instead.
528
529 =item *
530
531 If you just want to add an ISO file (often you use this as an
532 efficient way to transfer large files into the guest), then you
533 should probably use C<guestfs_add_drive_ro> instead.
534
535 =back");
536
537   ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
538    [],
539    "add a drive in snapshot mode (read-only)",
540    "\
541 This adds a drive in snapshot mode, making it effectively
542 read-only.
543
544 Note that writes to the device are allowed, and will be seen for
545 the duration of the guestfs handle, but they are written
546 to a temporary file which is discarded as soon as the guestfs
547 handle is closed.  We don't currently have any method to enable
548 changes to be committed, although qemu can support this.
549
550 This is equivalent to the qemu parameter
551 C<-drive file=filename,snapshot=on,readonly=on,if=...>.
552
553 C<if=...> is set at compile time by the configuration option
554 C<./configure --with-drive-if=...>.  In the rare case where you
555 might need to change this at run time, use C<guestfs_add_drive_with_if>
556 or C<guestfs_add_drive_ro_with_if>.
557
558 C<readonly=on> is only added where qemu supports this option.
559
560 Note that this call checks for the existence of C<filename>.  This
561 stops you from specifying other types of drive which are supported
562 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
563 the general C<guestfs_config> call instead.");
564
565   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
566    [],
567    "add qemu parameters",
568    "\
569 This can be used to add arbitrary qemu command line parameters
570 of the form C<-param value>.  Actually it's not quite arbitrary - we
571 prevent you from setting some parameters which would interfere with
572 parameters that we use.
573
574 The first character of C<param> string must be a C<-> (dash).
575
576 C<value> can be NULL.");
577
578   ("set_qemu", (RErr, [OptString "qemu"]), -1, [FishAlias "qemu"],
579    [],
580    "set the qemu binary",
581    "\
582 Set the qemu binary that we will use.
583
584 The default is chosen when the library was compiled by the
585 configure script.
586
587 You can also override this by setting the C<LIBGUESTFS_QEMU>
588 environment variable.
589
590 Setting C<qemu> to C<NULL> restores the default qemu binary.
591
592 Note that you should call this function as early as possible
593 after creating the handle.  This is because some pre-launch
594 operations depend on testing qemu features (by running C<qemu -help>).
595 If the qemu binary changes, we don't retest features, and
596 so you might see inconsistent results.  Using the environment
597 variable C<LIBGUESTFS_QEMU> is safest of all since that picks
598 the qemu binary at the same time as the handle is created.");
599
600   ("get_qemu", (RConstString "qemu", []), -1, [],
601    [InitNone, Always, TestRun (
602       [["get_qemu"]])],
603    "get the qemu binary",
604    "\
605 Return the current qemu binary.
606
607 This is always non-NULL.  If it wasn't set already, then this will
608 return the default qemu binary name.");
609
610   ("set_path", (RErr, [OptString "searchpath"]), -1, [FishAlias "path"],
611    [],
612    "set the search path",
613    "\
614 Set the path that libguestfs searches for kernel and initrd.img.
615
616 The default is C<$libdir/guestfs> unless overridden by setting
617 C<LIBGUESTFS_PATH> environment variable.
618
619 Setting C<path> to C<NULL> restores the default path.");
620
621   ("get_path", (RConstString "path", []), -1, [],
622    [InitNone, Always, TestRun (
623       [["get_path"]])],
624    "get the search path",
625    "\
626 Return the current search path.
627
628 This is always non-NULL.  If it wasn't set already, then this will
629 return the default path.");
630
631   ("set_append", (RErr, [OptString "append"]), -1, [FishAlias "append"],
632    [],
633    "add options to kernel command line",
634    "\
635 This function is used to add additional options to the
636 guest kernel command line.
637
638 The default is C<NULL> unless overridden by setting
639 C<LIBGUESTFS_APPEND> environment variable.
640
641 Setting C<append> to C<NULL> means I<no> additional options
642 are passed (libguestfs always adds a few of its own).");
643
644   ("get_append", (RConstOptString "append", []), -1, [],
645    (* This cannot be tested with the current framework.  The
646     * function can return NULL in normal operations, which the
647     * test framework interprets as an error.
648     *)
649    [],
650    "get the additional kernel options",
651    "\
652 Return the additional kernel options which are added to the
653 guest kernel command line.
654
655 If C<NULL> then no options are added.");
656
657   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
658    [],
659    "set autosync mode",
660    "\
661 If C<autosync> is true, this enables autosync.  Libguestfs will make a
662 best effort attempt to run C<guestfs_umount_all> followed by
663 C<guestfs_sync> when the handle is closed
664 (also if the program exits without closing handles).
665
666 This is disabled by default (except in guestfish where it is
667 enabled by default).");
668
669   ("get_autosync", (RBool "autosync", []), -1, [],
670    [InitNone, Always, TestRun (
671       [["get_autosync"]])],
672    "get autosync mode",
673    "\
674 Get the autosync flag.");
675
676   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
677    [],
678    "set verbose mode",
679    "\
680 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
681
682 Verbose messages are disabled unless the environment variable
683 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
684
685   ("get_verbose", (RBool "verbose", []), -1, [],
686    [],
687    "get verbose mode",
688    "\
689 This returns the verbose messages flag.");
690
691   ("is_ready", (RBool "ready", []), -1, [],
692    [InitNone, Always, TestOutputTrue (
693       [["is_ready"]])],
694    "is ready to accept commands",
695    "\
696 This returns true iff this handle is ready to accept commands
697 (in the C<READY> state).
698
699 For more information on states, see L<guestfs(3)>.");
700
701   ("is_config", (RBool "config", []), -1, [],
702    [InitNone, Always, TestOutputFalse (
703       [["is_config"]])],
704    "is in configuration state",
705    "\
706 This returns true iff this handle is being configured
707 (in the C<CONFIG> state).
708
709 For more information on states, see L<guestfs(3)>.");
710
711   ("is_launching", (RBool "launching", []), -1, [],
712    [InitNone, Always, TestOutputFalse (
713       [["is_launching"]])],
714    "is launching subprocess",
715    "\
716 This returns true iff this handle is launching the subprocess
717 (in the C<LAUNCHING> state).
718
719 For more information on states, see L<guestfs(3)>.");
720
721   ("is_busy", (RBool "busy", []), -1, [],
722    [InitNone, Always, TestOutputFalse (
723       [["is_busy"]])],
724    "is busy processing a command",
725    "\
726 This returns true iff this handle is busy processing a command
727 (in the C<BUSY> state).
728
729 For more information on states, see L<guestfs(3)>.");
730
731   ("get_state", (RInt "state", []), -1, [],
732    [],
733    "get the current state",
734    "\
735 This returns the current state as an opaque integer.  This is
736 only useful for printing debug and internal error messages.
737
738 For more information on states, see L<guestfs(3)>.");
739
740   ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
741    [InitNone, Always, TestOutputInt (
742       [["set_memsize"; "500"];
743        ["get_memsize"]], 500)],
744    "set memory allocated to the qemu subprocess",
745    "\
746 This sets the memory size in megabytes allocated to the
747 qemu subprocess.  This only has any effect if called before
748 C<guestfs_launch>.
749
750 You can also change this by setting the environment
751 variable C<LIBGUESTFS_MEMSIZE> before the handle is
752 created.
753
754 For more information on the architecture of libguestfs,
755 see L<guestfs(3)>.");
756
757   ("get_memsize", (RInt "memsize", []), -1, [],
758    [InitNone, Always, TestOutputIntOp (
759       [["get_memsize"]], ">=", 256)],
760    "get memory allocated to the qemu subprocess",
761    "\
762 This gets the memory size in megabytes allocated to the
763 qemu subprocess.
764
765 If C<guestfs_set_memsize> was not called
766 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
767 then this returns the compiled-in default value for memsize.
768
769 For more information on the architecture of libguestfs,
770 see L<guestfs(3)>.");
771
772   ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"],
773    [InitNone, Always, TestOutputIntOp (
774       [["get_pid"]], ">=", 1)],
775    "get PID of qemu subprocess",
776    "\
777 Return the process ID of the qemu subprocess.  If there is no
778 qemu subprocess, then this will return an error.
779
780 This is an internal call used for debugging and testing.");
781
782   ("version", (RStruct ("version", "version"), []), -1, [],
783    [InitNone, Always, TestOutputStruct (
784       [["version"]], [CompareWithInt ("major", 1)])],
785    "get the library version number",
786    "\
787 Return the libguestfs version number that the program is linked
788 against.
789
790 Note that because of dynamic linking this is not necessarily
791 the version of libguestfs that you compiled against.  You can
792 compile the program, and then at runtime dynamically link
793 against a completely different C<libguestfs.so> library.
794
795 This call was added in version C<1.0.58>.  In previous
796 versions of libguestfs there was no way to get the version
797 number.  From C code you can use dynamic linker functions
798 to find out if this symbol exists (if it doesn't, then
799 it's an earlier version).
800
801 The call returns a structure with four elements.  The first
802 three (C<major>, C<minor> and C<release>) are numbers and
803 correspond to the usual version triplet.  The fourth element
804 (C<extra>) is a string and is normally empty, but may be
805 used for distro-specific information.
806
807 To construct the original version string:
808 C<$major.$minor.$release$extra>
809
810 See also: L<guestfs(3)/LIBGUESTFS VERSION NUMBERS>.
811
812 I<Note:> Don't use this call to test for availability
813 of features.  In enterprise distributions we backport
814 features from later versions into earlier versions,
815 making this an unreliable way to test for features.
816 Use C<guestfs_available> instead.");
817
818   ("set_selinux", (RErr, [Bool "selinux"]), -1, [FishAlias "selinux"],
819    [InitNone, Always, TestOutputTrue (
820       [["set_selinux"; "true"];
821        ["get_selinux"]])],
822    "set SELinux enabled or disabled at appliance boot",
823    "\
824 This sets the selinux flag that is passed to the appliance
825 at boot time.  The default is C<selinux=0> (disabled).
826
827 Note that if SELinux is enabled, it is always in
828 Permissive mode (C<enforcing=0>).
829
830 For more information on the architecture of libguestfs,
831 see L<guestfs(3)>.");
832
833   ("get_selinux", (RBool "selinux", []), -1, [],
834    [],
835    "get SELinux enabled flag",
836    "\
837 This returns the current setting of the selinux flag which
838 is passed to the appliance at boot time.  See C<guestfs_set_selinux>.
839
840 For more information on the architecture of libguestfs,
841 see L<guestfs(3)>.");
842
843   ("set_trace", (RErr, [Bool "trace"]), -1, [FishAlias "trace"],
844    [InitNone, Always, TestOutputFalse (
845       [["set_trace"; "false"];
846        ["get_trace"]])],
847    "enable or disable command traces",
848    "\
849 If the command trace flag is set to 1, then commands are
850 printed on stdout before they are executed in a format
851 which is very similar to the one used by guestfish.  In
852 other words, you can run a program with this enabled, and
853 you will get out a script which you can feed to guestfish
854 to perform the same set of actions.
855
856 If you want to trace C API calls into libguestfs (and
857 other libraries) then possibly a better way is to use
858 the external ltrace(1) command.
859
860 Command traces are disabled unless the environment variable
861 C<LIBGUESTFS_TRACE> is defined and set to C<1>.");
862
863   ("get_trace", (RBool "trace", []), -1, [],
864    [],
865    "get command trace enabled flag",
866    "\
867 Return the command trace flag.");
868
869   ("set_direct", (RErr, [Bool "direct"]), -1, [FishAlias "direct"],
870    [InitNone, Always, TestOutputFalse (
871       [["set_direct"; "false"];
872        ["get_direct"]])],
873    "enable or disable direct appliance mode",
874    "\
875 If the direct appliance mode flag is enabled, then stdin and
876 stdout are passed directly through to the appliance once it
877 is launched.
878
879 One consequence of this is that log messages aren't caught
880 by the library and handled by C<guestfs_set_log_message_callback>,
881 but go straight to stdout.
882
883 You probably don't want to use this unless you know what you
884 are doing.
885
886 The default is disabled.");
887
888   ("get_direct", (RBool "direct", []), -1, [],
889    [],
890    "get direct appliance mode flag",
891    "\
892 Return the direct appliance mode flag.");
893
894   ("set_recovery_proc", (RErr, [Bool "recoveryproc"]), -1, [FishAlias "recovery-proc"],
895    [InitNone, Always, TestOutputTrue (
896       [["set_recovery_proc"; "true"];
897        ["get_recovery_proc"]])],
898    "enable or disable the recovery process",
899    "\
900 If this is called with the parameter C<false> then
901 C<guestfs_launch> does not create a recovery process.  The
902 purpose of the recovery process is to stop runaway qemu
903 processes in the case where the main program aborts abruptly.
904
905 This only has any effect if called before C<guestfs_launch>,
906 and the default is true.
907
908 About the only time when you would want to disable this is
909 if the main process will fork itself into the background
910 (\"daemonize\" itself).  In this case the recovery process
911 thinks that the main program has disappeared and so kills
912 qemu, which is not very helpful.");
913
914   ("get_recovery_proc", (RBool "recoveryproc", []), -1, [],
915    [],
916    "get recovery process enabled flag",
917    "\
918 Return the recovery process enabled flag.");
919
920   ("add_drive_with_if", (RErr, [String "filename"; String "iface"]), -1, [],
921    [],
922    "add a drive specifying the QEMU block emulation to use",
923    "\
924 This is the same as C<guestfs_add_drive> but it allows you
925 to specify the QEMU interface emulation to use at run time.");
926
927   ("add_drive_ro_with_if", (RErr, [String "filename"; String "iface"]), -1, [],
928    [],
929    "add a drive read-only specifying the QEMU block emulation to use",
930    "\
931 This is the same as C<guestfs_add_drive_ro> but it allows you
932 to specify the QEMU interface emulation to use at run time.");
933
934 ]
935
936 (* daemon_functions are any functions which cause some action
937  * to take place in the daemon.
938  *)
939
940 let daemon_functions = [
941   ("mount", (RErr, [Device "device"; String "mountpoint"]), 1, [],
942    [InitEmpty, Always, TestOutput (
943       [["part_disk"; "/dev/sda"; "mbr"];
944        ["mkfs"; "ext2"; "/dev/sda1"];
945        ["mount"; "/dev/sda1"; "/"];
946        ["write"; "/new"; "new file contents"];
947        ["cat"; "/new"]], "new file contents")],
948    "mount a guest disk at a position in the filesystem",
949    "\
950 Mount a guest disk at a position in the filesystem.  Block devices
951 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
952 the guest.  If those block devices contain partitions, they will have
953 the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
954 names can be used.
955
956 The rules are the same as for L<mount(2)>:  A filesystem must
957 first be mounted on C</> before others can be mounted.  Other
958 filesystems can only be mounted on directories which already
959 exist.
960
961 The mounted filesystem is writable, if we have sufficient permissions
962 on the underlying device.
963
964 B<Important note:>
965 When you use this call, the filesystem options C<sync> and C<noatime>
966 are set implicitly.  This was originally done because we thought it
967 would improve reliability, but it turns out that I<-o sync> has a
968 very large negative performance impact and negligible effect on
969 reliability.  Therefore we recommend that you avoid using
970 C<guestfs_mount> in any code that needs performance, and instead
971 use C<guestfs_mount_options> (use an empty string for the first
972 parameter if you don't want any options).");
973
974   ("sync", (RErr, []), 2, [],
975    [ InitEmpty, Always, TestRun [["sync"]]],
976    "sync disks, writes are flushed through to the disk image",
977    "\
978 This syncs the disk, so that any writes are flushed through to the
979 underlying disk image.
980
981 You should always call this if you have modified a disk image, before
982 closing the handle.");
983
984   ("touch", (RErr, [Pathname "path"]), 3, [],
985    [InitBasicFS, Always, TestOutputTrue (
986       [["touch"; "/new"];
987        ["exists"; "/new"]])],
988    "update file timestamps or create a new file",
989    "\
990 Touch acts like the L<touch(1)> command.  It can be used to
991 update the timestamps on a file, or, if the file does not exist,
992 to create a new zero-length file.");
993
994   ("cat", (RString "content", [Pathname "path"]), 4, [ProtocolLimitWarning],
995    [InitISOFS, Always, TestOutput (
996       [["cat"; "/known-2"]], "abcdef\n")],
997    "list the contents of a file",
998    "\
999 Return the contents of the file named C<path>.
1000
1001 Note that this function cannot correctly handle binary files
1002 (specifically, files containing C<\\0> character which is treated
1003 as end of string).  For those you need to use the C<guestfs_read_file>
1004 or C<guestfs_download> functions which have a more complex interface.");
1005
1006   ("ll", (RString "listing", [Pathname "directory"]), 5, [],
1007    [], (* XXX Tricky to test because it depends on the exact format
1008         * of the 'ls -l' command, which changes between F10 and F11.
1009         *)
1010    "list the files in a directory (long format)",
1011    "\
1012 List the files in C<directory> (relative to the root directory,
1013 there is no cwd) in the format of 'ls -la'.
1014
1015 This command is mostly useful for interactive sessions.  It
1016 is I<not> intended that you try to parse the output string.");
1017
1018   ("ls", (RStringList "listing", [Pathname "directory"]), 6, [],
1019    [InitBasicFS, Always, TestOutputList (
1020       [["touch"; "/new"];
1021        ["touch"; "/newer"];
1022        ["touch"; "/newest"];
1023        ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
1024    "list the files in a directory",
1025    "\
1026 List the files in C<directory> (relative to the root directory,
1027 there is no cwd).  The '.' and '..' entries are not returned, but
1028 hidden files are shown.
1029
1030 This command is mostly useful for interactive sessions.  Programs
1031 should probably use C<guestfs_readdir> instead.");
1032
1033   ("list_devices", (RStringList "devices", []), 7, [],
1034    [InitEmpty, Always, TestOutputListOfDevices (
1035       [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
1036    "list the block devices",
1037    "\
1038 List all the block devices.
1039
1040 The full block device names are returned, eg. C</dev/sda>");
1041
1042   ("list_partitions", (RStringList "partitions", []), 8, [],
1043    [InitBasicFS, Always, TestOutputListOfDevices (
1044       [["list_partitions"]], ["/dev/sda1"]);
1045     InitEmpty, Always, TestOutputListOfDevices (
1046       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1047        ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1048    "list the partitions",
1049    "\
1050 List all the partitions detected on all block devices.
1051
1052 The full partition device names are returned, eg. C</dev/sda1>
1053
1054 This does not return logical volumes.  For that you will need to
1055 call C<guestfs_lvs>.");
1056
1057   ("pvs", (RStringList "physvols", []), 9, [Optional "lvm2"],
1058    [InitBasicFSonLVM, Always, TestOutputListOfDevices (
1059       [["pvs"]], ["/dev/sda1"]);
1060     InitEmpty, Always, TestOutputListOfDevices (
1061       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1062        ["pvcreate"; "/dev/sda1"];
1063        ["pvcreate"; "/dev/sda2"];
1064        ["pvcreate"; "/dev/sda3"];
1065        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1066    "list the LVM physical volumes (PVs)",
1067    "\
1068 List all the physical volumes detected.  This is the equivalent
1069 of the L<pvs(8)> command.
1070
1071 This returns a list of just the device names that contain
1072 PVs (eg. C</dev/sda2>).
1073
1074 See also C<guestfs_pvs_full>.");
1075
1076   ("vgs", (RStringList "volgroups", []), 10, [Optional "lvm2"],
1077    [InitBasicFSonLVM, Always, TestOutputList (
1078       [["vgs"]], ["VG"]);
1079     InitEmpty, Always, TestOutputList (
1080       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1081        ["pvcreate"; "/dev/sda1"];
1082        ["pvcreate"; "/dev/sda2"];
1083        ["pvcreate"; "/dev/sda3"];
1084        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1085        ["vgcreate"; "VG2"; "/dev/sda3"];
1086        ["vgs"]], ["VG1"; "VG2"])],
1087    "list the LVM volume groups (VGs)",
1088    "\
1089 List all the volumes groups detected.  This is the equivalent
1090 of the L<vgs(8)> command.
1091
1092 This returns a list of just the volume group names that were
1093 detected (eg. C<VolGroup00>).
1094
1095 See also C<guestfs_vgs_full>.");
1096
1097   ("lvs", (RStringList "logvols", []), 11, [Optional "lvm2"],
1098    [InitBasicFSonLVM, Always, TestOutputList (
1099       [["lvs"]], ["/dev/VG/LV"]);
1100     InitEmpty, Always, TestOutputList (
1101       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1102        ["pvcreate"; "/dev/sda1"];
1103        ["pvcreate"; "/dev/sda2"];
1104        ["pvcreate"; "/dev/sda3"];
1105        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1106        ["vgcreate"; "VG2"; "/dev/sda3"];
1107        ["lvcreate"; "LV1"; "VG1"; "50"];
1108        ["lvcreate"; "LV2"; "VG1"; "50"];
1109        ["lvcreate"; "LV3"; "VG2"; "50"];
1110        ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
1111    "list the LVM logical volumes (LVs)",
1112    "\
1113 List all the logical volumes detected.  This is the equivalent
1114 of the L<lvs(8)> command.
1115
1116 This returns a list of the logical volume device names
1117 (eg. C</dev/VolGroup00/LogVol00>).
1118
1119 See also C<guestfs_lvs_full>.");
1120
1121   ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [Optional "lvm2"],
1122    [], (* XXX how to test? *)
1123    "list the LVM physical volumes (PVs)",
1124    "\
1125 List all the physical volumes detected.  This is the equivalent
1126 of the L<pvs(8)> command.  The \"full\" version includes all fields.");
1127
1128   ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [Optional "lvm2"],
1129    [], (* XXX how to test? *)
1130    "list the LVM volume groups (VGs)",
1131    "\
1132 List all the volumes groups detected.  This is the equivalent
1133 of the L<vgs(8)> command.  The \"full\" version includes all fields.");
1134
1135   ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [Optional "lvm2"],
1136    [], (* XXX how to test? *)
1137    "list the LVM logical volumes (LVs)",
1138    "\
1139 List all the logical volumes detected.  This is the equivalent
1140 of the L<lvs(8)> command.  The \"full\" version includes all fields.");
1141
1142   ("read_lines", (RStringList "lines", [Pathname "path"]), 15, [],
1143    [InitISOFS, Always, TestOutputList (
1144       [["read_lines"; "/known-4"]], ["abc"; "def"; "ghi"]);
1145     InitISOFS, Always, TestOutputList (
1146       [["read_lines"; "/empty"]], [])],
1147    "read file as lines",
1148    "\
1149 Return the contents of the file named C<path>.
1150
1151 The file contents are returned as a list of lines.  Trailing
1152 C<LF> and C<CRLF> character sequences are I<not> returned.
1153
1154 Note that this function cannot correctly handle binary files
1155 (specifically, files containing C<\\0> character which is treated
1156 as end of line).  For those you need to use the C<guestfs_read_file>
1157 function which has a more complex interface.");
1158
1159   ("aug_init", (RErr, [Pathname "root"; Int "flags"]), 16, [Optional "augeas"],
1160    [], (* XXX Augeas code needs tests. *)
1161    "create a new Augeas handle",
1162    "\
1163 Create a new Augeas handle for editing configuration files.
1164 If there was any previous Augeas handle associated with this
1165 guestfs session, then it is closed.
1166
1167 You must call this before using any other C<guestfs_aug_*>
1168 commands.
1169
1170 C<root> is the filesystem root.  C<root> must not be NULL,
1171 use C</> instead.
1172
1173 The flags are the same as the flags defined in
1174 E<lt>augeas.hE<gt>, the logical I<or> of the following
1175 integers:
1176
1177 =over 4
1178
1179 =item C<AUG_SAVE_BACKUP> = 1
1180
1181 Keep the original file with a C<.augsave> extension.
1182
1183 =item C<AUG_SAVE_NEWFILE> = 2
1184
1185 Save changes into a file with extension C<.augnew>, and
1186 do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
1187
1188 =item C<AUG_TYPE_CHECK> = 4
1189
1190 Typecheck lenses (can be expensive).
1191
1192 =item C<AUG_NO_STDINC> = 8
1193
1194 Do not use standard load path for modules.
1195
1196 =item C<AUG_SAVE_NOOP> = 16
1197
1198 Make save a no-op, just record what would have been changed.
1199
1200 =item C<AUG_NO_LOAD> = 32
1201
1202 Do not load the tree in C<guestfs_aug_init>.
1203
1204 =back
1205
1206 To close the handle, you can call C<guestfs_aug_close>.
1207
1208 To find out more about Augeas, see L<http://augeas.net/>.");
1209
1210   ("aug_close", (RErr, []), 26, [Optional "augeas"],
1211    [], (* XXX Augeas code needs tests. *)
1212    "close the current Augeas handle",
1213    "\
1214 Close the current Augeas handle and free up any resources
1215 used by it.  After calling this, you have to call
1216 C<guestfs_aug_init> again before you can use any other
1217 Augeas functions.");
1218
1219   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [Optional "augeas"],
1220    [], (* XXX Augeas code needs tests. *)
1221    "define an Augeas variable",
1222    "\
1223 Defines an Augeas variable C<name> whose value is the result
1224 of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
1225 undefined.
1226
1227 On success this returns the number of nodes in C<expr>, or
1228 C<0> if C<expr> evaluates to something which is not a nodeset.");
1229
1230   ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [Optional "augeas"],
1231    [], (* XXX Augeas code needs tests. *)
1232    "define an Augeas node",
1233    "\
1234 Defines a variable C<name> whose value is the result of
1235 evaluating C<expr>.
1236
1237 If C<expr> evaluates to an empty nodeset, a node is created,
1238 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
1239 C<name> will be the nodeset containing that single node.
1240
1241 On success this returns a pair containing the
1242 number of nodes in the nodeset, and a boolean flag
1243 if a node was created.");
1244
1245   ("aug_get", (RString "val", [String "augpath"]), 19, [Optional "augeas"],
1246    [], (* XXX Augeas code needs tests. *)
1247    "look up the value of an Augeas path",
1248    "\
1249 Look up the value associated with C<path>.  If C<path>
1250 matches exactly one node, the C<value> is returned.");
1251
1252   ("aug_set", (RErr, [String "augpath"; String "val"]), 20, [Optional "augeas"],
1253    [], (* XXX Augeas code needs tests. *)
1254    "set Augeas path to value",
1255    "\
1256 Set the value associated with C<path> to C<val>.
1257
1258 In the Augeas API, it is possible to clear a node by setting
1259 the value to NULL.  Due to an oversight in the libguestfs API
1260 you cannot do that with this call.  Instead you must use the
1261 C<guestfs_aug_clear> call.");
1262
1263   ("aug_insert", (RErr, [String "augpath"; String "label"; Bool "before"]), 21, [Optional "augeas"],
1264    [], (* XXX Augeas code needs tests. *)
1265    "insert a sibling Augeas node",
1266    "\
1267 Create a new sibling C<label> for C<path>, inserting it into
1268 the tree before or after C<path> (depending on the boolean
1269 flag C<before>).
1270
1271 C<path> must match exactly one existing node in the tree, and
1272 C<label> must be a label, ie. not contain C</>, C<*> or end
1273 with a bracketed index C<[N]>.");
1274
1275   ("aug_rm", (RInt "nrnodes", [String "augpath"]), 22, [Optional "augeas"],
1276    [], (* XXX Augeas code needs tests. *)
1277    "remove an Augeas path",
1278    "\
1279 Remove C<path> and all of its children.
1280
1281 On success this returns the number of entries which were removed.");
1282
1283   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [Optional "augeas"],
1284    [], (* XXX Augeas code needs tests. *)
1285    "move Augeas node",
1286    "\
1287 Move the node C<src> to C<dest>.  C<src> must match exactly
1288 one node.  C<dest> is overwritten if it exists.");
1289
1290   ("aug_match", (RStringList "matches", [String "augpath"]), 24, [Optional "augeas"],
1291    [], (* XXX Augeas code needs tests. *)
1292    "return Augeas nodes which match augpath",
1293    "\
1294 Returns a list of paths which match the path expression C<path>.
1295 The returned paths are sufficiently qualified so that they match
1296 exactly one node in the current tree.");
1297
1298   ("aug_save", (RErr, []), 25, [Optional "augeas"],
1299    [], (* XXX Augeas code needs tests. *)
1300    "write all pending Augeas changes to disk",
1301    "\
1302 This writes all pending changes to disk.
1303
1304 The flags which were passed to C<guestfs_aug_init> affect exactly
1305 how files are saved.");
1306
1307   ("aug_load", (RErr, []), 27, [Optional "augeas"],
1308    [], (* XXX Augeas code needs tests. *)
1309    "load files into the tree",
1310    "\
1311 Load files into the tree.
1312
1313 See C<aug_load> in the Augeas documentation for the full gory
1314 details.");
1315
1316   ("aug_ls", (RStringList "matches", [String "augpath"]), 28, [Optional "augeas"],
1317    [], (* XXX Augeas code needs tests. *)
1318    "list Augeas nodes under augpath",
1319    "\
1320 This is just a shortcut for listing C<guestfs_aug_match>
1321 C<path/*> and sorting the resulting nodes into alphabetical order.");
1322
1323   ("rm", (RErr, [Pathname "path"]), 29, [],
1324    [InitBasicFS, Always, TestRun
1325       [["touch"; "/new"];
1326        ["rm"; "/new"]];
1327     InitBasicFS, Always, TestLastFail
1328       [["rm"; "/new"]];
1329     InitBasicFS, Always, TestLastFail
1330       [["mkdir"; "/new"];
1331        ["rm"; "/new"]]],
1332    "remove a file",
1333    "\
1334 Remove the single file C<path>.");
1335
1336   ("rmdir", (RErr, [Pathname "path"]), 30, [],
1337    [InitBasicFS, Always, TestRun
1338       [["mkdir"; "/new"];
1339        ["rmdir"; "/new"]];
1340     InitBasicFS, Always, TestLastFail
1341       [["rmdir"; "/new"]];
1342     InitBasicFS, Always, TestLastFail
1343       [["touch"; "/new"];
1344        ["rmdir"; "/new"]]],
1345    "remove a directory",
1346    "\
1347 Remove the single directory C<path>.");
1348
1349   ("rm_rf", (RErr, [Pathname "path"]), 31, [],
1350    [InitBasicFS, Always, TestOutputFalse
1351       [["mkdir"; "/new"];
1352        ["mkdir"; "/new/foo"];
1353        ["touch"; "/new/foo/bar"];
1354        ["rm_rf"; "/new"];
1355        ["exists"; "/new"]]],
1356    "remove a file or directory recursively",
1357    "\
1358 Remove the file or directory C<path>, recursively removing the
1359 contents if its a directory.  This is like the C<rm -rf> shell
1360 command.");
1361
1362   ("mkdir", (RErr, [Pathname "path"]), 32, [],
1363    [InitBasicFS, Always, TestOutputTrue
1364       [["mkdir"; "/new"];
1365        ["is_dir"; "/new"]];
1366     InitBasicFS, Always, TestLastFail
1367       [["mkdir"; "/new/foo/bar"]]],
1368    "create a directory",
1369    "\
1370 Create a directory named C<path>.");
1371
1372   ("mkdir_p", (RErr, [Pathname "path"]), 33, [],
1373    [InitBasicFS, Always, TestOutputTrue
1374       [["mkdir_p"; "/new/foo/bar"];
1375        ["is_dir"; "/new/foo/bar"]];
1376     InitBasicFS, Always, TestOutputTrue
1377       [["mkdir_p"; "/new/foo/bar"];
1378        ["is_dir"; "/new/foo"]];
1379     InitBasicFS, Always, TestOutputTrue
1380       [["mkdir_p"; "/new/foo/bar"];
1381        ["is_dir"; "/new"]];
1382     (* Regression tests for RHBZ#503133: *)
1383     InitBasicFS, Always, TestRun
1384       [["mkdir"; "/new"];
1385        ["mkdir_p"; "/new"]];
1386     InitBasicFS, Always, TestLastFail
1387       [["touch"; "/new"];
1388        ["mkdir_p"; "/new"]]],
1389    "create a directory and parents",
1390    "\
1391 Create a directory named C<path>, creating any parent directories
1392 as necessary.  This is like the C<mkdir -p> shell command.");
1393
1394   ("chmod", (RErr, [Int "mode"; Pathname "path"]), 34, [],
1395    [], (* XXX Need stat command to test *)
1396    "change file mode",
1397    "\
1398 Change the mode (permissions) of C<path> to C<mode>.  Only
1399 numeric modes are supported.
1400
1401 I<Note>: When using this command from guestfish, C<mode>
1402 by default would be decimal, unless you prefix it with
1403 C<0> to get octal, ie. use C<0700> not C<700>.
1404
1405 The mode actually set is affected by the umask.");
1406
1407   ("chown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 35, [],
1408    [], (* XXX Need stat command to test *)
1409    "change file owner and group",
1410    "\
1411 Change the file owner to C<owner> and group to C<group>.
1412
1413 Only numeric uid and gid are supported.  If you want to use
1414 names, you will need to locate and parse the password file
1415 yourself (Augeas support makes this relatively easy).");
1416
1417   ("exists", (RBool "existsflag", [Pathname "path"]), 36, [],
1418    [InitISOFS, Always, TestOutputTrue (
1419       [["exists"; "/empty"]]);
1420     InitISOFS, Always, TestOutputTrue (
1421       [["exists"; "/directory"]])],
1422    "test if file or directory exists",
1423    "\
1424 This returns C<true> if and only if there is a file, directory
1425 (or anything) with the given C<path> name.
1426
1427 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1428
1429   ("is_file", (RBool "fileflag", [Pathname "path"]), 37, [],
1430    [InitISOFS, Always, TestOutputTrue (
1431       [["is_file"; "/known-1"]]);
1432     InitISOFS, Always, TestOutputFalse (
1433       [["is_file"; "/directory"]])],
1434    "test if file exists",
1435    "\
1436 This returns C<true> if and only if there is a file
1437 with the given C<path> name.  Note that it returns false for
1438 other objects like directories.
1439
1440 See also C<guestfs_stat>.");
1441
1442   ("is_dir", (RBool "dirflag", [Pathname "path"]), 38, [],
1443    [InitISOFS, Always, TestOutputFalse (
1444       [["is_dir"; "/known-3"]]);
1445     InitISOFS, Always, TestOutputTrue (
1446       [["is_dir"; "/directory"]])],
1447    "test if file exists",
1448    "\
1449 This returns C<true> if and only if there is a directory
1450 with the given C<path> name.  Note that it returns false for
1451 other objects like files.
1452
1453 See also C<guestfs_stat>.");
1454
1455   ("pvcreate", (RErr, [Device "device"]), 39, [Optional "lvm2"],
1456    [InitEmpty, Always, TestOutputListOfDevices (
1457       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1458        ["pvcreate"; "/dev/sda1"];
1459        ["pvcreate"; "/dev/sda2"];
1460        ["pvcreate"; "/dev/sda3"];
1461        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1462    "create an LVM physical volume",
1463    "\
1464 This creates an LVM physical volume on the named C<device>,
1465 where C<device> should usually be a partition name such
1466 as C</dev/sda1>.");
1467
1468   ("vgcreate", (RErr, [String "volgroup"; DeviceList "physvols"]), 40, [Optional "lvm2"],
1469    [InitEmpty, Always, TestOutputList (
1470       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1471        ["pvcreate"; "/dev/sda1"];
1472        ["pvcreate"; "/dev/sda2"];
1473        ["pvcreate"; "/dev/sda3"];
1474        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1475        ["vgcreate"; "VG2"; "/dev/sda3"];
1476        ["vgs"]], ["VG1"; "VG2"])],
1477    "create an LVM volume group",
1478    "\
1479 This creates an LVM volume group called C<volgroup>
1480 from the non-empty list of physical volumes C<physvols>.");
1481
1482   ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [Optional "lvm2"],
1483    [InitEmpty, Always, TestOutputList (
1484       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1485        ["pvcreate"; "/dev/sda1"];
1486        ["pvcreate"; "/dev/sda2"];
1487        ["pvcreate"; "/dev/sda3"];
1488        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1489        ["vgcreate"; "VG2"; "/dev/sda3"];
1490        ["lvcreate"; "LV1"; "VG1"; "50"];
1491        ["lvcreate"; "LV2"; "VG1"; "50"];
1492        ["lvcreate"; "LV3"; "VG2"; "50"];
1493        ["lvcreate"; "LV4"; "VG2"; "50"];
1494        ["lvcreate"; "LV5"; "VG2"; "50"];
1495        ["lvs"]],
1496       ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1497        "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1498    "create an LVM logical volume",
1499    "\
1500 This creates an LVM logical volume called C<logvol>
1501 on the volume group C<volgroup>, with C<size> megabytes.");
1502
1503   ("mkfs", (RErr, [String "fstype"; Device "device"]), 42, [],
1504    [InitEmpty, Always, TestOutput (
1505       [["part_disk"; "/dev/sda"; "mbr"];
1506        ["mkfs"; "ext2"; "/dev/sda1"];
1507        ["mount_options"; ""; "/dev/sda1"; "/"];
1508        ["write"; "/new"; "new file contents"];
1509        ["cat"; "/new"]], "new file contents")],
1510    "make a filesystem",
1511    "\
1512 This creates a filesystem on C<device> (usually a partition
1513 or LVM logical volume).  The filesystem type is C<fstype>, for
1514 example C<ext3>.");
1515
1516   ("sfdisk", (RErr, [Device "device";
1517                      Int "cyls"; Int "heads"; Int "sectors";
1518                      StringList "lines"]), 43, [DangerWillRobinson],
1519    [],
1520    "create partitions on a block device",
1521    "\
1522 This is a direct interface to the L<sfdisk(8)> program for creating
1523 partitions on block devices.
1524
1525 C<device> should be a block device, for example C</dev/sda>.
1526
1527 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1528 and sectors on the device, which are passed directly to sfdisk as
1529 the I<-C>, I<-H> and I<-S> parameters.  If you pass C<0> for any
1530 of these, then the corresponding parameter is omitted.  Usually for
1531 'large' disks, you can just pass C<0> for these, but for small
1532 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1533 out the right geometry and you will need to tell it.
1534
1535 C<lines> is a list of lines that we feed to C<sfdisk>.  For more
1536 information refer to the L<sfdisk(8)> manpage.
1537
1538 To create a single partition occupying the whole disk, you would
1539 pass C<lines> as a single element list, when the single element being
1540 the string C<,> (comma).
1541
1542 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>,
1543 C<guestfs_part_init>");
1544
1545   ("write_file", (RErr, [Pathname "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning; DeprecatedBy "write"],
1546    (* Regression test for RHBZ#597135. *)
1547    [InitBasicFS, Always, TestLastFail
1548       [["write_file"; "/new"; "abc"; "10000"]]],
1549    "create a file",
1550    "\
1551 This call creates a file called C<path>.  The contents of the
1552 file is the string C<content> (which can contain any 8 bit data),
1553 with length C<size>.
1554
1555 As a special case, if C<size> is C<0>
1556 then the length is calculated using C<strlen> (so in this case
1557 the content cannot contain embedded ASCII NULs).
1558
1559 I<NB.> Owing to a bug, writing content containing ASCII NUL
1560 characters does I<not> work, even if the length is specified.");
1561
1562   ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1563    [InitEmpty, Always, TestOutputListOfDevices (
1564       [["part_disk"; "/dev/sda"; "mbr"];
1565        ["mkfs"; "ext2"; "/dev/sda1"];
1566        ["mount_options"; ""; "/dev/sda1"; "/"];
1567        ["mounts"]], ["/dev/sda1"]);
1568     InitEmpty, Always, TestOutputList (
1569       [["part_disk"; "/dev/sda"; "mbr"];
1570        ["mkfs"; "ext2"; "/dev/sda1"];
1571        ["mount_options"; ""; "/dev/sda1"; "/"];
1572        ["umount"; "/"];
1573        ["mounts"]], [])],
1574    "unmount a filesystem",
1575    "\
1576 This unmounts the given filesystem.  The filesystem may be
1577 specified either by its mountpoint (path) or the device which
1578 contains the filesystem.");
1579
1580   ("mounts", (RStringList "devices", []), 46, [],
1581    [InitBasicFS, Always, TestOutputListOfDevices (
1582       [["mounts"]], ["/dev/sda1"])],
1583    "show mounted filesystems",
1584    "\
1585 This returns the list of currently mounted filesystems.  It returns
1586 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1587
1588 Some internal mounts are not shown.
1589
1590 See also: C<guestfs_mountpoints>");
1591
1592   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1593    [InitBasicFS, Always, TestOutputList (
1594       [["umount_all"];
1595        ["mounts"]], []);
1596     (* check that umount_all can unmount nested mounts correctly: *)
1597     InitEmpty, Always, TestOutputList (
1598       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1599        ["mkfs"; "ext2"; "/dev/sda1"];
1600        ["mkfs"; "ext2"; "/dev/sda2"];
1601        ["mkfs"; "ext2"; "/dev/sda3"];
1602        ["mount_options"; ""; "/dev/sda1"; "/"];
1603        ["mkdir"; "/mp1"];
1604        ["mount_options"; ""; "/dev/sda2"; "/mp1"];
1605        ["mkdir"; "/mp1/mp2"];
1606        ["mount_options"; ""; "/dev/sda3"; "/mp1/mp2"];
1607        ["mkdir"; "/mp1/mp2/mp3"];
1608        ["umount_all"];
1609        ["mounts"]], [])],
1610    "unmount all filesystems",
1611    "\
1612 This unmounts all mounted filesystems.
1613
1614 Some internal mounts are not unmounted by this call.");
1615
1616   ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson; Optional "lvm2"],
1617    [],
1618    "remove all LVM LVs, VGs and PVs",
1619    "\
1620 This command removes all LVM logical volumes, volume groups
1621 and physical volumes.");
1622
1623   ("file", (RString "description", [Dev_or_Path "path"]), 49, [],
1624    [InitISOFS, Always, TestOutput (
1625       [["file"; "/empty"]], "empty");
1626     InitISOFS, Always, TestOutput (
1627       [["file"; "/known-1"]], "ASCII text");
1628     InitISOFS, Always, TestLastFail (
1629       [["file"; "/notexists"]])],
1630    "determine file type",
1631    "\
1632 This call uses the standard L<file(1)> command to determine
1633 the type or contents of the file.  This also works on devices,
1634 for example to find out whether a partition contains a filesystem.
1635
1636 This call will also transparently look inside various types
1637 of compressed file.
1638
1639 The exact command which runs is C<file -zbsL path>.  Note in
1640 particular that the filename is not prepended to the output
1641 (the C<-b> option).");
1642
1643   ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1644    [InitBasicFS, Always, TestOutput (
1645       [["upload"; "test-command"; "/test-command"];
1646        ["chmod"; "0o755"; "/test-command"];
1647        ["command"; "/test-command 1"]], "Result1");
1648     InitBasicFS, Always, TestOutput (
1649       [["upload"; "test-command"; "/test-command"];
1650        ["chmod"; "0o755"; "/test-command"];
1651        ["command"; "/test-command 2"]], "Result2\n");
1652     InitBasicFS, Always, TestOutput (
1653       [["upload"; "test-command"; "/test-command"];
1654        ["chmod"; "0o755"; "/test-command"];
1655        ["command"; "/test-command 3"]], "\nResult3");
1656     InitBasicFS, Always, TestOutput (
1657       [["upload"; "test-command"; "/test-command"];
1658        ["chmod"; "0o755"; "/test-command"];
1659        ["command"; "/test-command 4"]], "\nResult4\n");
1660     InitBasicFS, Always, TestOutput (
1661       [["upload"; "test-command"; "/test-command"];
1662        ["chmod"; "0o755"; "/test-command"];
1663        ["command"; "/test-command 5"]], "\nResult5\n\n");
1664     InitBasicFS, Always, TestOutput (
1665       [["upload"; "test-command"; "/test-command"];
1666        ["chmod"; "0o755"; "/test-command"];
1667        ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1668     InitBasicFS, Always, TestOutput (
1669       [["upload"; "test-command"; "/test-command"];
1670        ["chmod"; "0o755"; "/test-command"];
1671        ["command"; "/test-command 7"]], "");
1672     InitBasicFS, Always, TestOutput (
1673       [["upload"; "test-command"; "/test-command"];
1674        ["chmod"; "0o755"; "/test-command"];
1675        ["command"; "/test-command 8"]], "\n");
1676     InitBasicFS, Always, TestOutput (
1677       [["upload"; "test-command"; "/test-command"];
1678        ["chmod"; "0o755"; "/test-command"];
1679        ["command"; "/test-command 9"]], "\n\n");
1680     InitBasicFS, Always, TestOutput (
1681       [["upload"; "test-command"; "/test-command"];
1682        ["chmod"; "0o755"; "/test-command"];
1683        ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1684     InitBasicFS, Always, TestOutput (
1685       [["upload"; "test-command"; "/test-command"];
1686        ["chmod"; "0o755"; "/test-command"];
1687        ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1688     InitBasicFS, Always, TestLastFail (
1689       [["upload"; "test-command"; "/test-command"];
1690        ["chmod"; "0o755"; "/test-command"];
1691        ["command"; "/test-command"]])],
1692    "run a command from the guest filesystem",
1693    "\
1694 This call runs a command from the guest filesystem.  The
1695 filesystem must be mounted, and must contain a compatible
1696 operating system (ie. something Linux, with the same
1697 or compatible processor architecture).
1698
1699 The single parameter is an argv-style list of arguments.
1700 The first element is the name of the program to run.
1701 Subsequent elements are parameters.  The list must be
1702 non-empty (ie. must contain a program name).  Note that
1703 the command runs directly, and is I<not> invoked via
1704 the shell (see C<guestfs_sh>).
1705
1706 The return value is anything printed to I<stdout> by
1707 the command.
1708
1709 If the command returns a non-zero exit status, then
1710 this function returns an error message.  The error message
1711 string is the content of I<stderr> from the command.
1712
1713 The C<$PATH> environment variable will contain at least
1714 C</usr/bin> and C</bin>.  If you require a program from
1715 another location, you should provide the full path in the
1716 first parameter.
1717
1718 Shared libraries and data files required by the program
1719 must be available on filesystems which are mounted in the
1720 correct places.  It is the caller's responsibility to ensure
1721 all filesystems that are needed are mounted at the right
1722 locations.");
1723
1724   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1725    [InitBasicFS, Always, TestOutputList (
1726       [["upload"; "test-command"; "/test-command"];
1727        ["chmod"; "0o755"; "/test-command"];
1728        ["command_lines"; "/test-command 1"]], ["Result1"]);
1729     InitBasicFS, Always, TestOutputList (
1730       [["upload"; "test-command"; "/test-command"];
1731        ["chmod"; "0o755"; "/test-command"];
1732        ["command_lines"; "/test-command 2"]], ["Result2"]);
1733     InitBasicFS, Always, TestOutputList (
1734       [["upload"; "test-command"; "/test-command"];
1735        ["chmod"; "0o755"; "/test-command"];
1736        ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1737     InitBasicFS, Always, TestOutputList (
1738       [["upload"; "test-command"; "/test-command"];
1739        ["chmod"; "0o755"; "/test-command"];
1740        ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1741     InitBasicFS, Always, TestOutputList (
1742       [["upload"; "test-command"; "/test-command"];
1743        ["chmod"; "0o755"; "/test-command"];
1744        ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1745     InitBasicFS, Always, TestOutputList (
1746       [["upload"; "test-command"; "/test-command"];
1747        ["chmod"; "0o755"; "/test-command"];
1748        ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1749     InitBasicFS, Always, TestOutputList (
1750       [["upload"; "test-command"; "/test-command"];
1751        ["chmod"; "0o755"; "/test-command"];
1752        ["command_lines"; "/test-command 7"]], []);
1753     InitBasicFS, Always, TestOutputList (
1754       [["upload"; "test-command"; "/test-command"];
1755        ["chmod"; "0o755"; "/test-command"];
1756        ["command_lines"; "/test-command 8"]], [""]);
1757     InitBasicFS, Always, TestOutputList (
1758       [["upload"; "test-command"; "/test-command"];
1759        ["chmod"; "0o755"; "/test-command"];
1760        ["command_lines"; "/test-command 9"]], ["";""]);
1761     InitBasicFS, Always, TestOutputList (
1762       [["upload"; "test-command"; "/test-command"];
1763        ["chmod"; "0o755"; "/test-command"];
1764        ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1765     InitBasicFS, Always, TestOutputList (
1766       [["upload"; "test-command"; "/test-command"];
1767        ["chmod"; "0o755"; "/test-command"];
1768        ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1769    "run a command, returning lines",
1770    "\
1771 This is the same as C<guestfs_command>, but splits the
1772 result into a list of lines.
1773
1774 See also: C<guestfs_sh_lines>");
1775
1776   ("stat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 52, [],
1777    [InitISOFS, Always, TestOutputStruct (
1778       [["stat"; "/empty"]], [CompareWithInt ("size", 0)])],
1779    "get file information",
1780    "\
1781 Returns file information for the given C<path>.
1782
1783 This is the same as the C<stat(2)> system call.");
1784
1785   ("lstat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 53, [],
1786    [InitISOFS, Always, TestOutputStruct (
1787       [["lstat"; "/empty"]], [CompareWithInt ("size", 0)])],
1788    "get file information for a symbolic link",
1789    "\
1790 Returns file information for the given C<path>.
1791
1792 This is the same as C<guestfs_stat> except that if C<path>
1793 is a symbolic link, then the link is stat-ed, not the file it
1794 refers to.
1795
1796 This is the same as the C<lstat(2)> system call.");
1797
1798   ("statvfs", (RStruct ("statbuf", "statvfs"), [Pathname "path"]), 54, [],
1799    [InitISOFS, Always, TestOutputStruct (
1800       [["statvfs"; "/"]], [CompareWithInt ("namemax", 255)])],
1801    "get file system statistics",
1802    "\
1803 Returns file system statistics for any mounted file system.
1804 C<path> should be a file or directory in the mounted file system
1805 (typically it is the mount point itself, but it doesn't need to be).
1806
1807 This is the same as the C<statvfs(2)> system call.");
1808
1809   ("tune2fs_l", (RHashtable "superblock", [Device "device"]), 55, [],
1810    [], (* XXX test *)
1811    "get ext2/ext3/ext4 superblock details",
1812    "\
1813 This returns the contents of the ext2, ext3 or ext4 filesystem
1814 superblock on C<device>.
1815
1816 It is the same as running C<tune2fs -l device>.  See L<tune2fs(8)>
1817 manpage for more details.  The list of fields returned isn't
1818 clearly defined, and depends on both the version of C<tune2fs>
1819 that libguestfs was built against, and the filesystem itself.");
1820
1821   ("blockdev_setro", (RErr, [Device "device"]), 56, [],
1822    [InitEmpty, Always, TestOutputTrue (
1823       [["blockdev_setro"; "/dev/sda"];
1824        ["blockdev_getro"; "/dev/sda"]])],
1825    "set block device to read-only",
1826    "\
1827 Sets the block device named C<device> to read-only.
1828
1829 This uses the L<blockdev(8)> command.");
1830
1831   ("blockdev_setrw", (RErr, [Device "device"]), 57, [],
1832    [InitEmpty, Always, TestOutputFalse (
1833       [["blockdev_setrw"; "/dev/sda"];
1834        ["blockdev_getro"; "/dev/sda"]])],
1835    "set block device to read-write",
1836    "\
1837 Sets the block device named C<device> to read-write.
1838
1839 This uses the L<blockdev(8)> command.");
1840
1841   ("blockdev_getro", (RBool "ro", [Device "device"]), 58, [],
1842    [InitEmpty, Always, TestOutputTrue (
1843       [["blockdev_setro"; "/dev/sda"];
1844        ["blockdev_getro"; "/dev/sda"]])],
1845    "is block device set to read-only",
1846    "\
1847 Returns a boolean indicating if the block device is read-only
1848 (true if read-only, false if not).
1849
1850 This uses the L<blockdev(8)> command.");
1851
1852   ("blockdev_getss", (RInt "sectorsize", [Device "device"]), 59, [],
1853    [InitEmpty, Always, TestOutputInt (
1854       [["blockdev_getss"; "/dev/sda"]], 512)],
1855    "get sectorsize of block device",
1856    "\
1857 This returns the size of sectors on a block device.
1858 Usually 512, but can be larger for modern devices.
1859
1860 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1861 for that).
1862
1863 This uses the L<blockdev(8)> command.");
1864
1865   ("blockdev_getbsz", (RInt "blocksize", [Device "device"]), 60, [],
1866    [InitEmpty, Always, TestOutputInt (
1867       [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1868    "get blocksize of block device",
1869    "\
1870 This returns the block size of a device.
1871
1872 (Note this is different from both I<size in blocks> and
1873 I<filesystem block size>).
1874
1875 This uses the L<blockdev(8)> command.");
1876
1877   ("blockdev_setbsz", (RErr, [Device "device"; Int "blocksize"]), 61, [],
1878    [], (* XXX test *)
1879    "set blocksize of block device",
1880    "\
1881 This sets the block size of a device.
1882
1883 (Note this is different from both I<size in blocks> and
1884 I<filesystem block size>).
1885
1886 This uses the L<blockdev(8)> command.");
1887
1888   ("blockdev_getsz", (RInt64 "sizeinsectors", [Device "device"]), 62, [],
1889    [InitEmpty, Always, TestOutputInt (
1890       [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1891    "get total size of device in 512-byte sectors",
1892    "\
1893 This returns the size of the device in units of 512-byte sectors
1894 (even if the sectorsize isn't 512 bytes ... weird).
1895
1896 See also C<guestfs_blockdev_getss> for the real sector size of
1897 the device, and C<guestfs_blockdev_getsize64> for the more
1898 useful I<size in bytes>.
1899
1900 This uses the L<blockdev(8)> command.");
1901
1902   ("blockdev_getsize64", (RInt64 "sizeinbytes", [Device "device"]), 63, [],
1903    [InitEmpty, Always, TestOutputInt (
1904       [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1905    "get total size of device in bytes",
1906    "\
1907 This returns the size of the device in bytes.
1908
1909 See also C<guestfs_blockdev_getsz>.
1910
1911 This uses the L<blockdev(8)> command.");
1912
1913   ("blockdev_flushbufs", (RErr, [Device "device"]), 64, [],
1914    [InitEmpty, Always, TestRun
1915       [["blockdev_flushbufs"; "/dev/sda"]]],
1916    "flush device buffers",
1917    "\
1918 This tells the kernel to flush internal buffers associated
1919 with C<device>.
1920
1921 This uses the L<blockdev(8)> command.");
1922
1923   ("blockdev_rereadpt", (RErr, [Device "device"]), 65, [],
1924    [InitEmpty, Always, TestRun
1925       [["blockdev_rereadpt"; "/dev/sda"]]],
1926    "reread partition table",
1927    "\
1928 Reread the partition table on C<device>.
1929
1930 This uses the L<blockdev(8)> command.");
1931
1932   ("upload", (RErr, [FileIn "filename"; Dev_or_Path "remotefilename"]), 66, [],
1933    [InitBasicFS, Always, TestOutput (
1934       (* Pick a file from cwd which isn't likely to change. *)
1935       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1936        ["checksum"; "md5"; "/COPYING.LIB"]],
1937       Digest.to_hex (Digest.file "COPYING.LIB"))],
1938    "upload a file from the local machine",
1939    "\
1940 Upload local file C<filename> to C<remotefilename> on the
1941 filesystem.
1942
1943 C<filename> can also be a named pipe.
1944
1945 See also C<guestfs_download>.");
1946
1947   ("download", (RErr, [Dev_or_Path "remotefilename"; FileOut "filename"]), 67, [],
1948    [InitBasicFS, Always, TestOutput (
1949       (* Pick a file from cwd which isn't likely to change. *)
1950       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1951        ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1952        ["upload"; "testdownload.tmp"; "/upload"];
1953        ["checksum"; "md5"; "/upload"]],
1954       Digest.to_hex (Digest.file "COPYING.LIB"))],
1955    "download a file to the local machine",
1956    "\
1957 Download file C<remotefilename> and save it as C<filename>
1958 on the local machine.
1959
1960 C<filename> can also be a named pipe.
1961
1962 See also C<guestfs_upload>, C<guestfs_cat>.");
1963
1964   ("checksum", (RString "checksum", [String "csumtype"; Pathname "path"]), 68, [],
1965    [InitISOFS, Always, TestOutput (
1966       [["checksum"; "crc"; "/known-3"]], "2891671662");
1967     InitISOFS, Always, TestLastFail (
1968       [["checksum"; "crc"; "/notexists"]]);
1969     InitISOFS, Always, TestOutput (
1970       [["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c");
1971     InitISOFS, Always, TestOutput (
1972       [["checksum"; "sha1"; "/known-3"]], "b7ebccc3ee418311091c3eda0a45b83c0a770f15");
1973     InitISOFS, Always, TestOutput (
1974       [["checksum"; "sha224"; "/known-3"]], "d2cd1774b28f3659c14116be0a6dc2bb5c4b350ce9cd5defac707741");
1975     InitISOFS, Always, TestOutput (
1976       [["checksum"; "sha256"; "/known-3"]], "75bb71b90cd20cb13f86d2bea8dad63ac7194e7517c3b52b8d06ff52d3487d30");
1977     InitISOFS, Always, TestOutput (
1978       [["checksum"; "sha384"; "/known-3"]], "5fa7883430f357b5d7b7271d3a1d2872b51d73cba72731de6863d3dea55f30646af2799bef44d5ea776a5ec7941ac640");
1979     InitISOFS, Always, TestOutput (
1980       [["checksum"; "sha512"; "/known-3"]], "2794062c328c6b216dca90443b7f7134c5f40e56bd0ed7853123275a09982a6f992e6ca682f9d2fba34a4c5e870d8fe077694ff831e3032a004ee077e00603f6");
1981     (* Test for RHBZ#579608, absolute symbolic links. *)
1982     InitISOFS, Always, TestOutput (
1983       [["checksum"; "sha512"; "/abssymlink"]], "5f57d0639bc95081c53afc63a449403883818edc64da48930ad6b1a4fb49be90404686877743fbcd7c99811f3def7df7bc22635c885c6a8cf79c806b43451c1a")],
1984    "compute MD5, SHAx or CRC checksum of file",
1985    "\
1986 This call computes the MD5, SHAx or CRC checksum of the
1987 file named C<path>.
1988
1989 The type of checksum to compute is given by the C<csumtype>
1990 parameter which must have one of the following values:
1991
1992 =over 4
1993
1994 =item C<crc>
1995
1996 Compute the cyclic redundancy check (CRC) specified by POSIX
1997 for the C<cksum> command.
1998
1999 =item C<md5>
2000
2001 Compute the MD5 hash (using the C<md5sum> program).
2002
2003 =item C<sha1>
2004
2005 Compute the SHA1 hash (using the C<sha1sum> program).
2006
2007 =item C<sha224>
2008
2009 Compute the SHA224 hash (using the C<sha224sum> program).
2010
2011 =item C<sha256>
2012
2013 Compute the SHA256 hash (using the C<sha256sum> program).
2014
2015 =item C<sha384>
2016
2017 Compute the SHA384 hash (using the C<sha384sum> program).
2018
2019 =item C<sha512>
2020
2021 Compute the SHA512 hash (using the C<sha512sum> program).
2022
2023 =back
2024
2025 The checksum is returned as a printable string.
2026
2027 To get the checksum for a device, use C<guestfs_checksum_device>.
2028
2029 To get the checksums for many files, use C<guestfs_checksums_out>.");
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"; "/new"; "data"];
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 If the C<options> parameter is an empty string, then
2097 no options are passed (all options default to whatever
2098 the filesystem uses).");
2099
2100   ("mount_vfs", (RErr, [String "options"; String "vfstype"; Device "device"; String "mountpoint"]), 75, [],
2101    [],
2102    "mount a guest disk with mount options and vfstype",
2103    "\
2104 This is the same as the C<guestfs_mount> command, but it
2105 allows you to set both the mount options and the vfstype
2106 as for the L<mount(8)> I<-o> and I<-t> flags.");
2107
2108   ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
2109    [],
2110    "debugging and internals",
2111    "\
2112 The C<guestfs_debug> command exposes some internals of
2113 C<guestfsd> (the guestfs daemon) that runs inside the
2114 qemu subprocess.
2115
2116 There is no comprehensive help for this command.  You have
2117 to look at the file C<daemon/debug.c> in the libguestfs source
2118 to find out what you can do.");
2119
2120   ("lvremove", (RErr, [Device "device"]), 77, [Optional "lvm2"],
2121    [InitEmpty, Always, TestOutputList (
2122       [["part_disk"; "/dev/sda"; "mbr"];
2123        ["pvcreate"; "/dev/sda1"];
2124        ["vgcreate"; "VG"; "/dev/sda1"];
2125        ["lvcreate"; "LV1"; "VG"; "50"];
2126        ["lvcreate"; "LV2"; "VG"; "50"];
2127        ["lvremove"; "/dev/VG/LV1"];
2128        ["lvs"]], ["/dev/VG/LV2"]);
2129     InitEmpty, Always, TestOutputList (
2130       [["part_disk"; "/dev/sda"; "mbr"];
2131        ["pvcreate"; "/dev/sda1"];
2132        ["vgcreate"; "VG"; "/dev/sda1"];
2133        ["lvcreate"; "LV1"; "VG"; "50"];
2134        ["lvcreate"; "LV2"; "VG"; "50"];
2135        ["lvremove"; "/dev/VG"];
2136        ["lvs"]], []);
2137     InitEmpty, Always, TestOutputList (
2138       [["part_disk"; "/dev/sda"; "mbr"];
2139        ["pvcreate"; "/dev/sda1"];
2140        ["vgcreate"; "VG"; "/dev/sda1"];
2141        ["lvcreate"; "LV1"; "VG"; "50"];
2142        ["lvcreate"; "LV2"; "VG"; "50"];
2143        ["lvremove"; "/dev/VG"];
2144        ["vgs"]], ["VG"])],
2145    "remove an LVM logical volume",
2146    "\
2147 Remove an LVM logical volume C<device>, where C<device> is
2148 the path to the LV, such as C</dev/VG/LV>.
2149
2150 You can also remove all LVs in a volume group by specifying
2151 the VG name, C</dev/VG>.");
2152
2153   ("vgremove", (RErr, [String "vgname"]), 78, [Optional "lvm2"],
2154    [InitEmpty, Always, TestOutputList (
2155       [["part_disk"; "/dev/sda"; "mbr"];
2156        ["pvcreate"; "/dev/sda1"];
2157        ["vgcreate"; "VG"; "/dev/sda1"];
2158        ["lvcreate"; "LV1"; "VG"; "50"];
2159        ["lvcreate"; "LV2"; "VG"; "50"];
2160        ["vgremove"; "VG"];
2161        ["lvs"]], []);
2162     InitEmpty, Always, TestOutputList (
2163       [["part_disk"; "/dev/sda"; "mbr"];
2164        ["pvcreate"; "/dev/sda1"];
2165        ["vgcreate"; "VG"; "/dev/sda1"];
2166        ["lvcreate"; "LV1"; "VG"; "50"];
2167        ["lvcreate"; "LV2"; "VG"; "50"];
2168        ["vgremove"; "VG"];
2169        ["vgs"]], [])],
2170    "remove an LVM volume group",
2171    "\
2172 Remove an LVM volume group C<vgname>, (for example C<VG>).
2173
2174 This also forcibly removes all logical volumes in the volume
2175 group (if any).");
2176
2177   ("pvremove", (RErr, [Device "device"]), 79, [Optional "lvm2"],
2178    [InitEmpty, Always, TestOutputListOfDevices (
2179       [["part_disk"; "/dev/sda"; "mbr"];
2180        ["pvcreate"; "/dev/sda1"];
2181        ["vgcreate"; "VG"; "/dev/sda1"];
2182        ["lvcreate"; "LV1"; "VG"; "50"];
2183        ["lvcreate"; "LV2"; "VG"; "50"];
2184        ["vgremove"; "VG"];
2185        ["pvremove"; "/dev/sda1"];
2186        ["lvs"]], []);
2187     InitEmpty, Always, TestOutputListOfDevices (
2188       [["part_disk"; "/dev/sda"; "mbr"];
2189        ["pvcreate"; "/dev/sda1"];
2190        ["vgcreate"; "VG"; "/dev/sda1"];
2191        ["lvcreate"; "LV1"; "VG"; "50"];
2192        ["lvcreate"; "LV2"; "VG"; "50"];
2193        ["vgremove"; "VG"];
2194        ["pvremove"; "/dev/sda1"];
2195        ["vgs"]], []);
2196     InitEmpty, Always, TestOutputListOfDevices (
2197       [["part_disk"; "/dev/sda"; "mbr"];
2198        ["pvcreate"; "/dev/sda1"];
2199        ["vgcreate"; "VG"; "/dev/sda1"];
2200        ["lvcreate"; "LV1"; "VG"; "50"];
2201        ["lvcreate"; "LV2"; "VG"; "50"];
2202        ["vgremove"; "VG"];
2203        ["pvremove"; "/dev/sda1"];
2204        ["pvs"]], [])],
2205    "remove an LVM physical volume",
2206    "\
2207 This wipes a physical volume C<device> so that LVM will no longer
2208 recognise it.
2209
2210 The implementation uses the C<pvremove> command which refuses to
2211 wipe physical volumes that contain any volume groups, so you have
2212 to remove those first.");
2213
2214   ("set_e2label", (RErr, [Device "device"; String "label"]), 80, [],
2215    [InitBasicFS, Always, TestOutput (
2216       [["set_e2label"; "/dev/sda1"; "testlabel"];
2217        ["get_e2label"; "/dev/sda1"]], "testlabel")],
2218    "set the ext2/3/4 filesystem label",
2219    "\
2220 This sets the ext2/3/4 filesystem label of the filesystem on
2221 C<device> to C<label>.  Filesystem labels are limited to
2222 16 characters.
2223
2224 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
2225 to return the existing label on a filesystem.");
2226
2227   ("get_e2label", (RString "label", [Device "device"]), 81, [DeprecatedBy "vfs_label"],
2228    [],
2229    "get the ext2/3/4 filesystem label",
2230    "\
2231 This returns the ext2/3/4 filesystem label of the filesystem on
2232 C<device>.");
2233
2234   ("set_e2uuid", (RErr, [Device "device"; String "uuid"]), 82, [],
2235    (let uuid = uuidgen () in
2236     [InitBasicFS, Always, TestOutput (
2237        [["set_e2uuid"; "/dev/sda1"; uuid];
2238         ["get_e2uuid"; "/dev/sda1"]], uuid);
2239      InitBasicFS, Always, TestOutput (
2240        [["set_e2uuid"; "/dev/sda1"; "clear"];
2241         ["get_e2uuid"; "/dev/sda1"]], "");
2242      (* We can't predict what UUIDs will be, so just check the commands run. *)
2243      InitBasicFS, Always, TestRun (
2244        [["set_e2uuid"; "/dev/sda1"; "random"]]);
2245      InitBasicFS, Always, TestRun (
2246        [["set_e2uuid"; "/dev/sda1"; "time"]])]),
2247    "set the ext2/3/4 filesystem UUID",
2248    "\
2249 This sets the ext2/3/4 filesystem UUID of the filesystem on
2250 C<device> to C<uuid>.  The format of the UUID and alternatives
2251 such as C<clear>, C<random> and C<time> are described in the
2252 L<tune2fs(8)> manpage.
2253
2254 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
2255 to return the existing UUID of a filesystem.");
2256
2257   ("get_e2uuid", (RString "uuid", [Device "device"]), 83, [DeprecatedBy "vfs_uuid"],
2258    (* Regression test for RHBZ#597112. *)
2259    (let uuid = uuidgen () in
2260     [InitBasicFS, Always, TestOutput (
2261        [["mke2journal"; "1024"; "/dev/sdb"];
2262         ["set_e2uuid"; "/dev/sdb"; uuid];
2263         ["get_e2uuid"; "/dev/sdb"]], uuid)]),
2264    "get the ext2/3/4 filesystem UUID",
2265    "\
2266 This returns the ext2/3/4 filesystem UUID of the filesystem on
2267 C<device>.");
2268
2269   ("fsck", (RInt "status", [String "fstype"; Device "device"]), 84, [FishOutput FishOutputHexadecimal],
2270    [InitBasicFS, Always, TestOutputInt (
2271       [["umount"; "/dev/sda1"];
2272        ["fsck"; "ext2"; "/dev/sda1"]], 0);
2273     InitBasicFS, Always, TestOutputInt (
2274       [["umount"; "/dev/sda1"];
2275        ["zero"; "/dev/sda1"];
2276        ["fsck"; "ext2"; "/dev/sda1"]], 8)],
2277    "run the filesystem checker",
2278    "\
2279 This runs the filesystem checker (fsck) on C<device> which
2280 should have filesystem type C<fstype>.
2281
2282 The returned integer is the status.  See L<fsck(8)> for the
2283 list of status codes from C<fsck>.
2284
2285 Notes:
2286
2287 =over 4
2288
2289 =item *
2290
2291 Multiple status codes can be summed together.
2292
2293 =item *
2294
2295 A non-zero return code can mean \"success\", for example if
2296 errors have been corrected on the filesystem.
2297
2298 =item *
2299
2300 Checking or repairing NTFS volumes is not supported
2301 (by linux-ntfs).
2302
2303 =back
2304
2305 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2306
2307   ("zero", (RErr, [Device "device"]), 85, [],
2308    [InitBasicFS, Always, TestOutput (
2309       [["umount"; "/dev/sda1"];
2310        ["zero"; "/dev/sda1"];
2311        ["file"; "/dev/sda1"]], "data")],
2312    "write zeroes to the device",
2313    "\
2314 This command writes zeroes over the first few blocks of C<device>.
2315
2316 How many blocks are zeroed isn't specified (but it's I<not> enough
2317 to securely wipe the device).  It should be sufficient to remove
2318 any partition tables, filesystem superblocks and so on.
2319
2320 See also: C<guestfs_zero_device>, C<guestfs_scrub_device>.");
2321
2322   ("grub_install", (RErr, [Pathname "root"; Device "device"]), 86, [],
2323    (* See:
2324     * https://bugzilla.redhat.com/show_bug.cgi?id=484986
2325     * https://bugzilla.redhat.com/show_bug.cgi?id=479760
2326     *)
2327    [InitBasicFS, Always, TestOutputTrue (
2328       [["mkdir_p"; "/boot/grub"];
2329        ["write"; "/boot/grub/device.map"; "(hd0) /dev/vda"];
2330        ["grub_install"; "/"; "/dev/vda"];
2331        ["is_dir"; "/boot"]])],
2332    "install GRUB",
2333    "\
2334 This command installs GRUB (the Grand Unified Bootloader) on
2335 C<device>, with the root directory being C<root>.
2336
2337 Note: If grub-install reports the error
2338 \"No suitable drive was found in the generated device map.\"
2339 it may be that you need to create a C</boot/grub/device.map>
2340 file first that contains the mapping between grub device names
2341 and Linux device names.  It is usually sufficient to create
2342 a file containing:
2343
2344  (hd0) /dev/vda
2345
2346 replacing C</dev/vda> with the name of the installation device.");
2347
2348   ("cp", (RErr, [Pathname "src"; Pathname "dest"]), 87, [],
2349    [InitBasicFS, Always, TestOutput (
2350       [["write"; "/old"; "file content"];
2351        ["cp"; "/old"; "/new"];
2352        ["cat"; "/new"]], "file content");
2353     InitBasicFS, Always, TestOutputTrue (
2354       [["write"; "/old"; "file content"];
2355        ["cp"; "/old"; "/new"];
2356        ["is_file"; "/old"]]);
2357     InitBasicFS, Always, TestOutput (
2358       [["write"; "/old"; "file content"];
2359        ["mkdir"; "/dir"];
2360        ["cp"; "/old"; "/dir/new"];
2361        ["cat"; "/dir/new"]], "file content")],
2362    "copy a file",
2363    "\
2364 This copies a file from C<src> to C<dest> where C<dest> is
2365 either a destination filename or destination directory.");
2366
2367   ("cp_a", (RErr, [Pathname "src"; Pathname "dest"]), 88, [],
2368    [InitBasicFS, Always, TestOutput (
2369       [["mkdir"; "/olddir"];
2370        ["mkdir"; "/newdir"];
2371        ["write"; "/olddir/file"; "file content"];
2372        ["cp_a"; "/olddir"; "/newdir"];
2373        ["cat"; "/newdir/olddir/file"]], "file content")],
2374    "copy a file or directory recursively",
2375    "\
2376 This copies a file or directory from C<src> to C<dest>
2377 recursively using the C<cp -a> command.");
2378
2379   ("mv", (RErr, [Pathname "src"; Pathname "dest"]), 89, [],
2380    [InitBasicFS, Always, TestOutput (
2381       [["write"; "/old"; "file content"];
2382        ["mv"; "/old"; "/new"];
2383        ["cat"; "/new"]], "file content");
2384     InitBasicFS, Always, TestOutputFalse (
2385       [["write"; "/old"; "file content"];
2386        ["mv"; "/old"; "/new"];
2387        ["is_file"; "/old"]])],
2388    "move a file",
2389    "\
2390 This moves a file from C<src> to C<dest> where C<dest> is
2391 either a destination filename or destination directory.");
2392
2393   ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2394    [InitEmpty, Always, TestRun (
2395       [["drop_caches"; "3"]])],
2396    "drop kernel page cache, dentries and inodes",
2397    "\
2398 This instructs the guest kernel to drop its page cache,
2399 and/or dentries and inode caches.  The parameter C<whattodrop>
2400 tells the kernel what precisely to drop, see
2401 L<http://linux-mm.org/Drop_Caches>
2402
2403 Setting C<whattodrop> to 3 should drop everything.
2404
2405 This automatically calls L<sync(2)> before the operation,
2406 so that the maximum guest memory is freed.");
2407
2408   ("dmesg", (RString "kmsgs", []), 91, [],
2409    [InitEmpty, Always, TestRun (
2410       [["dmesg"]])],
2411    "return kernel messages",
2412    "\
2413 This returns the kernel messages (C<dmesg> output) from
2414 the guest kernel.  This is sometimes useful for extended
2415 debugging of problems.
2416
2417 Another way to get the same information is to enable
2418 verbose messages with C<guestfs_set_verbose> or by setting
2419 the environment variable C<LIBGUESTFS_DEBUG=1> before
2420 running the program.");
2421
2422   ("ping_daemon", (RErr, []), 92, [],
2423    [InitEmpty, Always, TestRun (
2424       [["ping_daemon"]])],
2425    "ping the guest daemon",
2426    "\
2427 This is a test probe into the guestfs daemon running inside
2428 the qemu subprocess.  Calling this function checks that the
2429 daemon responds to the ping message, without affecting the daemon
2430 or attached block device(s) in any other way.");
2431
2432   ("equal", (RBool "equality", [Pathname "file1"; Pathname "file2"]), 93, [],
2433    [InitBasicFS, Always, TestOutputTrue (
2434       [["write"; "/file1"; "contents of a file"];
2435        ["cp"; "/file1"; "/file2"];
2436        ["equal"; "/file1"; "/file2"]]);
2437     InitBasicFS, Always, TestOutputFalse (
2438       [["write"; "/file1"; "contents of a file"];
2439        ["write"; "/file2"; "contents of another file"];
2440        ["equal"; "/file1"; "/file2"]]);
2441     InitBasicFS, Always, TestLastFail (
2442       [["equal"; "/file1"; "/file2"]])],
2443    "test if two files have equal contents",
2444    "\
2445 This compares the two files C<file1> and C<file2> and returns
2446 true if their content is exactly equal, or false otherwise.
2447
2448 The external L<cmp(1)> program is used for the comparison.");
2449
2450   ("strings", (RStringList "stringsout", [Pathname "path"]), 94, [ProtocolLimitWarning],
2451    [InitISOFS, Always, TestOutputList (
2452       [["strings"; "/known-5"]], ["abcdefghi"; "jklmnopqr"]);
2453     InitISOFS, Always, TestOutputList (
2454       [["strings"; "/empty"]], []);
2455     (* Test for RHBZ#579608, absolute symbolic links. *)
2456     InitISOFS, Always, TestRun (
2457       [["strings"; "/abssymlink"]])],
2458    "print the printable strings in a file",
2459    "\
2460 This runs the L<strings(1)> command on a file and returns
2461 the list of printable strings found.");
2462
2463   ("strings_e", (RStringList "stringsout", [String "encoding"; Pathname "path"]), 95, [ProtocolLimitWarning],
2464    [InitISOFS, Always, TestOutputList (
2465       [["strings_e"; "b"; "/known-5"]], []);
2466     InitBasicFS, Always, TestOutputList (
2467       [["write"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"];
2468        ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2469    "print the printable strings in a file",
2470    "\
2471 This is like the C<guestfs_strings> command, but allows you to
2472 specify the encoding of strings that are looked for in
2473 the source file C<path>.
2474
2475 Allowed encodings are:
2476
2477 =over 4
2478
2479 =item s
2480
2481 Single 7-bit-byte characters like ASCII and the ASCII-compatible
2482 parts of ISO-8859-X (this is what C<guestfs_strings> uses).
2483
2484 =item S
2485
2486 Single 8-bit-byte characters.
2487
2488 =item b
2489
2490 16-bit big endian strings such as those encoded in
2491 UTF-16BE or UCS-2BE.
2492
2493 =item l (lower case letter L)
2494
2495 16-bit little endian such as UTF-16LE and UCS-2LE.
2496 This is useful for examining binaries in Windows guests.
2497
2498 =item B
2499
2500 32-bit big endian such as UCS-4BE.
2501
2502 =item L
2503
2504 32-bit little endian such as UCS-4LE.
2505
2506 =back
2507
2508 The returned strings are transcoded to UTF-8.");
2509
2510   ("hexdump", (RString "dump", [Pathname "path"]), 96, [ProtocolLimitWarning],
2511    [InitISOFS, Always, TestOutput (
2512       [["hexdump"; "/known-4"]], "00000000  61 62 63 0a 64 65 66 0a  67 68 69                 |abc.def.ghi|\n0000000b\n");
2513     (* Test for RHBZ#501888c2 regression which caused large hexdump
2514      * commands to segfault.
2515      *)
2516     InitISOFS, Always, TestRun (
2517       [["hexdump"; "/100krandom"]]);
2518     (* Test for RHBZ#579608, absolute symbolic links. *)
2519     InitISOFS, Always, TestRun (
2520       [["hexdump"; "/abssymlink"]])],
2521    "dump a file in hexadecimal",
2522    "\
2523 This runs C<hexdump -C> on the given C<path>.  The result is
2524 the human-readable, canonical hex dump of the file.");
2525
2526   ("zerofree", (RErr, [Device "device"]), 97, [Optional "zerofree"],
2527    [InitNone, Always, TestOutput (
2528       [["part_disk"; "/dev/sda"; "mbr"];
2529        ["mkfs"; "ext3"; "/dev/sda1"];
2530        ["mount_options"; ""; "/dev/sda1"; "/"];
2531        ["write"; "/new"; "test file"];
2532        ["umount"; "/dev/sda1"];
2533        ["zerofree"; "/dev/sda1"];
2534        ["mount_options"; ""; "/dev/sda1"; "/"];
2535        ["cat"; "/new"]], "test file")],
2536    "zero unused inodes and disk blocks on ext2/3 filesystem",
2537    "\
2538 This runs the I<zerofree> program on C<device>.  This program
2539 claims to zero unused inodes and disk blocks on an ext2/3
2540 filesystem, thus making it possible to compress the filesystem
2541 more effectively.
2542
2543 You should B<not> run this program if the filesystem is
2544 mounted.
2545
2546 It is possible that using this program can damage the filesystem
2547 or data on the filesystem.");
2548
2549   ("pvresize", (RErr, [Device "device"]), 98, [Optional "lvm2"],
2550    [],
2551    "resize an LVM physical volume",
2552    "\
2553 This resizes (expands or shrinks) an existing LVM physical
2554 volume to match the new size of the underlying device.");
2555
2556   ("sfdisk_N", (RErr, [Device "device"; Int "partnum";
2557                        Int "cyls"; Int "heads"; Int "sectors";
2558                        String "line"]), 99, [DangerWillRobinson],
2559    [],
2560    "modify a single partition on a block device",
2561    "\
2562 This runs L<sfdisk(8)> option to modify just the single
2563 partition C<n> (note: C<n> counts from 1).
2564
2565 For other parameters, see C<guestfs_sfdisk>.  You should usually
2566 pass C<0> for the cyls/heads/sectors parameters.
2567
2568 See also: C<guestfs_part_add>");
2569
2570   ("sfdisk_l", (RString "partitions", [Device "device"]), 100, [],
2571    [],
2572    "display the partition table",
2573    "\
2574 This displays the partition table on C<device>, in the
2575 human-readable output of the L<sfdisk(8)> command.  It is
2576 not intended to be parsed.
2577
2578 See also: C<guestfs_part_list>");
2579
2580   ("sfdisk_kernel_geometry", (RString "partitions", [Device "device"]), 101, [],
2581    [],
2582    "display the kernel geometry",
2583    "\
2584 This displays the kernel's idea of the geometry of C<device>.
2585
2586 The result is in human-readable format, and not designed to
2587 be parsed.");
2588
2589   ("sfdisk_disk_geometry", (RString "partitions", [Device "device"]), 102, [],
2590    [],
2591    "display the disk geometry from the partition table",
2592    "\
2593 This displays the disk geometry of C<device> read from the
2594 partition table.  Especially in the case where the underlying
2595 block device has been resized, this can be different from the
2596 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2597
2598 The result is in human-readable format, and not designed to
2599 be parsed.");
2600
2601   ("vg_activate_all", (RErr, [Bool "activate"]), 103, [Optional "lvm2"],
2602    [],
2603    "activate or deactivate all volume groups",
2604    "\
2605 This command activates or (if C<activate> is false) deactivates
2606 all logical volumes in all volume groups.
2607 If activated, then they are made known to the
2608 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2609 then those devices disappear.
2610
2611 This command is the same as running C<vgchange -a y|n>");
2612
2613   ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [Optional "lvm2"],
2614    [],
2615    "activate or deactivate some volume groups",
2616    "\
2617 This command activates or (if C<activate> is false) deactivates
2618 all logical volumes in the listed volume groups C<volgroups>.
2619 If activated, then they are made known to the
2620 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2621 then those devices disappear.
2622
2623 This command is the same as running C<vgchange -a y|n volgroups...>
2624
2625 Note that if C<volgroups> is an empty list then B<all> volume groups
2626 are activated or deactivated.");
2627
2628   ("lvresize", (RErr, [Device "device"; Int "mbytes"]), 105, [Optional "lvm2"],
2629    [InitNone, Always, TestOutput (
2630       [["part_disk"; "/dev/sda"; "mbr"];
2631        ["pvcreate"; "/dev/sda1"];
2632        ["vgcreate"; "VG"; "/dev/sda1"];
2633        ["lvcreate"; "LV"; "VG"; "10"];
2634        ["mkfs"; "ext2"; "/dev/VG/LV"];
2635        ["mount_options"; ""; "/dev/VG/LV"; "/"];
2636        ["write"; "/new"; "test content"];
2637        ["umount"; "/"];
2638        ["lvresize"; "/dev/VG/LV"; "20"];
2639        ["e2fsck_f"; "/dev/VG/LV"];
2640        ["resize2fs"; "/dev/VG/LV"];
2641        ["mount_options"; ""; "/dev/VG/LV"; "/"];
2642        ["cat"; "/new"]], "test content");
2643     InitNone, Always, TestRun (
2644       (* Make an LV smaller to test RHBZ#587484. *)
2645       [["part_disk"; "/dev/sda"; "mbr"];
2646        ["pvcreate"; "/dev/sda1"];
2647        ["vgcreate"; "VG"; "/dev/sda1"];
2648        ["lvcreate"; "LV"; "VG"; "20"];
2649        ["lvresize"; "/dev/VG/LV"; "10"]])],
2650    "resize an LVM logical volume",
2651    "\
2652 This resizes (expands or shrinks) an existing LVM logical
2653 volume to C<mbytes>.  When reducing, data in the reduced part
2654 is lost.");
2655
2656   ("resize2fs", (RErr, [Device "device"]), 106, [],
2657    [], (* lvresize tests this *)
2658    "resize an ext2, ext3 or ext4 filesystem",
2659    "\
2660 This resizes an ext2, ext3 or ext4 filesystem to match the size of
2661 the underlying device.
2662
2663 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2664 on the C<device> before calling this command.  For unknown reasons
2665 C<resize2fs> sometimes gives an error about this and sometimes not.
2666 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2667 calling this function.");
2668
2669   ("find", (RStringList "names", [Pathname "directory"]), 107, [ProtocolLimitWarning],
2670    [InitBasicFS, Always, TestOutputList (
2671       [["find"; "/"]], ["lost+found"]);
2672     InitBasicFS, Always, TestOutputList (
2673       [["touch"; "/a"];
2674        ["mkdir"; "/b"];
2675        ["touch"; "/b/c"];
2676        ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2677     InitBasicFS, Always, TestOutputList (
2678       [["mkdir_p"; "/a/b/c"];
2679        ["touch"; "/a/b/c/d"];
2680        ["find"; "/a/b/"]], ["c"; "c/d"])],
2681    "find all files and directories",
2682    "\
2683 This command lists out all files and directories, recursively,
2684 starting at C<directory>.  It is essentially equivalent to
2685 running the shell command C<find directory -print> but some
2686 post-processing happens on the output, described below.
2687
2688 This returns a list of strings I<without any prefix>.  Thus
2689 if the directory structure was:
2690
2691  /tmp/a
2692  /tmp/b
2693  /tmp/c/d
2694
2695 then the returned list from C<guestfs_find> C</tmp> would be
2696 4 elements:
2697
2698  a
2699  b
2700  c
2701  c/d
2702
2703 If C<directory> is not a directory, then this command returns
2704 an error.
2705
2706 The returned list is sorted.
2707
2708 See also C<guestfs_find0>.");
2709
2710   ("e2fsck_f", (RErr, [Device "device"]), 108, [],
2711    [], (* lvresize tests this *)
2712    "check an ext2/ext3 filesystem",
2713    "\
2714 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2715 filesystem checker on C<device>, noninteractively (C<-p>),
2716 even if the filesystem appears to be clean (C<-f>).
2717
2718 This command is only needed because of C<guestfs_resize2fs>
2719 (q.v.).  Normally you should use C<guestfs_fsck>.");
2720
2721   ("sleep", (RErr, [Int "secs"]), 109, [],
2722    [InitNone, Always, TestRun (
2723       [["sleep"; "1"]])],
2724    "sleep for some seconds",
2725    "\
2726 Sleep for C<secs> seconds.");
2727
2728   ("ntfs_3g_probe", (RInt "status", [Bool "rw"; Device "device"]), 110, [Optional "ntfs3g"],
2729    [InitNone, Always, TestOutputInt (
2730       [["part_disk"; "/dev/sda"; "mbr"];
2731        ["mkfs"; "ntfs"; "/dev/sda1"];
2732        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2733     InitNone, Always, TestOutputInt (
2734       [["part_disk"; "/dev/sda"; "mbr"];
2735        ["mkfs"; "ext2"; "/dev/sda1"];
2736        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2737    "probe NTFS volume",
2738    "\
2739 This command runs the L<ntfs-3g.probe(8)> command which probes
2740 an NTFS C<device> for mountability.  (Not all NTFS volumes can
2741 be mounted read-write, and some cannot be mounted at all).
2742
2743 C<rw> is a boolean flag.  Set it to true if you want to test
2744 if the volume can be mounted read-write.  Set it to false if
2745 you want to test if the volume can be mounted read-only.
2746
2747 The return value is an integer which C<0> if the operation
2748 would succeed, or some non-zero value documented in the
2749 L<ntfs-3g.probe(8)> manual page.");
2750
2751   ("sh", (RString "output", [String "command"]), 111, [],
2752    [], (* XXX needs tests *)
2753    "run a command via the shell",
2754    "\
2755 This call runs a command from the guest filesystem via the
2756 guest's C</bin/sh>.
2757
2758 This is like C<guestfs_command>, but passes the command to:
2759
2760  /bin/sh -c \"command\"
2761
2762 Depending on the guest's shell, this usually results in
2763 wildcards being expanded, shell expressions being interpolated
2764 and so on.
2765
2766 All the provisos about C<guestfs_command> apply to this call.");
2767
2768   ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2769    [], (* XXX needs tests *)
2770    "run a command via the shell returning lines",
2771    "\
2772 This is the same as C<guestfs_sh>, but splits the result
2773 into a list of lines.
2774
2775 See also: C<guestfs_command_lines>");
2776
2777   ("glob_expand", (RStringList "paths", [Pathname "pattern"]), 113, [],
2778    (* Use Pathname here, and hence ABS_PATH (pattern,... in generated
2779     * code in stubs.c, since all valid glob patterns must start with "/".
2780     * There is no concept of "cwd" in libguestfs, hence no "."-relative names.
2781     *)
2782    [InitBasicFS, Always, TestOutputList (
2783       [["mkdir_p"; "/a/b/c"];
2784        ["touch"; "/a/b/c/d"];
2785        ["touch"; "/a/b/c/e"];
2786        ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2787     InitBasicFS, Always, TestOutputList (
2788       [["mkdir_p"; "/a/b/c"];
2789        ["touch"; "/a/b/c/d"];
2790        ["touch"; "/a/b/c/e"];
2791        ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2792     InitBasicFS, Always, TestOutputList (
2793       [["mkdir_p"; "/a/b/c"];
2794        ["touch"; "/a/b/c/d"];
2795        ["touch"; "/a/b/c/e"];
2796        ["glob_expand"; "/a/*/x/*"]], [])],
2797    "expand a wildcard path",
2798    "\
2799 This command searches for all the pathnames matching
2800 C<pattern> according to the wildcard expansion rules
2801 used by the shell.
2802
2803 If no paths match, then this returns an empty list
2804 (note: not an error).
2805
2806 It is just a wrapper around the C L<glob(3)> function
2807 with flags C<GLOB_MARK|GLOB_BRACE>.
2808 See that manual page for more details.");
2809
2810   ("scrub_device", (RErr, [Device "device"]), 114, [DangerWillRobinson; Optional "scrub"],
2811    [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2812       [["scrub_device"; "/dev/sdc"]])],
2813    "scrub (securely wipe) a device",
2814    "\
2815 This command writes patterns over C<device> to make data retrieval
2816 more difficult.
2817
2818 It is an interface to the L<scrub(1)> program.  See that
2819 manual page for more details.");
2820
2821   ("scrub_file", (RErr, [Pathname "file"]), 115, [Optional "scrub"],
2822    [InitBasicFS, Always, TestRun (
2823       [["write"; "/file"; "content"];
2824        ["scrub_file"; "/file"]])],
2825    "scrub (securely wipe) a file",
2826    "\
2827 This command writes patterns over a file to make data retrieval
2828 more difficult.
2829
2830 The file is I<removed> after scrubbing.
2831
2832 It is an interface to the L<scrub(1)> program.  See that
2833 manual page for more details.");
2834
2835   ("scrub_freespace", (RErr, [Pathname "dir"]), 116, [Optional "scrub"],
2836    [], (* XXX needs testing *)
2837    "scrub (securely wipe) free space",
2838    "\
2839 This command creates the directory C<dir> and then fills it
2840 with files until the filesystem is full, and scrubs the files
2841 as for C<guestfs_scrub_file>, and deletes them.
2842 The intention is to scrub any free space on the partition
2843 containing C<dir>.
2844
2845 It is an interface to the L<scrub(1)> program.  See that
2846 manual page for more details.");
2847
2848   ("mkdtemp", (RString "dir", [Pathname "template"]), 117, [],
2849    [InitBasicFS, Always, TestRun (
2850       [["mkdir"; "/tmp"];
2851        ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2852    "create a temporary directory",
2853    "\
2854 This command creates a temporary directory.  The
2855 C<template> parameter should be a full pathname for the
2856 temporary directory name with the final six characters being
2857 \"XXXXXX\".
2858
2859 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2860 the second one being suitable for Windows filesystems.
2861
2862 The name of the temporary directory that was created
2863 is returned.
2864
2865 The temporary directory is created with mode 0700
2866 and is owned by root.
2867
2868 The caller is responsible for deleting the temporary
2869 directory and its contents after use.
2870
2871 See also: L<mkdtemp(3)>");
2872
2873   ("wc_l", (RInt "lines", [Pathname "path"]), 118, [],
2874    [InitISOFS, Always, TestOutputInt (
2875       [["wc_l"; "/10klines"]], 10000);
2876     (* Test for RHBZ#579608, absolute symbolic links. *)
2877     InitISOFS, Always, TestOutputInt (
2878       [["wc_l"; "/abssymlink"]], 10000)],
2879    "count lines in a file",
2880    "\
2881 This command counts the lines in a file, using the
2882 C<wc -l> external command.");
2883
2884   ("wc_w", (RInt "words", [Pathname "path"]), 119, [],
2885    [InitISOFS, Always, TestOutputInt (
2886       [["wc_w"; "/10klines"]], 10000)],
2887    "count words in a file",
2888    "\
2889 This command counts the words in a file, using the
2890 C<wc -w> external command.");
2891
2892   ("wc_c", (RInt "chars", [Pathname "path"]), 120, [],
2893    [InitISOFS, Always, TestOutputInt (
2894       [["wc_c"; "/100kallspaces"]], 102400)],
2895    "count characters in a file",
2896    "\
2897 This command counts the characters in a file, using the
2898 C<wc -c> external command.");
2899
2900   ("head", (RStringList "lines", [Pathname "path"]), 121, [ProtocolLimitWarning],
2901    [InitISOFS, Always, TestOutputList (
2902       [["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"]);
2903     (* Test for RHBZ#579608, absolute symbolic links. *)
2904     InitISOFS, Always, TestOutputList (
2905       [["head"; "/abssymlink"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2906    "return first 10 lines of a file",
2907    "\
2908 This command returns up to the first 10 lines of a file as
2909 a list of strings.");
2910
2911   ("head_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 122, [ProtocolLimitWarning],
2912    [InitISOFS, Always, TestOutputList (
2913       [["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2914     InitISOFS, Always, TestOutputList (
2915       [["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2916     InitISOFS, Always, TestOutputList (
2917       [["head_n"; "0"; "/10klines"]], [])],
2918    "return first N lines of a file",
2919    "\
2920 If the parameter C<nrlines> is a positive number, this returns the first
2921 C<nrlines> lines of the file C<path>.
2922
2923 If the parameter C<nrlines> is a negative number, this returns lines
2924 from the file C<path>, excluding the last C<nrlines> lines.
2925
2926 If the parameter C<nrlines> is zero, this returns an empty list.");
2927
2928   ("tail", (RStringList "lines", [Pathname "path"]), 123, [ProtocolLimitWarning],
2929    [InitISOFS, Always, TestOutputList (
2930       [["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2931    "return last 10 lines of a file",
2932    "\
2933 This command returns up to the last 10 lines of a file as
2934 a list of strings.");
2935
2936   ("tail_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 124, [ProtocolLimitWarning],
2937    [InitISOFS, Always, TestOutputList (
2938       [["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2939     InitISOFS, Always, TestOutputList (
2940       [["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2941     InitISOFS, Always, TestOutputList (
2942       [["tail_n"; "0"; "/10klines"]], [])],
2943    "return last N lines of a file",
2944    "\
2945 If the parameter C<nrlines> is a positive number, this returns the last
2946 C<nrlines> lines of the file C<path>.
2947
2948 If the parameter C<nrlines> is a negative number, this returns lines
2949 from the file C<path>, starting with the C<-nrlines>th line.
2950
2951 If the parameter C<nrlines> is zero, this returns an empty list.");
2952
2953   ("df", (RString "output", []), 125, [],
2954    [], (* XXX Tricky to test because it depends on the exact format
2955         * of the 'df' command and other imponderables.
2956         *)
2957    "report file system disk space usage",
2958    "\
2959 This command runs the C<df> command to report disk space used.
2960
2961 This command is mostly useful for interactive sessions.  It
2962 is I<not> intended that you try to parse the output string.
2963 Use C<statvfs> from programs.");
2964
2965   ("df_h", (RString "output", []), 126, [],
2966    [], (* XXX Tricky to test because it depends on the exact format
2967         * of the 'df' command and other imponderables.
2968         *)
2969    "report file system disk space usage (human readable)",
2970    "\
2971 This command runs the C<df -h> command to report disk space used
2972 in human-readable format.
2973
2974 This command is mostly useful for interactive sessions.  It
2975 is I<not> intended that you try to parse the output string.
2976 Use C<statvfs> from programs.");
2977
2978   ("du", (RInt64 "sizekb", [Pathname "path"]), 127, [],
2979    [InitISOFS, Always, TestOutputInt (
2980       [["du"; "/directory"]], 2 (* ISO fs blocksize is 2K *))],
2981    "estimate file space usage",
2982    "\
2983 This command runs the C<du -s> command to estimate file space
2984 usage for C<path>.
2985
2986 C<path> can be a file or a directory.  If C<path> is a directory
2987 then the estimate includes the contents of the directory and all
2988 subdirectories (recursively).
2989
2990 The result is the estimated size in I<kilobytes>
2991 (ie. units of 1024 bytes).");
2992
2993   ("initrd_list", (RStringList "filenames", [Pathname "path"]), 128, [],
2994    [InitISOFS, Always, TestOutputList (
2995       [["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3";"known-4"; "known-5"])],
2996    "list files in an initrd",
2997    "\
2998 This command lists out files contained in an initrd.
2999
3000 The files are listed without any initial C</> character.  The
3001 files are listed in the order they appear (not necessarily
3002 alphabetical).  Directory names are listed as separate items.
3003
3004 Old Linux kernels (2.4 and earlier) used a compressed ext2
3005 filesystem as initrd.  We I<only> support the newer initramfs
3006 format (compressed cpio files).");
3007
3008   ("mount_loop", (RErr, [Pathname "file"; Pathname "mountpoint"]), 129, [],
3009    [],
3010    "mount a file using the loop device",
3011    "\
3012 This command lets you mount C<file> (a filesystem image
3013 in a file) on a mount point.  It is entirely equivalent to
3014 the command C<mount -o loop file mountpoint>.");
3015
3016   ("mkswap", (RErr, [Device "device"]), 130, [],
3017    [InitEmpty, Always, TestRun (
3018       [["part_disk"; "/dev/sda"; "mbr"];
3019        ["mkswap"; "/dev/sda1"]])],
3020    "create a swap partition",
3021    "\
3022 Create a swap partition on C<device>.");
3023
3024   ("mkswap_L", (RErr, [String "label"; Device "device"]), 131, [],
3025    [InitEmpty, Always, TestRun (
3026       [["part_disk"; "/dev/sda"; "mbr"];
3027        ["mkswap_L"; "hello"; "/dev/sda1"]])],
3028    "create a swap partition with a label",
3029    "\
3030 Create a swap partition on C<device> with label C<label>.
3031
3032 Note that you cannot attach a swap label to a block device
3033 (eg. C</dev/sda>), just to a partition.  This appears to be
3034 a limitation of the kernel or swap tools.");
3035
3036   ("mkswap_U", (RErr, [String "uuid"; Device "device"]), 132, [Optional "linuxfsuuid"],
3037    (let uuid = uuidgen () in
3038     [InitEmpty, Always, TestRun (
3039        [["part_disk"; "/dev/sda"; "mbr"];
3040         ["mkswap_U"; uuid; "/dev/sda1"]])]),
3041    "create a swap partition with an explicit UUID",
3042    "\
3043 Create a swap partition on C<device> with UUID C<uuid>.");
3044
3045   ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 133, [Optional "mknod"],
3046    [InitBasicFS, Always, TestOutputStruct (
3047       [["mknod"; "0o10777"; "0"; "0"; "/node"];
3048        (* NB: default umask 022 means 0777 -> 0755 in these tests *)
3049        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
3050     InitBasicFS, Always, TestOutputStruct (
3051       [["mknod"; "0o60777"; "66"; "99"; "/node"];
3052        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
3053    "make block, character or FIFO devices",
3054    "\
3055 This call creates block or character special devices, or
3056 named pipes (FIFOs).
3057
3058 The C<mode> parameter should be the mode, using the standard
3059 constants.  C<devmajor> and C<devminor> are the
3060 device major and minor numbers, only used when creating block
3061 and character special devices.
3062
3063 Note that, just like L<mknod(2)>, the mode must be bitwise
3064 OR'd with S_IFBLK, S_IFCHR, S_IFIFO or S_IFSOCK (otherwise this call
3065 just creates a regular file).  These constants are
3066 available in the standard Linux header files, or you can use
3067 C<guestfs_mknod_b>, C<guestfs_mknod_c> or C<guestfs_mkfifo>
3068 which are wrappers around this command which bitwise OR
3069 in the appropriate constant for you.
3070
3071 The mode actually set is affected by the umask.");
3072
3073   ("mkfifo", (RErr, [Int "mode"; Pathname "path"]), 134, [Optional "mknod"],
3074    [InitBasicFS, Always, TestOutputStruct (
3075       [["mkfifo"; "0o777"; "/node"];
3076        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
3077    "make FIFO (named pipe)",
3078    "\
3079 This call creates a FIFO (named pipe) called C<path> with
3080 mode C<mode>.  It is just a convenient wrapper around
3081 C<guestfs_mknod>.
3082
3083 The mode actually set is affected by the umask.");
3084
3085   ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 135, [Optional "mknod"],
3086    [InitBasicFS, Always, TestOutputStruct (
3087       [["mknod_b"; "0o777"; "99"; "66"; "/node"];
3088        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
3089    "make block device node",
3090    "\
3091 This call creates a block device node called C<path> with
3092 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
3093 It is just a convenient wrapper around C<guestfs_mknod>.
3094
3095 The mode actually set is affected by the umask.");
3096
3097   ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 136, [Optional "mknod"],
3098    [InitBasicFS, Always, TestOutputStruct (
3099       [["mknod_c"; "0o777"; "99"; "66"; "/node"];
3100        ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
3101    "make char device node",
3102    "\
3103 This call creates a char device node called C<path> with
3104 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
3105 It is just a convenient wrapper around C<guestfs_mknod>.
3106
3107 The mode actually set is affected by the umask.");
3108
3109   ("umask", (RInt "oldmask", [Int "mask"]), 137, [FishOutput FishOutputOctal],
3110    [InitEmpty, Always, TestOutputInt (
3111       [["umask"; "0o22"]], 0o22)],
3112    "set file mode creation mask (umask)",
3113    "\
3114 This function sets the mask used for creating new files and
3115 device nodes to C<mask & 0777>.
3116
3117 Typical umask values would be C<022> which creates new files
3118 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
3119 C<002> which creates new files with permissions like
3120 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
3121
3122 The default umask is C<022>.  This is important because it
3123 means that directories and device nodes will be created with
3124 C<0644> or C<0755> mode even if you specify C<0777>.
3125
3126 See also C<guestfs_get_umask>,
3127 L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
3128
3129 This call returns the previous umask.");
3130
3131   ("readdir", (RStructList ("entries", "dirent"), [Pathname "dir"]), 138, [],
3132    [],
3133    "read directories entries",
3134    "\
3135 This returns the list of directory entries in directory C<dir>.
3136
3137 All entries in the directory are returned, including C<.> and
3138 C<..>.  The entries are I<not> sorted, but returned in the same
3139 order as the underlying filesystem.
3140
3141 Also this call returns basic file type information about each
3142 file.  The C<ftyp> field will contain one of the following characters:
3143
3144 =over 4
3145
3146 =item 'b'
3147
3148 Block special
3149
3150 =item 'c'
3151
3152 Char special
3153
3154 =item 'd'
3155
3156 Directory
3157
3158 =item 'f'
3159
3160 FIFO (named pipe)
3161
3162 =item 'l'
3163
3164 Symbolic link
3165
3166 =item 'r'
3167
3168 Regular file
3169
3170 =item 's'
3171
3172 Socket
3173
3174 =item 'u'
3175
3176 Unknown file type
3177
3178 =item '?'
3179
3180 The L<readdir(3)> call returned a C<d_type> field with an
3181 unexpected value
3182
3183 =back
3184
3185 This function is primarily intended for use by programs.  To
3186 get a simple list of names, use C<guestfs_ls>.  To get a printable
3187 directory for human consumption, use C<guestfs_ll>.");
3188
3189   ("sfdiskM", (RErr, [Device "device"; StringList "lines"]), 139, [DangerWillRobinson],
3190    [],
3191    "create partitions on a block device",
3192    "\
3193 This is a simplified interface to the C<guestfs_sfdisk>
3194 command, where partition sizes are specified in megabytes
3195 only (rounded to the nearest cylinder) and you don't need
3196 to specify the cyls, heads and sectors parameters which
3197 were rarely if ever used anyway.
3198
3199 See also: C<guestfs_sfdisk>, the L<sfdisk(8)> manpage
3200 and C<guestfs_part_disk>");
3201
3202   ("zfile", (RString "description", [String "meth"; Pathname "path"]), 140, [DeprecatedBy "file"],
3203    [],
3204    "determine file type inside a compressed file",
3205    "\
3206 This command runs C<file> after first decompressing C<path>
3207 using C<method>.
3208
3209 C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
3210
3211 Since 1.0.63, use C<guestfs_file> instead which can now
3212 process compressed files.");
3213
3214   ("getxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 141, [Optional "linuxxattrs"],
3215    [],
3216    "list extended attributes of a file or directory",
3217    "\
3218 This call lists the extended attributes of the file or directory
3219 C<path>.
3220
3221 At the system call level, this is a combination of the
3222 L<listxattr(2)> and L<getxattr(2)> calls.
3223
3224 See also: C<guestfs_lgetxattrs>, L<attr(5)>.");
3225
3226   ("lgetxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 142, [Optional "linuxxattrs"],
3227    [],
3228    "list extended attributes of a file or directory",
3229    "\
3230 This is the same as C<guestfs_getxattrs>, but if C<path>
3231 is a symbolic link, then it returns the extended attributes
3232 of the link itself.");
3233
3234   ("setxattr", (RErr, [String "xattr";
3235                        String "val"; Int "vallen"; (* will be BufferIn *)
3236                        Pathname "path"]), 143, [Optional "linuxxattrs"],
3237    [],
3238    "set extended attribute of a file or directory",
3239    "\
3240 This call sets the extended attribute named C<xattr>
3241 of the file C<path> to the value C<val> (of length C<vallen>).
3242 The value is arbitrary 8 bit data.
3243
3244 See also: C<guestfs_lsetxattr>, L<attr(5)>.");
3245
3246   ("lsetxattr", (RErr, [String "xattr";
3247                         String "val"; Int "vallen"; (* will be BufferIn *)
3248                         Pathname "path"]), 144, [Optional "linuxxattrs"],
3249    [],
3250    "set extended attribute of a file or directory",
3251    "\
3252 This is the same as C<guestfs_setxattr>, but if C<path>
3253 is a symbolic link, then it sets an extended attribute
3254 of the link itself.");
3255
3256   ("removexattr", (RErr, [String "xattr"; Pathname "path"]), 145, [Optional "linuxxattrs"],
3257    [],
3258    "remove extended attribute of a file or directory",
3259    "\
3260 This call removes the extended attribute named C<xattr>
3261 of the file C<path>.
3262
3263 See also: C<guestfs_lremovexattr>, L<attr(5)>.");
3264
3265   ("lremovexattr", (RErr, [String "xattr"; Pathname "path"]), 146, [Optional "linuxxattrs"],
3266    [],
3267    "remove extended attribute of a file or directory",
3268    "\
3269 This is the same as C<guestfs_removexattr>, but if C<path>
3270 is a symbolic link, then it removes an extended attribute
3271 of the link itself.");
3272
3273   ("mountpoints", (RHashtable "mps", []), 147, [],
3274    [],
3275    "show mountpoints",
3276    "\
3277 This call is similar to C<guestfs_mounts>.  That call returns
3278 a list of devices.  This one returns a hash table (map) of
3279 device name to directory where the device is mounted.");
3280
3281   ("mkmountpoint", (RErr, [String "exemptpath"]), 148, [],
3282    (* This is a special case: while you would expect a parameter
3283     * of type "Pathname", that doesn't work, because it implies
3284     * NEED_ROOT in the generated calling code in stubs.c, and
3285     * this function cannot use NEED_ROOT.
3286     *)
3287    [],
3288    "create a mountpoint",
3289    "\
3290 C<guestfs_mkmountpoint> and C<guestfs_rmmountpoint> are
3291 specialized calls that can be used to create extra mountpoints
3292 before mounting the first filesystem.
3293
3294 These calls are I<only> necessary in some very limited circumstances,
3295 mainly the case where you want to mount a mix of unrelated and/or
3296 read-only filesystems together.
3297
3298 For example, live CDs often contain a \"Russian doll\" nest of
3299 filesystems, an ISO outer layer, with a squashfs image inside, with
3300 an ext2/3 image inside that.  You can unpack this as follows
3301 in guestfish:
3302
3303  add-ro Fedora-11-i686-Live.iso
3304  run
3305  mkmountpoint /cd
3306  mkmountpoint /squash
3307  mkmountpoint /ext3
3308  mount /dev/sda /cd
3309  mount-loop /cd/LiveOS/squashfs.img /squash
3310  mount-loop /squash/LiveOS/ext3fs.img /ext3
3311
3312 The inner filesystem is now unpacked under the /ext3 mountpoint.");
3313
3314   ("rmmountpoint", (RErr, [String "exemptpath"]), 149, [],
3315    [],
3316    "remove a mountpoint",
3317    "\
3318 This calls removes a mountpoint that was previously created
3319 with C<guestfs_mkmountpoint>.  See C<guestfs_mkmountpoint>
3320 for full details.");
3321
3322   ("read_file", (RBufferOut "content", [Pathname "path"]), 150, [ProtocolLimitWarning],
3323    [InitISOFS, Always, TestOutputBuffer (
3324       [["read_file"; "/known-4"]], "abc\ndef\nghi");
3325     (* Test various near large, large and too large files (RHBZ#589039). *)
3326     InitBasicFS, Always, TestLastFail (
3327       [["touch"; "/a"];
3328        ["truncate_size"; "/a"; "4194303"]; (* GUESTFS_MESSAGE_MAX - 1 *)
3329        ["read_file"; "/a"]]);
3330     InitBasicFS, Always, TestLastFail (
3331       [["touch"; "/a"];
3332        ["truncate_size"; "/a"; "4194304"]; (* GUESTFS_MESSAGE_MAX *)
3333        ["read_file"; "/a"]]);
3334     InitBasicFS, Always, TestLastFail (
3335       [["touch"; "/a"];
3336        ["truncate_size"; "/a"; "41943040"]; (* GUESTFS_MESSAGE_MAX * 10 *)
3337        ["read_file"; "/a"]])],
3338    "read a file",
3339    "\
3340 This calls returns the contents of the file C<path> as a
3341 buffer.
3342
3343 Unlike C<guestfs_cat>, this function can correctly
3344 handle files that contain embedded ASCII NUL characters.
3345 However unlike C<guestfs_download>, this function is limited
3346 in the total size of file that can be handled.");
3347
3348   ("grep", (RStringList "lines", [String "regex"; Pathname "path"]), 151, [ProtocolLimitWarning],
3349    [InitISOFS, Always, TestOutputList (
3350       [["grep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"]);
3351     InitISOFS, Always, TestOutputList (
3352       [["grep"; "nomatch"; "/test-grep.txt"]], []);
3353     (* Test for RHBZ#579608, absolute symbolic links. *)
3354     InitISOFS, Always, TestOutputList (
3355       [["grep"; "nomatch"; "/abssymlink"]], [])],
3356    "return lines matching a pattern",
3357    "\
3358 This calls the external C<grep> program and returns the
3359 matching lines.");
3360
3361   ("egrep", (RStringList "lines", [String "regex"; Pathname "path"]), 152, [ProtocolLimitWarning],
3362    [InitISOFS, Always, TestOutputList (
3363       [["egrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3364    "return lines matching a pattern",
3365    "\
3366 This calls the external C<egrep> program and returns the
3367 matching lines.");
3368
3369   ("fgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 153, [ProtocolLimitWarning],
3370    [InitISOFS, Always, TestOutputList (
3371       [["fgrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3372    "return lines matching a pattern",
3373    "\
3374 This calls the external C<fgrep> program and returns the
3375 matching lines.");
3376
3377   ("grepi", (RStringList "lines", [String "regex"; Pathname "path"]), 154, [ProtocolLimitWarning],
3378    [InitISOFS, Always, TestOutputList (
3379       [["grepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3380    "return lines matching a pattern",
3381    "\
3382 This calls the external C<grep -i> program and returns the
3383 matching lines.");
3384
3385   ("egrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 155, [ProtocolLimitWarning],
3386    [InitISOFS, Always, TestOutputList (
3387       [["egrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3388    "return lines matching a pattern",
3389    "\
3390 This calls the external C<egrep -i> program and returns the
3391 matching lines.");
3392
3393   ("fgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 156, [ProtocolLimitWarning],
3394    [InitISOFS, Always, TestOutputList (
3395       [["fgrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3396    "return lines matching a pattern",
3397    "\
3398 This calls the external C<fgrep -i> program and returns the
3399 matching lines.");
3400
3401   ("zgrep", (RStringList "lines", [String "regex"; Pathname "path"]), 157, [ProtocolLimitWarning],
3402    [InitISOFS, Always, TestOutputList (
3403       [["zgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3404    "return lines matching a pattern",
3405    "\
3406 This calls the external C<zgrep> program and returns the
3407 matching lines.");
3408
3409   ("zegrep", (RStringList "lines", [String "regex"; Pathname "path"]), 158, [ProtocolLimitWarning],
3410    [InitISOFS, Always, TestOutputList (
3411       [["zegrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3412    "return lines matching a pattern",
3413    "\
3414 This calls the external C<zegrep> program and returns the
3415 matching lines.");
3416
3417   ("zfgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 159, [ProtocolLimitWarning],
3418    [InitISOFS, Always, TestOutputList (
3419       [["zfgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3420    "return lines matching a pattern",
3421    "\
3422 This calls the external C<zfgrep> program and returns the
3423 matching lines.");
3424
3425   ("zgrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 160, [ProtocolLimitWarning],
3426    [InitISOFS, Always, TestOutputList (
3427       [["zgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3428    "return lines matching a pattern",
3429    "\
3430 This calls the external C<zgrep -i> program and returns the
3431 matching lines.");
3432
3433   ("zegrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 161, [ProtocolLimitWarning],
3434    [InitISOFS, Always, TestOutputList (
3435       [["zegrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3436    "return lines matching a pattern",
3437    "\
3438 This calls the external C<zegrep -i> program and returns the
3439 matching lines.");
3440
3441   ("zfgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 162, [ProtocolLimitWarning],
3442    [InitISOFS, Always, TestOutputList (
3443       [["zfgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3444    "return lines matching a pattern",
3445    "\
3446 This calls the external C<zfgrep -i> program and returns the
3447 matching lines.");
3448
3449   ("realpath", (RString "rpath", [Pathname "path"]), 163, [Optional "realpath"],
3450    [InitISOFS, Always, TestOutput (
3451       [["realpath"; "/../directory"]], "/directory")],
3452    "canonicalized absolute pathname",
3453    "\
3454 Return the canonicalized absolute pathname of C<path>.  The
3455 returned path has no C<.>, C<..> or symbolic link path elements.");
3456
3457   ("ln", (RErr, [String "target"; Pathname "linkname"]), 164, [],
3458    [InitBasicFS, Always, TestOutputStruct (
3459       [["touch"; "/a"];
3460        ["ln"; "/a"; "/b"];
3461        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3462    "create a hard link",
3463    "\
3464 This command creates a hard link using the C<ln> command.");
3465
3466   ("ln_f", (RErr, [String "target"; Pathname "linkname"]), 165, [],
3467    [InitBasicFS, Always, TestOutputStruct (
3468       [["touch"; "/a"];
3469        ["touch"; "/b"];
3470        ["ln_f"; "/a"; "/b"];
3471        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3472    "create a hard link",
3473    "\
3474 This command creates a hard link using the C<ln -f> command.
3475 The C<-f> option removes the link (C<linkname>) if it exists already.");
3476
3477   ("ln_s", (RErr, [String "target"; Pathname "linkname"]), 166, [],
3478    [InitBasicFS, Always, TestOutputStruct (
3479       [["touch"; "/a"];
3480        ["ln_s"; "a"; "/b"];
3481        ["lstat"; "/b"]], [CompareWithInt ("mode", 0o120777)])],
3482    "create a symbolic link",
3483    "\
3484 This command creates a symbolic link using the C<ln -s> command.");
3485
3486   ("ln_sf", (RErr, [String "target"; Pathname "linkname"]), 167, [],
3487    [InitBasicFS, Always, TestOutput (
3488       [["mkdir_p"; "/a/b"];
3489        ["touch"; "/a/b/c"];
3490        ["ln_sf"; "../d"; "/a/b/c"];
3491        ["readlink"; "/a/b/c"]], "../d")],
3492    "create a symbolic link",
3493    "\
3494 This command creates a symbolic link using the C<ln -sf> command,
3495 The C<-f> option removes the link (C<linkname>) if it exists already.");
3496
3497   ("readlink", (RString "link", [Pathname "path"]), 168, [],
3498    [] (* XXX tested above *),
3499    "read the target of a symbolic link",
3500    "\
3501 This command reads the target of a symbolic link.");
3502
3503   ("fallocate", (RErr, [Pathname "path"; Int "len"]), 169, [DeprecatedBy "fallocate64"],
3504    [InitBasicFS, Always, TestOutputStruct (
3505       [["fallocate"; "/a"; "1000000"];
3506        ["stat"; "/a"]], [CompareWithInt ("size", 1_000_000)])],
3507    "preallocate a file in the guest filesystem",
3508    "\
3509 This command preallocates a file (containing zero bytes) named
3510 C<path> of size C<len> bytes.  If the file exists already, it
3511 is overwritten.
3512
3513 Do not confuse this with the guestfish-specific
3514 C<alloc> command which allocates a file in the host and
3515 attaches it as a device.");
3516
3517   ("swapon_device", (RErr, [Device "device"]), 170, [],
3518    [InitPartition, Always, TestRun (
3519       [["mkswap"; "/dev/sda1"];
3520        ["swapon_device"; "/dev/sda1"];
3521        ["swapoff_device"; "/dev/sda1"]])],
3522    "enable swap on device",
3523    "\
3524 This command enables the libguestfs appliance to use the
3525 swap device or partition named C<device>.  The increased
3526 memory is made available for all commands, for example
3527 those run using C<guestfs_command> or C<guestfs_sh>.
3528
3529 Note that you should not swap to existing guest swap
3530 partitions unless you know what you are doing.  They may
3531 contain hibernation information, or other information that
3532 the guest doesn't want you to trash.  You also risk leaking
3533 information about the host to the guest this way.  Instead,
3534 attach a new host device to the guest and swap on that.");
3535
3536   ("swapoff_device", (RErr, [Device "device"]), 171, [],
3537    [], (* XXX tested by swapon_device *)
3538    "disable swap on device",
3539    "\
3540 This command disables the libguestfs appliance swap
3541 device or partition named C<device>.
3542 See C<guestfs_swapon_device>.");
3543
3544   ("swapon_file", (RErr, [Pathname "file"]), 172, [],
3545    [InitBasicFS, Always, TestRun (
3546       [["fallocate"; "/swap"; "8388608"];
3547        ["mkswap_file"; "/swap"];
3548        ["swapon_file"; "/swap"];
3549        ["swapoff_file"; "/swap"]])],
3550    "enable swap on file",
3551    "\
3552 This command enables swap to a file.
3553 See C<guestfs_swapon_device> for other notes.");
3554
3555   ("swapoff_file", (RErr, [Pathname "file"]), 173, [],
3556    [], (* XXX tested by swapon_file *)
3557    "disable swap on file",
3558    "\
3559 This command disables the libguestfs appliance swap on file.");
3560
3561   ("swapon_label", (RErr, [String "label"]), 174, [],
3562    [InitEmpty, Always, TestRun (
3563       [["part_disk"; "/dev/sdb"; "mbr"];
3564        ["mkswap_L"; "swapit"; "/dev/sdb1"];
3565        ["swapon_label"; "swapit"];
3566        ["swapoff_label"; "swapit"];
3567        ["zero"; "/dev/sdb"];
3568        ["blockdev_rereadpt"; "/dev/sdb"]])],
3569    "enable swap on labeled swap partition",
3570    "\
3571 This command enables swap to a labeled swap partition.
3572 See C<guestfs_swapon_device> for other notes.");
3573
3574   ("swapoff_label", (RErr, [String "label"]), 175, [],
3575    [], (* XXX tested by swapon_label *)
3576    "disable swap on labeled swap partition",
3577    "\
3578 This command disables the libguestfs appliance swap on
3579 labeled swap partition.");
3580
3581   ("swapon_uuid", (RErr, [String "uuid"]), 176, [Optional "linuxfsuuid"],
3582    (let uuid = uuidgen () in
3583     [InitEmpty, Always, TestRun (
3584        [["mkswap_U"; uuid; "/dev/sdb"];
3585         ["swapon_uuid"; uuid];
3586         ["swapoff_uuid"; uuid]])]),
3587    "enable swap on swap partition by UUID",
3588    "\
3589 This command enables swap to a swap partition with the given UUID.
3590 See C<guestfs_swapon_device> for other notes.");
3591
3592   ("swapoff_uuid", (RErr, [String "uuid"]), 177, [Optional "linuxfsuuid"],
3593    [], (* XXX tested by swapon_uuid *)
3594    "disable swap on swap partition by UUID",
3595    "\
3596 This command disables the libguestfs appliance swap partition
3597 with the given UUID.");
3598
3599   ("mkswap_file", (RErr, [Pathname "path"]), 178, [],
3600    [InitBasicFS, Always, TestRun (
3601       [["fallocate"; "/swap"; "8388608"];
3602        ["mkswap_file"; "/swap"]])],
3603    "create a swap file",
3604    "\
3605 Create a swap file.
3606
3607 This command just writes a swap file signature to an existing
3608 file.  To create the file itself, use something like C<guestfs_fallocate>.");
3609
3610   ("inotify_init", (RErr, [Int "maxevents"]), 179, [Optional "inotify"],
3611    [InitISOFS, Always, TestRun (
3612       [["inotify_init"; "0"]])],
3613    "create an inotify handle",
3614    "\
3615 This command creates a new inotify handle.
3616 The inotify subsystem can be used to notify events which happen to
3617 objects in the guest filesystem.
3618
3619 C<maxevents> is the maximum number of events which will be
3620 queued up between calls to C<guestfs_inotify_read> or
3621 C<guestfs_inotify_files>.
3622 If this is passed as C<0>, then the kernel (or previously set)
3623 default is used.  For Linux 2.6.29 the default was 16384 events.
3624 Beyond this limit, the kernel throws away events, but records
3625 the fact that it threw them away by setting a flag
3626 C<IN_Q_OVERFLOW> in the returned structure list (see
3627 C<guestfs_inotify_read>).
3628
3629 Before any events are generated, you have to add some
3630 watches to the internal watch list.  See:
3631 C<guestfs_inotify_add_watch>,
3632 C<guestfs_inotify_rm_watch> and
3633 C<guestfs_inotify_watch_all>.
3634
3635 Queued up events should be read periodically by calling
3636 C<guestfs_inotify_read>
3637 (or C<guestfs_inotify_files> which is just a helpful
3638 wrapper around C<guestfs_inotify_read>).  If you don't
3639 read the events out often enough then you risk the internal
3640 queue overflowing.
3641
3642 The handle should be closed after use by calling
3643 C<guestfs_inotify_close>.  This also removes any
3644 watches automatically.
3645
3646 See also L<inotify(7)> for an overview of the inotify interface
3647 as exposed by the Linux kernel, which is roughly what we expose
3648 via libguestfs.  Note that there is one global inotify handle
3649 per libguestfs instance.");
3650
3651   ("inotify_add_watch", (RInt64 "wd", [Pathname "path"; Int "mask"]), 180, [Optional "inotify"],
3652    [InitBasicFS, Always, TestOutputList (
3653       [["inotify_init"; "0"];
3654        ["inotify_add_watch"; "/"; "1073741823"];
3655        ["touch"; "/a"];
3656        ["touch"; "/b"];
3657        ["inotify_files"]], ["a"; "b"])],
3658    "add an inotify watch",
3659    "\
3660 Watch C<path> for the events listed in C<mask>.
3661
3662 Note that if C<path> is a directory then events within that
3663 directory are watched, but this does I<not> happen recursively
3664 (in subdirectories).
3665
3666 Note for non-C or non-Linux callers: the inotify events are
3667 defined by the Linux kernel ABI and are listed in
3668 C</usr/include/sys/inotify.h>.");
3669
3670   ("inotify_rm_watch", (RErr, [Int(*XXX64*) "wd"]), 181, [Optional "inotify"],
3671    [],
3672    "remove an inotify watch",
3673    "\
3674 Remove a previously defined inotify watch.
3675 See C<guestfs_inotify_add_watch>.");
3676
3677   ("inotify_read", (RStructList ("events", "inotify_event"), []), 182, [Optional "inotify"],
3678    [],
3679    "return list of inotify events",
3680    "\
3681 Return the complete queue of events that have happened
3682 since the previous read call.
3683
3684 If no events have happened, this returns an empty list.
3685
3686 I<Note>: In order to make sure that all events have been
3687 read, you must call this function repeatedly until it
3688 returns an empty list.  The reason is that the call will
3689 read events up to the maximum appliance-to-host message
3690 size and leave remaining events in the queue.");
3691
3692   ("inotify_files", (RStringList "paths", []), 183, [Optional "inotify"],
3693    [],
3694    "return list of watched files that had events",
3695    "\
3696 This function is a helpful wrapper around C<guestfs_inotify_read>
3697 which just returns a list of pathnames of objects that were
3698 touched.  The returned pathnames are sorted and deduplicated.");
3699
3700   ("inotify_close", (RErr, []), 184, [Optional "inotify"],
3701    [],
3702    "close the inotify handle",
3703    "\
3704 This closes the inotify handle which was previously
3705 opened by inotify_init.  It removes all watches, throws
3706 away any pending events, and deallocates all resources.");
3707
3708   ("setcon", (RErr, [String "context"]), 185, [Optional "selinux"],
3709    [],
3710    "set SELinux security context",
3711    "\
3712 This sets the SELinux security context of the daemon
3713 to the string C<context>.
3714
3715 See the documentation about SELINUX in L<guestfs(3)>.");
3716
3717   ("getcon", (RString "context", []), 186, [Optional "selinux"],
3718    [],
3719    "get SELinux security context",
3720    "\
3721 This gets the SELinux security context of the daemon.
3722
3723 See the documentation about SELINUX in L<guestfs(3)>,
3724 and C<guestfs_setcon>");
3725
3726   ("mkfs_b", (RErr, [String "fstype"; Int "blocksize"; Device "device"]), 187, [],
3727    [InitEmpty, Always, TestOutput (
3728       [["part_disk"; "/dev/sda"; "mbr"];
3729        ["mkfs_b"; "ext2"; "4096"; "/dev/sda1"];
3730        ["mount_options"; ""; "/dev/sda1"; "/"];
3731        ["write"; "/new"; "new file contents"];
3732        ["cat"; "/new"]], "new file contents")],
3733    "make a filesystem with block size",
3734    "\
3735 This call is similar to C<guestfs_mkfs>, but it allows you to
3736 control the block size of the resulting filesystem.  Supported
3737 block sizes depend on the filesystem type, but typically they
3738 are C<1024>, C<2048> or C<4096> only.");
3739
3740   ("mke2journal", (RErr, [Int "blocksize"; Device "device"]), 188, [],
3741    [InitEmpty, Always, TestOutput (
3742       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3743        ["mke2journal"; "4096"; "/dev/sda1"];
3744        ["mke2fs_J"; "ext2"; "4096"; "/dev/sda2"; "/dev/sda1"];
3745        ["mount_options"; ""; "/dev/sda2"; "/"];
3746        ["write"; "/new"; "new file contents"];
3747        ["cat"; "/new"]], "new file contents")],
3748    "make ext2/3/4 external journal",
3749    "\
3750 This creates an ext2 external journal on C<device>.  It is equivalent
3751 to the command:
3752
3753  mke2fs -O journal_dev -b blocksize device");
3754
3755   ("mke2journal_L", (RErr, [Int "blocksize"; String "label"; Device "device"]), 189, [],
3756    [InitEmpty, Always, TestOutput (
3757       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3758        ["mke2journal_L"; "4096"; "JOURNAL"; "/dev/sda1"];
3759        ["mke2fs_JL"; "ext2"; "4096"; "/dev/sda2"; "JOURNAL"];
3760        ["mount_options"; ""; "/dev/sda2"; "/"];
3761        ["write"; "/new"; "new file contents"];
3762        ["cat"; "/new"]], "new file contents")],
3763    "make ext2/3/4 external journal with label",
3764    "\
3765 This creates an ext2 external journal on C<device> with label C<label>.");
3766
3767   ("mke2journal_U", (RErr, [Int "blocksize"; String "uuid"; Device "device"]), 190, [Optional "linuxfsuuid"],
3768    (let uuid = uuidgen () in
3769     [InitEmpty, Always, TestOutput (
3770        [["sfdiskM"; "/dev/sda"; ",100 ,"];
3771         ["mke2journal_U"; "4096"; uuid; "/dev/sda1"];
3772         ["mke2fs_JU"; "ext2"; "4096"; "/dev/sda2"; uuid];
3773         ["mount_options"; ""; "/dev/sda2"; "/"];
3774         ["write"; "/new"; "new file contents"];
3775         ["cat"; "/new"]], "new file contents")]),
3776    "make ext2/3/4 external journal with UUID",
3777    "\
3778 This creates an ext2 external journal on C<device> with UUID C<uuid>.");
3779
3780   ("mke2fs_J", (RErr, [String "fstype"; Int "blocksize"; Device "device"; Device "journal"]), 191, [],
3781    [],
3782    "make ext2/3/4 filesystem with external journal",
3783    "\
3784 This creates an ext2/3/4 filesystem on C<device> with
3785 an external journal on C<journal>.  It is equivalent
3786 to the command:
3787
3788  mke2fs -t fstype -b blocksize -J device=<journal> <device>
3789
3790 See also C<guestfs_mke2journal>.");
3791
3792   ("mke2fs_JL", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "label"]), 192, [],
3793    [],
3794    "make ext2/3/4 filesystem with external journal",
3795    "\
3796 This creates an ext2/3/4 filesystem on C<device> with
3797 an external journal on the journal labeled C<label>.
3798
3799 See also C<guestfs_mke2journal_L>.");
3800
3801   ("mke2fs_JU", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "uuid"]), 193, [Optional "linuxfsuuid"],
3802    [],
3803    "make ext2/3/4 filesystem with external journal",
3804    "\
3805 This creates an ext2/3/4 filesystem on C<device> with
3806 an external journal on the journal with UUID C<uuid>.
3807
3808 See also C<guestfs_mke2journal_U>.");
3809
3810   ("modprobe", (RErr, [String "modulename"]), 194, [Optional "linuxmodules"],
3811    [InitNone, Always, TestRun [["modprobe"; "fat"]]],
3812    "load a kernel module",
3813    "\
3814 This loads a kernel module in the appliance.
3815
3816 The kernel module must have been whitelisted when libguestfs
3817 was built (see C<appliance/kmod.whitelist.in> in the source).");
3818
3819   ("echo_daemon", (RString "output", [StringList "words"]), 195, [],
3820    [InitNone, Always, TestOutput (
3821       [["echo_daemon"; "This is a test"]], "This is a test"
3822     )],
3823    "echo arguments back to the client",
3824    "\
3825 This command concatenates the list of C<words> passed with single spaces
3826 between them and returns the resulting string.
3827
3828 You can use this command to test the connection through to the daemon.
3829
3830 See also C<guestfs_ping_daemon>.");
3831
3832   ("find0", (RErr, [Pathname "directory"; FileOut "files"]), 196, [],
3833    [], (* There is a regression test for this. *)
3834    "find all files and directories, returning NUL-separated list",
3835    "\
3836 This command lists out all files and directories, recursively,
3837 starting at C<directory>, placing the resulting list in the
3838 external file called C<files>.
3839
3840 This command works the same way as C<guestfs_find> with the
3841 following exceptions:
3842
3843 =over 4
3844
3845 =item *
3846
3847 The resulting list is written to an external file.
3848
3849 =item *
3850
3851 Items (filenames) in the result are separated
3852 by C<\\0> characters.  See L<find(1)> option I<-print0>.
3853
3854 =item *
3855
3856 This command is not limited in the number of names that it
3857 can return.
3858
3859 =item *
3860
3861 The result list is not sorted.
3862
3863 =back");
3864
3865   ("case_sensitive_path", (RString "rpath", [Pathname "path"]), 197, [],
3866    [InitISOFS, Always, TestOutput (
3867       [["case_sensitive_path"; "/DIRECTORY"]], "/directory");
3868     InitISOFS, Always, TestOutput (
3869       [["case_sensitive_path"; "/DIRECTORY/"]], "/directory");
3870     InitISOFS, Always, TestOutput (
3871       [["case_sensitive_path"; "/Known-1"]], "/known-1");
3872     InitISOFS, Always, TestLastFail (
3873       [["case_sensitive_path"; "/Known-1/"]]);
3874     InitBasicFS, Always, TestOutput (
3875       [["mkdir"; "/a"];
3876        ["mkdir"; "/a/bbb"];
3877        ["touch"; "/a/bbb/c"];
3878        ["case_sensitive_path"; "/A/bbB/C"]], "/a/bbb/c");
3879     InitBasicFS, Always, TestOutput (
3880       [["mkdir"; "/a"];
3881        ["mkdir"; "/a/bbb"];
3882        ["touch"; "/a/bbb/c"];
3883        ["case_sensitive_path"; "/A////bbB/C"]], "/a/bbb/c");
3884     InitBasicFS, Always, TestLastFail (
3885       [["mkdir"; "/a"];
3886        ["mkdir"; "/a/bbb"];
3887        ["touch"; "/a/bbb/c"];
3888        ["case_sensitive_path"; "/A/bbb/../bbb/C"]])],
3889    "return true path on case-insensitive filesystem",
3890    "\
3891 This can be used to resolve case insensitive paths on
3892 a filesystem which is case sensitive.  The use case is
3893 to resolve paths which you have read from Windows configuration
3894 files or the Windows Registry, to the true path.
3895
3896 The command handles a peculiarity of the Linux ntfs-3g
3897 filesystem driver (and probably others), which is that although
3898 the underlying filesystem is case-insensitive, the driver
3899 exports the filesystem to Linux as case-sensitive.
3900
3901 One consequence of this is that special directories such
3902 as C<c:\\windows> may appear as C</WINDOWS> or C</windows>
3903 (or other things) depending on the precise details of how
3904 they were created.  In Windows itself this would not be
3905 a problem.
3906
3907 Bug or feature?  You decide:
3908 L<http://www.tuxera.com/community/ntfs-3g-faq/#posixfilenames1>
3909
3910 This function resolves the true case of each element in the
3911 path and returns the case-sensitive path.
3912
3913 Thus C<guestfs_case_sensitive_path> (\"/Windows/System32\")
3914 might return C<\"/WINDOWS/system32\"> (the exact return value
3915 would depend on details of how the directories were originally
3916 created under Windows).
3917
3918 I<Note>:
3919 This function does not handle drive names, backslashes etc.
3920
3921 See also C<guestfs_realpath>.");
3922
3923   ("vfs_type", (RString "fstype", [Device "device"]), 198, [],
3924    [InitBasicFS, Always, TestOutput (
3925       [["vfs_type"; "/dev/sda1"]], "ext2")],
3926    "get the Linux VFS type corresponding to a mounted device",
3927    "\
3928 This command gets the filesystem type corresponding to
3929 the filesystem on C<device>.
3930
3931 For most filesystems, the result is the name of the Linux
3932 VFS module which would be used to mount this filesystem
3933 if you mounted it without specifying the filesystem type.
3934 For example a string such as C<ext3> or C<ntfs>.");
3935
3936   ("truncate", (RErr, [Pathname "path"]), 199, [],
3937    [InitBasicFS, Always, TestOutputStruct (
3938       [["write"; "/test"; "some stuff so size is not zero"];
3939        ["truncate"; "/test"];
3940        ["stat"; "/test"]], [CompareWithInt ("size", 0)])],
3941    "truncate a file to zero size",
3942    "\
3943 This command truncates C<path> to a zero-length file.  The
3944 file must exist already.");
3945
3946   ("truncate_size", (RErr, [Pathname "path"; Int64 "size"]), 200, [],
3947    [InitBasicFS, Always, TestOutputStruct (
3948       [["touch"; "/test"];
3949        ["truncate_size"; "/test"; "1000"];
3950        ["stat"; "/test"]], [CompareWithInt ("size", 1000)])],
3951    "truncate a file to a particular size",
3952    "\
3953 This command truncates C<path> to size C<size> bytes.  The file
3954 must exist already.
3955
3956 If the current file size is less than C<size> then
3957 the file is extended to the required size with zero bytes.
3958 This creates a sparse file (ie. disk blocks are not allocated
3959 for the file until you write to it).  To create a non-sparse
3960 file of zeroes, use C<guestfs_fallocate64> instead.");
3961
3962   ("utimens", (RErr, [Pathname "path"; Int64 "atsecs"; Int64 "atnsecs"; Int64 "mtsecs"; Int64 "mtnsecs"]), 201, [],
3963    [InitBasicFS, Always, TestOutputStruct (
3964       [["touch"; "/test"];
3965        ["utimens"; "/test"; "12345"; "67890"; "9876"; "5432"];
3966        ["stat"; "/test"]], [CompareWithInt ("mtime", 9876)])],
3967    "set timestamp of a file with nanosecond precision",
3968    "\
3969 This command sets the timestamps of a file with nanosecond
3970 precision.
3971
3972 C<atsecs, atnsecs> are the last access time (atime) in secs and
3973 nanoseconds from the epoch.
3974
3975 C<mtsecs, mtnsecs> are the last modification time (mtime) in
3976 secs and nanoseconds from the epoch.
3977
3978 If the C<*nsecs> field contains the special value C<-1> then
3979 the corresponding timestamp is set to the current time.  (The
3980 C<*secs> field is ignored in this case).
3981
3982 If the C<*nsecs> field contains the special value C<-2> then
3983 the corresponding timestamp is left unchanged.  (The
3984 C<*secs> field is ignored in this case).");
3985
3986   ("mkdir_mode", (RErr, [Pathname "path"; Int "mode"]), 202, [],
3987    [InitBasicFS, Always, TestOutputStruct (
3988       [["mkdir_mode"; "/test"; "0o111"];
3989        ["stat"; "/test"]], [CompareWithInt ("mode", 0o40111)])],
3990    "create a directory with a particular mode",
3991    "\
3992 This command creates a directory, setting the initial permissions
3993 of the directory to C<mode>.
3994
3995 For common Linux filesystems, the actual mode which is set will
3996 be C<mode & ~umask & 01777>.  Non-native-Linux filesystems may
3997 interpret the mode in other ways.
3998
3999 See also C<guestfs_mkdir>, C<guestfs_umask>");
4000
4001   ("lchown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 203, [],
4002    [], (* XXX *)
4003    "change file owner and group",
4004    "\
4005 Change the file owner to C<owner> and group to C<group>.
4006 This is like C<guestfs_chown> but if C<path> is a symlink then
4007 the link itself is changed, not the target.
4008
4009 Only numeric uid and gid are supported.  If you want to use
4010 names, you will need to locate and parse the password file
4011 yourself (Augeas support makes this relatively easy).");
4012
4013   ("lstatlist", (RStructList ("statbufs", "stat"), [Pathname "path"; StringList "names"]), 204, [],
4014    [], (* XXX *)
4015    "lstat on multiple files",
4016    "\
4017 This call allows you to perform the C<guestfs_lstat> operation
4018 on multiple files, where all files are in the directory C<path>.
4019 C<names> is the list of files from this directory.
4020
4021 On return you get a list of stat structs, with a one-to-one
4022 correspondence to the C<names> list.  If any name did not exist
4023 or could not be lstat'd, then the C<ino> field of that structure
4024 is set to C<-1>.
4025
4026 This call is intended for programs that want to efficiently
4027 list a directory contents without making many round-trips.
4028 See also C<guestfs_lxattrlist> for a similarly efficient call
4029 for getting extended attributes.  Very long directory listings
4030 might cause the protocol message size to be exceeded, causing
4031 this call to fail.  The caller must split up such requests
4032 into smaller groups of names.");
4033
4034   ("lxattrlist", (RStructList ("xattrs", "xattr"), [Pathname "path"; StringList "names"]), 205, [Optional "linuxxattrs"],
4035    [], (* XXX *)
4036    "lgetxattr on multiple files",
4037    "\
4038 This call allows you to get the extended attributes
4039 of multiple files, where all files are in the directory C<path>.
4040 C<names> is the list of files from this directory.
4041
4042 On return you get a flat list of xattr structs which must be
4043 interpreted sequentially.  The first xattr struct always has a zero-length
4044 C<attrname>.  C<attrval> in this struct is zero-length
4045 to indicate there was an error doing C<lgetxattr> for this
4046 file, I<or> is a C string which is a decimal number
4047 (the number of following attributes for this file, which could
4048 be C<\"0\">).  Then after the first xattr struct are the
4049 zero or more attributes for the first named file.
4050 This repeats for the second and subsequent files.
4051
4052 This call is intended for programs that want to efficiently
4053 list a directory contents without making many round-trips.
4054 See also C<guestfs_lstatlist> for a similarly efficient call
4055 for getting standard stats.  Very long directory listings
4056 might cause the protocol message size to be exceeded, causing
4057 this call to fail.  The caller must split up such requests
4058 into smaller groups of names.");
4059
4060   ("readlinklist", (RStringList "links", [Pathname "path"; StringList "names"]), 206, [],
4061    [], (* XXX *)
4062    "readlink on multiple files",
4063    "\
4064 This call allows you to do a C<readlink> operation
4065 on multiple files, where all files are in the directory C<path>.
4066 C<names> is the list of files from this directory.
4067
4068 On return you get a list of strings, with a one-to-one
4069 correspondence to the C<names> list.  Each string is the
4070 value of the symbolic link.
4071
4072 If the C<readlink(2)> operation fails on any name, then
4073 the corresponding result string is the empty string C<\"\">.
4074 However the whole operation is completed even if there
4075 were C<readlink(2)> errors, and so you can call this
4076 function with names where you don't know if they are
4077 symbolic links already (albeit slightly less efficient).
4078
4079 This call is intended for programs that want to efficiently
4080 list a directory contents without making many round-trips.
4081 Very long directory listings might cause the protocol
4082 message size to be exceeded, causing
4083 this call to fail.  The caller must split up such requests
4084 into smaller groups of names.");
4085
4086   ("pread", (RBufferOut "content", [Pathname "path"; Int "count"; Int64 "offset"]), 207, [ProtocolLimitWarning],
4087    [InitISOFS, Always, TestOutputBuffer (
4088       [["pread"; "/known-4"; "1"; "3"]], "\n");
4089     InitISOFS, Always, TestOutputBuffer (
4090       [["pread"; "/empty"; "0"; "100"]], "")],
4091    "read part of a file",
4092    "\
4093 This command lets you read part of a file.  It reads C<count>
4094 bytes of the file, starting at C<offset>, from file C<path>.
4095
4096 This may read fewer bytes than requested.  For further details
4097 see the L<pread(2)> system call.
4098
4099 See also C<guestfs_pwrite>.");
4100
4101   ("part_init", (RErr, [Device "device"; String "parttype"]), 208, [],
4102    [InitEmpty, Always, TestRun (
4103       [["part_init"; "/dev/sda"; "gpt"]])],
4104    "create an empty partition table",
4105    "\
4106 This creates an empty partition table on C<device> of one of the
4107 partition types listed below.  Usually C<parttype> should be
4108 either C<msdos> or C<gpt> (for large disks).
4109
4110 Initially there are no partitions.  Following this, you should
4111 call C<guestfs_part_add> for each partition required.
4112
4113 Possible values for C<parttype> are:
4114
4115 =over 4
4116
4117 =item B<efi> | B<gpt>
4118
4119 Intel EFI / GPT partition table.
4120
4121 This is recommended for >= 2 TB partitions that will be accessed
4122 from Linux and Intel-based Mac OS X.  It also has limited backwards
4123 compatibility with the C<mbr> format.
4124
4125 =item B<mbr> | B<msdos>
4126
4127 The standard PC \"Master Boot Record\" (MBR) format used
4128 by MS-DOS and Windows.  This partition type will B<only> work
4129 for device sizes up to 2 TB.  For large disks we recommend
4130 using C<gpt>.
4131
4132 =back
4133
4134 Other partition table types that may work but are not
4135 supported include:
4136
4137 =over 4
4138
4139 =item B<aix>
4140
4141 AIX disk labels.
4142
4143 =item B<amiga> | B<rdb>
4144
4145 Amiga \"Rigid Disk Block\" format.
4146
4147 =item B<bsd>
4148
4149 BSD disk labels.
4150
4151 =item B<dasd>
4152
4153 DASD, used on IBM mainframes.
4154
4155 =item B<dvh>
4156
4157 MIPS/SGI volumes.
4158
4159 =item B<mac>
4160
4161 Old Mac partition format.  Modern Macs use C<gpt>.
4162
4163 =item B<pc98>
4164
4165 NEC PC-98 format, common in Japan apparently.
4166
4167 =item B<sun>
4168
4169 Sun disk labels.
4170
4171 =back");
4172
4173   ("part_add", (RErr, [Device "device"; String "prlogex"; Int64 "startsect"; Int64 "endsect"]), 209, [],
4174    [InitEmpty, Always, TestRun (
4175       [["part_init"; "/dev/sda"; "mbr"];
4176        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"]]);
4177     InitEmpty, Always, TestRun (
4178       [["part_init"; "/dev/sda"; "gpt"];
4179        ["part_add"; "/dev/sda"; "primary"; "34"; "127"];
4180        ["part_add"; "/dev/sda"; "primary"; "128"; "-34"]]);
4181     InitEmpty, Always, TestRun (
4182       [["part_init"; "/dev/sda"; "mbr"];
4183        ["part_add"; "/dev/sda"; "primary"; "32"; "127"];
4184        ["part_add"; "/dev/sda"; "primary"; "128"; "255"];
4185        ["part_add"; "/dev/sda"; "primary"; "256"; "511"];
4186        ["part_add"; "/dev/sda"; "primary"; "512"; "-1"]])],
4187    "add a partition to the device",
4188    "\
4189 This command adds a partition to C<device>.  If there is no partition
4190 table on the device, call C<guestfs_part_init> first.
4191
4192 The C<prlogex> parameter is the type of partition.  Normally you
4193 should pass C<p> or C<primary> here, but MBR partition tables also
4194 support C<l> (or C<logical>) and C<e> (or C<extended>) partition
4195 types.
4196
4197 C<startsect> and C<endsect> are the start and end of the partition
4198 in I<sectors>.  C<endsect> may be negative, which means it counts
4199 backwards from the end of the disk (C<-1> is the last sector).
4200
4201 Creating a partition which covers the whole disk is not so easy.
4202 Use C<guestfs_part_disk> to do that.");
4203
4204   ("part_disk", (RErr, [Device "device"; String "parttype"]), 210, [DangerWillRobinson],
4205    [InitEmpty, Always, TestRun (
4206       [["part_disk"; "/dev/sda"; "mbr"]]);
4207     InitEmpty, Always, TestRun (
4208       [["part_disk"; "/dev/sda"; "gpt"]])],
4209    "partition whole disk with a single primary partition",
4210    "\
4211 This command is simply a combination of C<guestfs_part_init>
4212 followed by C<guestfs_part_add> to create a single primary partition
4213 covering the whole disk.
4214
4215 C<parttype> is the partition table type, usually C<mbr> or C<gpt>,
4216 but other possible values are described in C<guestfs_part_init>.");
4217
4218   ("part_set_bootable", (RErr, [Device "device"; Int "partnum"; Bool "bootable"]), 211, [],
4219    [InitEmpty, Always, TestRun (
4220       [["part_disk"; "/dev/sda"; "mbr"];
4221        ["part_set_bootable"; "/dev/sda"; "1"; "true"]])],
4222    "make a partition bootable",
4223    "\
4224 This sets the bootable flag on partition numbered C<partnum> on
4225 device C<device>.  Note that partitions are numbered from 1.
4226
4227 The bootable flag is used by some operating systems (notably
4228 Windows) to determine which partition to boot from.  It is by
4229 no means universally recognized.");
4230
4231   ("part_set_name", (RErr, [Device "device"; Int "partnum"; String "name"]), 212, [],
4232    [InitEmpty, Always, TestRun (
4233       [["part_disk"; "/dev/sda"; "gpt"];
4234        ["part_set_name"; "/dev/sda"; "1"; "thepartname"]])],
4235    "set partition name",
4236    "\
4237 This sets the partition name on partition numbered C<partnum> on
4238 device C<device>.  Note that partitions are numbered from 1.
4239
4240 The partition name can only be set on certain types of partition
4241 table.  This works on C<gpt> but not on C<mbr> partitions.");
4242
4243   ("part_list", (RStructList ("partitions", "partition"), [Device "device"]), 213, [],
4244    [], (* XXX Add a regression test for this. *)
4245    "list partitions on a device",
4246    "\
4247 This command parses the partition table on C<device> and
4248 returns the list of partitions found.
4249
4250 The fields in the returned structure are:
4251
4252 =over 4
4253
4254 =item B<part_num>
4255
4256 Partition number, counting from 1.
4257
4258 =item B<part_start>
4259
4260 Start of the partition I<in bytes>.  To get sectors you have to
4261 divide by the device's sector size, see C<guestfs_blockdev_getss>.
4262
4263 =item B<part_end>
4264
4265 End of the partition in bytes.
4266
4267 =item B<part_size>
4268
4269 Size of the partition in bytes.
4270
4271 =back");
4272
4273   ("part_get_parttype", (RString "parttype", [Device "device"]), 214, [],
4274    [InitEmpty, Always, TestOutput (
4275       [["part_disk"; "/dev/sda"; "gpt"];
4276        ["part_get_parttype"; "/dev/sda"]], "gpt")],
4277    "get the partition table type",
4278    "\
4279 This command examines the partition table on C<device> and
4280 returns the partition table type (format) being used.
4281
4282 Common return values include: C<msdos> (a DOS/Windows style MBR
4283 partition table), C<gpt> (a GPT/EFI-style partition table).  Other
4284 values are possible, although unusual.  See C<guestfs_part_init>
4285 for a full list.");
4286
4287   ("fill", (RErr, [Int "c"; Int "len"; Pathname "path"]), 215, [],
4288    [InitBasicFS, Always, TestOutputBuffer (
4289       [["fill"; "0x63"; "10"; "/test"];
4290        ["read_file"; "/test"]], "cccccccccc")],
4291    "fill a file with octets",
4292    "\
4293 This command creates a new file called C<path>.  The initial
4294 content of the file is C<len> octets of C<c>, where C<c>
4295 must be a number in the range C<[0..255]>.
4296
4297 To fill a file with zero bytes (sparsely), it is
4298 much more efficient to use C<guestfs_truncate_size>.
4299 To create a file with a pattern of repeating bytes
4300 use C<guestfs_fill_pattern>.");
4301
4302   ("available", (RErr, [StringList "groups"]), 216, [],
4303    [InitNone, Always, TestRun [["available"; ""]]],
4304    "test availability of some parts of the API",
4305    "\
4306 This command is used to check the availability of some
4307 groups of functionality in the appliance, which not all builds of
4308 the libguestfs appliance will be able to provide.
4309
4310 The libguestfs groups, and the functions that those
4311 groups correspond to, are listed in L<guestfs(3)/AVAILABILITY>.
4312 You can also fetch this list at runtime by calling
4313 C<guestfs_available_all_groups>.
4314
4315 The argument C<groups> is a list of group names, eg:
4316 C<[\"inotify\", \"augeas\"]> would check for the availability of
4317 the Linux inotify functions and Augeas (configuration file
4318 editing) functions.
4319
4320 The command returns no error if I<all> requested groups are available.
4321
4322 It fails with an error if one or more of the requested
4323 groups is unavailable in the appliance.
4324
4325 If an unknown group name is included in the
4326 list of groups then an error is always returned.
4327
4328 I<Notes:>
4329
4330 =over 4
4331
4332 =item *
4333
4334 You must call C<guestfs_launch> before calling this function.
4335
4336 The reason is because we don't know what groups are
4337 supported by the appliance/daemon until it is running and can
4338 be queried.
4339
4340 =item *
4341
4342 If a group of functions is available, this does not necessarily
4343 mean that they will work.  You still have to check for errors
4344 when calling individual API functions even if they are
4345 available.
4346
4347 =item *
4348
4349 It is usually the job of distro packagers to build
4350 complete functionality into the libguestfs appliance.
4351 Upstream libguestfs, if built from source with all
4352 requirements satisfied, will support everything.
4353
4354 =item *
4355
4356 This call was added in version C<1.0.80>.  In previous
4357 versions of libguestfs all you could do would be to speculatively
4358 execute a command to find out if the daemon implemented it.
4359 See also C<guestfs_version>.
4360
4361 =back");
4362
4363   ("dd", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"]), 217, [],
4364    [InitBasicFS, Always, TestOutputBuffer (
4365       [["write"; "/src"; "hello, world"];
4366        ["dd"; "/src"; "/dest"];
4367        ["read_file"; "/dest"]], "hello, world")],
4368    "copy from source to destination using dd",
4369    "\
4370 This command copies from one source device or file C<src>
4371 to another destination device or file C<dest>.  Normally you
4372 would use this to copy to or from a device or partition, for
4373 example to duplicate a filesystem.
4374
4375 If the destination is a device, it must be as large or larger
4376 than the source file or device, otherwise the copy will fail.
4377 This command cannot do partial copies (see C<guestfs_copy_size>).");
4378
4379   ("filesize", (RInt64 "size", [Pathname "file"]), 218, [],
4380    [InitBasicFS, Always, TestOutputInt (
4381       [["write"; "/file"; "hello, world"];
4382        ["filesize"; "/file"]], 12)],
4383    "return the size of the file in bytes",
4384    "\
4385 This command returns the size of C<file> in bytes.
4386
4387 To get other stats about a file, use C<guestfs_stat>, C<guestfs_lstat>,
4388 C<guestfs_is_dir>, C<guestfs_is_file> etc.
4389 To get the size of block devices, use C<guestfs_blockdev_getsize64>.");
4390
4391   ("lvrename", (RErr, [String "logvol"; String "newlogvol"]), 219, [],
4392    [InitBasicFSonLVM, Always, TestOutputList (
4393       [["lvrename"; "/dev/VG/LV"; "/dev/VG/LV2"];
4394        ["lvs"]], ["/dev/VG/LV2"])],
4395    "rename an LVM logical volume",
4396    "\
4397 Rename a logical volume C<logvol> with the new name C<newlogvol>.");
4398
4399   ("vgrename", (RErr, [String "volgroup"; String "newvolgroup"]), 220, [],
4400    [InitBasicFSonLVM, Always, TestOutputList (
4401       [["umount"; "/"];
4402        ["vg_activate"; "false"; "VG"];
4403        ["vgrename"; "VG"; "VG2"];
4404        ["vg_activate"; "true"; "VG2"];
4405        ["mount_options"; ""; "/dev/VG2/LV"; "/"];
4406        ["vgs"]], ["VG2"])],
4407    "rename an LVM volume group",
4408    "\
4409 Rename a volume group C<volgroup> with the new name C<newvolgroup>.");
4410
4411   ("initrd_cat", (RBufferOut "content", [Pathname "initrdpath"; String "filename"]), 221, [ProtocolLimitWarning],
4412    [InitISOFS, Always, TestOutputBuffer (
4413       [["initrd_cat"; "/initrd"; "known-4"]], "abc\ndef\nghi")],
4414    "list the contents of a single file in an initrd",
4415    "\
4416 This command unpacks the file C<filename> from the initrd file
4417 called C<initrdpath>.  The filename must be given I<without> the
4418 initial C</> character.
4419
4420 For example, in guestfish you could use the following command
4421 to examine the boot script (usually called C</init>)
4422 contained in a Linux initrd or initramfs image:
4423
4424  initrd-cat /boot/initrd-<version>.img init
4425
4426 See also C<guestfs_initrd_list>.");
4427
4428   ("pvuuid", (RString "uuid", [Device "device"]), 222, [],
4429    [],
4430    "get the UUID of a physical volume",
4431    "\
4432 This command returns the UUID of the LVM PV C<device>.");
4433
4434   ("vguuid", (RString "uuid", [String "vgname"]), 223, [],
4435    [],
4436    "get the UUID of a volume group",
4437    "\
4438 This command returns the UUID of the LVM VG named C<vgname>.");
4439
4440   ("lvuuid", (RString "uuid", [Device "device"]), 224, [],
4441    [],
4442    "get the UUID of a logical volume",
4443    "\
4444 This command returns the UUID of the LVM LV C<device>.");
4445
4446   ("vgpvuuids", (RStringList "uuids", [String "vgname"]), 225, [],
4447    [],
4448    "get the PV UUIDs containing the volume group",
4449    "\
4450 Given a VG called C<vgname>, this returns the UUIDs of all
4451 the physical volumes that this volume group resides on.
4452
4453 You can use this along with C<guestfs_pvs> and C<guestfs_pvuuid>
4454 calls to associate physical volumes and volume groups.
4455
4456 See also C<guestfs_vglvuuids>.");
4457
4458   ("vglvuuids", (RStringList "uuids", [String "vgname"]), 226, [],
4459    [],
4460    "get the LV UUIDs of all LVs in the volume group",
4461    "\
4462 Given a VG called C<vgname>, this returns the UUIDs of all
4463 the logical volumes created in this volume group.
4464
4465 You can use this along with C<guestfs_lvs> and C<guestfs_lvuuid>
4466 calls to associate logical volumes and volume groups.
4467
4468 See also C<guestfs_vgpvuuids>.");
4469
4470   ("copy_size", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"; Int64 "size"]), 227, [],
4471    [InitBasicFS, Always, TestOutputBuffer (
4472       [["write"; "/src"; "hello, world"];
4473        ["copy_size"; "/src"; "/dest"; "5"];
4474        ["read_file"; "/dest"]], "hello")],
4475    "copy size bytes from source to destination using dd",
4476    "\
4477 This command copies exactly C<size> bytes from one source device
4478 or file C<src> to another destination device or file C<dest>.
4479
4480 Note this will fail if the source is too short or if the destination
4481 is not large enough.");
4482
4483   ("zero_device", (RErr, [Device "device"]), 228, [DangerWillRobinson],
4484    [InitBasicFSonLVM, Always, TestRun (
4485       [["zero_device"; "/dev/VG/LV"]])],
4486    "write zeroes to an entire device",
4487    "\
4488 This command writes zeroes over the entire C<device>.  Compare
4489 with C<guestfs_zero> which just zeroes the first few blocks of
4490 a device.");
4491
4492   ("txz_in", (RErr, [FileIn "tarball"; Pathname "directory"]), 229, [Optional "xz"],
4493    [InitBasicFS, Always, TestOutput (
4494       [["txz_in"; "../images/helloworld.tar.xz"; "/"];
4495        ["cat"; "/hello"]], "hello\n")],
4496    "unpack compressed tarball to directory",
4497    "\
4498 This command uploads and unpacks local file C<tarball> (an
4499 I<xz compressed> tar file) into C<directory>.");
4500
4501   ("txz_out", (RErr, [Pathname "directory"; FileOut "tarball"]), 230, [Optional "xz"],
4502    [],
4503    "pack directory into compressed tarball",
4504    "\
4505 This command packs the contents of C<directory> and downloads
4506 it to local file C<tarball> (as an xz compressed tar archive).");
4507
4508   ("ntfsresize", (RErr, [Device "device"]), 231, [Optional "ntfsprogs"],
4509    [],
4510    "resize an NTFS filesystem",
4511    "\
4512 This command resizes an NTFS filesystem, expanding or
4513 shrinking it to the size of the underlying device.
4514 See also L<ntfsresize(8)>.");
4515
4516   ("vgscan", (RErr, []), 232, [],
4517    [InitEmpty, Always, TestRun (
4518       [["vgscan"]])],
4519    "rescan for LVM physical volumes, volume groups and logical volumes",
4520    "\
4521 This rescans all block devices and rebuilds the list of LVM
4522 physical volumes, volume groups and logical volumes.");
4523
4524   ("part_del", (RErr, [Device "device"; Int "partnum"]), 233, [],
4525    [InitEmpty, Always, TestRun (
4526       [["part_init"; "/dev/sda"; "mbr"];
4527        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
4528        ["part_del"; "/dev/sda"; "1"]])],
4529    "delete a partition",
4530    "\
4531 This command deletes the partition numbered C<partnum> on C<device>.
4532
4533 Note that in the case of MBR partitioning, deleting an
4534 extended partition also deletes any logical partitions
4535 it contains.");
4536
4537   ("part_get_bootable", (RBool "bootable", [Device "device"; Int "partnum"]), 234, [],
4538    [InitEmpty, Always, TestOutputTrue (
4539       [["part_init"; "/dev/sda"; "mbr"];
4540        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
4541        ["part_set_bootable"; "/dev/sda"; "1"; "true"];
4542        ["part_get_bootable"; "/dev/sda"; "1"]])],
4543    "return true if a partition is bootable",
4544    "\
4545 This command returns true if the partition C<partnum> on
4546 C<device> has the bootable flag set.
4547
4548 See also C<guestfs_part_set_bootable>.");
4549
4550   ("part_get_mbr_id", (RInt "idbyte", [Device "device"; Int "partnum"]), 235, [FishOutput FishOutputHexadecimal],
4551    [InitEmpty, Always, TestOutputInt (
4552       [["part_init"; "/dev/sda"; "mbr"];
4553        ["part_add"; "/dev/sda"; "primary"; "1"; "-1"];
4554        ["part_set_mbr_id"; "/dev/sda"; "1"; "0x7f"];
4555        ["part_get_mbr_id"; "/dev/sda"; "1"]], 0x7f)],
4556    "get the MBR type byte (ID byte) from a partition",
4557    "\
4558 Returns the MBR type byte (also known as the ID byte) from
4559 the numbered partition C<partnum>.
4560
4561 Note that only MBR (old DOS-style) partitions have type bytes.
4562 You will get undefined results for other partition table
4563 types (see C<guestfs_part_get_parttype>).");
4564
4565   ("part_set_mbr_id", (RErr, [Device "device"; Int "partnum"; Int "idbyte"]), 236, [],
4566    [], (* tested by part_get_mbr_id *)
4567    "set the MBR type byte (ID byte) of a partition",
4568    "\
4569 Sets the MBR type byte (also known as the ID byte) of
4570 the numbered partition C<partnum> to C<idbyte>.  Note
4571 that the type bytes quoted in most documentation are
4572 in fact hexadecimal numbers, but usually documented
4573 without any leading \"0x\" which might be confusing.
4574
4575 Note that only MBR (old DOS-style) partitions have type bytes.
4576 You will get undefined results for other partition table
4577 types (see C<guestfs_part_get_parttype>).");
4578
4579   ("checksum_device", (RString "checksum", [String "csumtype"; Device "device"]), 237, [],
4580    [InitISOFS, Always, TestOutput (
4581       [["checksum_device"; "md5"; "/dev/sdd"]],
4582       (Digest.to_hex (Digest.file "images/test.iso")))],
4583    "compute MD5, SHAx or CRC checksum of the contents of a device",
4584    "\
4585 This call computes the MD5, SHAx or CRC checksum of the
4586 contents of the device named C<device>.  For the types of
4587 checksums supported see the C<guestfs_checksum> command.");
4588
4589   ("lvresize_free", (RErr, [Device "lv"; Int "percent"]), 238, [Optional "lvm2"],
4590    [InitNone, Always, TestRun (
4591       [["part_disk"; "/dev/sda"; "mbr"];
4592        ["pvcreate"; "/dev/sda1"];
4593        ["vgcreate"; "VG"; "/dev/sda1"];
4594        ["lvcreate"; "LV"; "VG"; "10"];
4595        ["lvresize_free"; "/dev/VG/LV"; "100"]])],
4596    "expand an LV to fill free space",
4597    "\
4598 This expands an existing logical volume C<lv> so that it fills
4599 C<pc>% of the remaining free space in the volume group.  Commonly
4600 you would call this with pc = 100 which expands the logical volume
4601 as much as possible, using all remaining free space in the volume
4602 group.");
4603
4604   ("aug_clear", (RErr, [String "augpath"]), 239, [Optional "augeas"],
4605    [], (* XXX Augeas code needs tests. *)
4606    "clear Augeas path",
4607    "\
4608 Set the value associated with C<path> to C<NULL>.  This
4609 is the same as the L<augtool(1)> C<clear> command.");
4610
4611   ("get_umask", (RInt "mask", []), 240, [FishOutput FishOutputOctal],
4612    [InitEmpty, Always, TestOutputInt (
4613       [["get_umask"]], 0o22)],
4614    "get the current umask",
4615    "\
4616 Return the current umask.  By default the umask is C<022>
4617 unless it has been set by calling C<guestfs_umask>.");
4618
4619   ("debug_upload", (RErr, [FileIn "filename"; String "tmpname"; Int "mode"]), 241, [],
4620    [],
4621    "upload a file to the appliance (internal use only)",
4622    "\
4623 The C<guestfs_debug_upload> command uploads a file to
4624 the libguestfs appliance.
4625
4626 There is no comprehensive help for this command.  You have
4627 to look at the file C<daemon/debug.c> in the libguestfs source
4628 to find out what it is for.");
4629
4630   ("base64_in", (RErr, [FileIn "base64file"; Pathname "filename"]), 242, [],
4631    [InitBasicFS, Always, TestOutput (
4632       [["base64_in"; "../images/hello.b64"; "/hello"];
4633        ["cat"; "/hello"]], "hello\n")],
4634    "upload base64-encoded data to file",
4635    "\
4636 This command uploads base64-encoded data from C<base64file>
4637 to C<filename>.");
4638
4639   ("base64_out", (RErr, [Pathname "filename"; FileOut "base64file"]), 243, [],
4640    [],
4641    "download file and encode as base64",
4642    "\
4643 This command downloads the contents of C<filename>, writing
4644 it out to local file C<base64file> encoded as base64.");
4645
4646   ("checksums_out", (RErr, [String "csumtype"; Pathname "directory"; FileOut "sumsfile"]), 244, [],
4647    [],
4648    "compute MD5, SHAx or CRC checksum of files in a directory",
4649    "\
4650 This command computes the checksums of all regular files in
4651 C<directory> and then emits a list of those checksums to
4652 the local output file C<sumsfile>.
4653
4654 This can be used for verifying the integrity of a virtual
4655 machine.  However to be properly secure you should pay
4656 attention to the output of the checksum command (it uses
4657 the ones from GNU coreutils).  In particular when the
4658 filename is not printable, coreutils uses a special
4659 backslash syntax.  For more information, see the GNU
4660 coreutils info file.");
4661
4662   ("fill_pattern", (RErr, [String "pattern"; Int "len"; Pathname "path"]), 245, [],
4663    [InitBasicFS, Always, TestOutputBuffer (
4664       [["fill_pattern"; "abcdefghijklmnopqrstuvwxyz"; "28"; "/test"];
4665        ["read_file"; "/test"]], "abcdefghijklmnopqrstuvwxyzab")],
4666    "fill a file with a repeating pattern of bytes",
4667    "\
4668 This function is like C<guestfs_fill> except that it creates
4669 a new file of length C<len> containing the repeating pattern
4670 of bytes in C<pattern>.  The pattern is truncated if necessary
4671 to ensure the length of the file is exactly C<len> bytes.");
4672
4673   ("write", (RErr, [Pathname "path"; BufferIn "content"]), 246, [ProtocolLimitWarning],
4674    [InitBasicFS, Always, TestOutput (
4675       [["write"; "/new"; "new file contents"];
4676        ["cat"; "/new"]], "new file contents");
4677     InitBasicFS, Always, TestOutput (
4678       [["write"; "/new"; "\nnew file contents\n"];
4679        ["cat"; "/new"]], "\nnew file contents\n");
4680     InitBasicFS, Always, TestOutput (
4681       [["write"; "/new"; "\n\n"];
4682        ["cat"; "/new"]], "\n\n");
4683     InitBasicFS, Always, TestOutput (
4684       [["write"; "/new"; ""];
4685        ["cat"; "/new"]], "");
4686     InitBasicFS, Always, TestOutput (
4687       [["write"; "/new"; "\n\n\n"];
4688        ["cat"; "/new"]], "\n\n\n");
4689     InitBasicFS, Always, TestOutput (
4690       [["write"; "/new"; "\n"];
4691        ["cat"; "/new"]], "\n")],
4692    "create a new file",
4693    "\
4694 This call creates a file called C<path>.  The content of the
4695 file is the string C<content> (which can contain any 8 bit data).");
4696
4697   ("pwrite", (RInt "nbytes", [Pathname "path"; BufferIn "content"; Int64 "offset"]), 247, [ProtocolLimitWarning],
4698    [InitBasicFS, Always, TestOutput (
4699       [["write"; "/new"; "new file contents"];
4700        ["pwrite"; "/new"; "data"; "4"];
4701        ["cat"; "/new"]], "new data contents");
4702     InitBasicFS, Always, TestOutput (
4703       [["write"; "/new"; "new file contents"];
4704        ["pwrite"; "/new"; "is extended"; "9"];
4705        ["cat"; "/new"]], "new file is extended");
4706     InitBasicFS, Always, TestOutput (
4707       [["write"; "/new"; "new file contents"];
4708        ["pwrite"; "/new"; ""; "4"];
4709        ["cat"; "/new"]], "new file contents")],
4710    "write to part of a file",
4711    "\
4712 This command writes to part of a file.  It writes the data
4713 buffer C<content> to the file C<path> starting at offset C<offset>.
4714
4715 This command implements the L<pwrite(2)> system call, and like
4716 that system call it may not write the full data requested.  The
4717 return value is the number of bytes that were actually written
4718 to the file.  This could even be 0, although short writes are
4719 unlikely for regular files in ordinary circumstances.
4720
4721 See also C<guestfs_pread>.");
4722
4723   ("resize2fs_size", (RErr, [Device "device"; Int64 "size"]), 248, [],
4724    [],
4725    "resize an ext2, ext3 or ext4 filesystem (with size)",
4726    "\
4727 This command is the same as C<guestfs_resize2fs> except that it
4728 allows you to specify the new size (in bytes) explicitly.");
4729
4730   ("pvresize_size", (RErr, [Device "device"; Int64 "size"]), 249, [Optional "lvm2"],
4731    [],
4732    "resize an LVM physical volume (with size)",
4733    "\
4734 This command is the same as C<guestfs_pvresize> except that it
4735 allows you to specify the new size (in bytes) explicitly.");
4736
4737   ("ntfsresize_size", (RErr, [Device "device"; Int64 "size"]), 250, [Optional "ntfsprogs"],
4738    [],
4739    "resize an NTFS filesystem (with size)",
4740    "\
4741 This command is the same as C<guestfs_ntfsresize> except that it
4742 allows you to specify the new size (in bytes) explicitly.");
4743
4744   ("available_all_groups", (RStringList "groups", []), 251, [],
4745    [InitNone, Always, TestRun [["available_all_groups"]]],
4746    "return a list of all optional groups",
4747    "\
4748 This command returns a list of all optional groups that this
4749 daemon knows about.  Note this returns both supported and unsupported
4750 groups.  To find out which ones the daemon can actually support
4751 you have to call C<guestfs_available> on each member of the
4752 returned list.
4753
4754 See also C<guestfs_available> and L<guestfs(3)/AVAILABILITY>.");
4755
4756   ("fallocate64", (RErr, [Pathname "path"; Int64 "len"]), 252, [],
4757    [InitBasicFS, Always, TestOutputStruct (
4758       [["fallocate64"; "/a"; "1000000"];
4759        ["stat"; "/a"]], [CompareWithInt ("size", 1_000_000)])],
4760    "preallocate a file in the guest filesystem",
4761    "\
4762 This command preallocates a file (containing zero bytes) named
4763 C<path> of size C<len> bytes.  If the file exists already, it
4764 is overwritten.
4765
4766 Note that this call allocates disk blocks for the file.
4767 To create a sparse file use C<guestfs_truncate_size> instead.
4768
4769 The deprecated call C<guestfs_fallocate> does the same,
4770 but owing to an oversight it only allowed 30 bit lengths
4771 to be specified, effectively limiting the maximum size
4772 of files created through that call to 1GB.
4773
4774 Do not confuse this with the guestfish-specific
4775 C<alloc> and C<sparse> commands which create
4776 a file in the host and attach it as a device.");
4777
4778   ("vfs_label", (RString "label", [Device "device"]), 253, [],
4779    [InitBasicFS, Always, TestOutput (
4780        [["set_e2label"; "/dev/sda1"; "LTEST"];
4781         ["vfs_label"; "/dev/sda1"]], "LTEST")],
4782    "get the filesystem label",
4783    "\
4784 This returns the filesystem label of the filesystem on
4785 C<device>.
4786
4787 If the filesystem is unlabeled, this returns the empty string.");
4788
4789   ("vfs_uuid", (RString "uuid", [Device "device"]), 254, [],
4790    (let uuid = uuidgen () in
4791     [InitBasicFS, Always, TestOutput (
4792        [["set_e2uuid"; "/dev/sda1"; uuid];
4793         ["vfs_uuid"; "/dev/sda1"]], uuid)]),
4794    "get the filesystem UUID",
4795    "\
4796 This returns the filesystem UUID of the filesystem on
4797 C<device>.
4798
4799 If the filesystem does not have a UUID, this returns the empty string.");
4800
4801 ]
4802
4803 let all_functions = non_daemon_functions @ daemon_functions
4804
4805 (* In some places we want the functions to be displayed sorted
4806  * alphabetically, so this is useful:
4807  *)
4808 let all_functions_sorted =
4809   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
4810                compare n1 n2) all_functions
4811
4812 (* This is used to generate the src/MAX_PROC_NR file which
4813  * contains the maximum procedure number, a surrogate for the
4814  * ABI version number.  See src/Makefile.am for the details.
4815  *)
4816 let max_proc_nr =
4817   let proc_nrs = List.map (
4818     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
4819   ) daemon_functions in
4820   List.fold_left max 0 proc_nrs
4821
4822 (* Field types for structures. *)
4823 type field =
4824   | FChar                       (* C 'char' (really, a 7 bit byte). *)
4825   | FString                     (* nul-terminated ASCII string, NOT NULL. *)
4826   | FBuffer                     (* opaque buffer of bytes, (char *, int) pair *)
4827   | FUInt32
4828   | FInt32
4829   | FUInt64
4830   | FInt64
4831   | FBytes                      (* Any int measure that counts bytes. *)
4832   | FUUID                       (* 32 bytes long, NOT nul-terminated. *)
4833   | FOptPercent                 (* [0..100], or -1 meaning "not present". *)
4834
4835 (* Because we generate extra parsing code for LVM command line tools,
4836  * we have to pull out the LVM columns separately here.
4837  *)
4838 let lvm_pv_cols = [
4839   "pv_name", FString;
4840   "pv_uuid", FUUID;
4841   "pv_fmt", FString;
4842   "pv_size", FBytes;
4843   "dev_size", FBytes;
4844   "pv_free", FBytes;
4845   "pv_used", FBytes;
4846   "pv_attr", FString (* XXX *);
4847   "pv_pe_count", FInt64;
4848   "pv_pe_alloc_count", FInt64;
4849   "pv_tags", FString;
4850   "pe_start", FBytes;
4851   "pv_mda_count", FInt64;
4852   "pv_mda_free", FBytes;
4853   (* Not in Fedora 10:
4854      "pv_mda_size", FBytes;
4855   *)
4856 ]
4857 let lvm_vg_cols = [
4858   "vg_name", FString;
4859   "vg_uuid", FUUID;
4860   "vg_fmt", FString;
4861   "vg_attr", FString (* XXX *);
4862   "vg_size", FBytes;
4863   "vg_free", FBytes;
4864   "vg_sysid", FString;
4865   "vg_extent_size", FBytes;
4866   "vg_extent_count", FInt64;
4867   "vg_free_count", FInt64;
4868   "max_lv", FInt64;
4869   "max_pv", FInt64;
4870   "pv_count", FInt64;
4871   "lv_count", FInt64;
4872   "snap_count", FInt64;
4873   "vg_seqno", FInt64;
4874   "vg_tags", FString;
4875   "vg_mda_count", FInt64;
4876   "vg_mda_free", FBytes;
4877   (* Not in Fedora 10:
4878      "vg_mda_size", FBytes;
4879   *)
4880 ]
4881 let lvm_lv_cols = [
4882   "lv_name", FString;
4883   "lv_uuid", FUUID;
4884   "lv_attr", FString (* XXX *);
4885   "lv_major", FInt64;
4886   "lv_minor", FInt64;
4887   "lv_kernel_major", FInt64;
4888   "lv_kernel_minor", FInt64;
4889   "lv_size", FBytes;
4890   "seg_count", FInt64;
4891   "origin", FString;
4892   "snap_percent", FOptPercent;
4893   "copy_percent", FOptPercent;
4894   "move_pv", FString;
4895   "lv_tags", FString;
4896   "mirror_log", FString;
4897   "modules", FString;
4898 ]
4899
4900 (* Names and fields in all structures (in RStruct and RStructList)
4901  * that we support.
4902  *)
4903 let structs = [
4904   (* The old RIntBool return type, only ever used for aug_defnode.  Do
4905    * not use this struct in any new code.
4906    *)
4907   "int_bool", [
4908     "i", FInt32;                (* for historical compatibility *)
4909     "b", FInt32;                (* for historical compatibility *)
4910   ];
4911
4912   (* LVM PVs, VGs, LVs. *)
4913   "lvm_pv", lvm_pv_cols;
4914   "lvm_vg", lvm_vg_cols;
4915   "lvm_lv", lvm_lv_cols;
4916
4917   (* Column names and types from stat structures.
4918    * NB. Can't use things like 'st_atime' because glibc header files
4919    * define some of these as macros.  Ugh.
4920    *)
4921   "stat", [
4922     "dev", FInt64;
4923     "ino", FInt64;
4924     "mode", FInt64;
4925     "nlink", FInt64;
4926     "uid", FInt64;
4927     "gid", FInt64;
4928     "rdev", FInt64;
4929     "size", FInt64;
4930     "blksize", FInt64;
4931     "blocks", FInt64;
4932     "atime", FInt64;
4933     "mtime", FInt64;
4934     "ctime", FInt64;
4935   ];
4936   "statvfs", [
4937     "bsize", FInt64;
4938     "frsize", FInt64;
4939     "blocks", FInt64;
4940     "bfree", FInt64;
4941     "bavail", FInt64;
4942     "files", FInt64;
4943     "ffree", FInt64;
4944     "favail", FInt64;
4945     "fsid", FInt64;
4946     "flag", FInt64;
4947     "namemax", FInt64;
4948   ];
4949
4950   (* Column names in dirent structure. *)
4951   "dirent", [
4952     "ino", FInt64;
4953     (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
4954     "ftyp", FChar;
4955     "name", FString;
4956   ];
4957
4958   (* Version numbers. *)
4959   "version", [
4960     "major", FInt64;
4961     "minor", FInt64;
4962     "release", FInt64;
4963     "extra", FString;
4964   ];
4965
4966   (* Extended attribute. *)
4967   "xattr", [
4968     "attrname", FString;
4969     "attrval", FBuffer;
4970   ];
4971
4972   (* Inotify events. *)
4973   "inotify_event", [
4974     "in_wd", FInt64;
4975     "in_mask", FUInt32;
4976     "in_cookie", FUInt32;
4977     "in_name", FString;
4978   ];
4979
4980   (* Partition table entry. *)
4981   "partition", [
4982     "part_num", FInt32;
4983     "part_start", FBytes;
4984     "part_end", FBytes;
4985     "part_size", FBytes;
4986   ];
4987 ] (* end of structs *)
4988
4989 (* Ugh, Java has to be different ..
4990  * These names are also used by the Haskell bindings.
4991  *)
4992 let java_structs = [
4993   "int_bool", "IntBool";
4994   "lvm_pv", "PV";
4995   "lvm_vg", "VG";
4996   "lvm_lv", "LV";
4997   "stat", "Stat";
4998   "statvfs", "StatVFS";
4999   "dirent", "Dirent";
5000   "version", "Version";
5001   "xattr", "XAttr";
5002   "inotify_event", "INotifyEvent";
5003   "partition", "Partition";
5004 ]
5005
5006 (* What structs are actually returned. *)
5007 type rstructs_used_t = RStructOnly | RStructListOnly | RStructAndList
5008
5009 (* Returns a list of RStruct/RStructList structs that are returned
5010  * by any function.  Each element of returned list is a pair:
5011  *
5012  * (structname, RStructOnly)
5013  *    == there exists function which returns RStruct (_, structname)
5014  * (structname, RStructListOnly)
5015  *    == there exists function which returns RStructList (_, structname)
5016  * (structname, RStructAndList)
5017  *    == there are functions returning both RStruct (_, structname)
5018  *                                      and RStructList (_, structname)
5019  *)
5020 let rstructs_used_by functions =
5021   (* ||| is a "logical OR" for rstructs_used_t *)
5022   let (|||) a b =
5023     match a, b with
5024     | RStructAndList, _
5025     | _, RStructAndList -> RStructAndList
5026     | RStructOnly, RStructListOnly
5027     | RStructListOnly, RStructOnly -> RStructAndList
5028     | RStructOnly, RStructOnly -> RStructOnly
5029     | RStructListOnly, RStructListOnly -> RStructListOnly
5030   in
5031
5032   let h = Hashtbl.create 13 in
5033
5034   (* if elem->oldv exists, update entry using ||| operator,
5035    * else just add elem->newv to the hash
5036    *)
5037   let update elem newv =
5038     try  let oldv = Hashtbl.find h elem in
5039          Hashtbl.replace h elem (newv ||| oldv)
5040     with Not_found -> Hashtbl.add h elem newv
5041   in
5042
5043   List.iter (
5044     fun (_, style, _, _, _, _, _) ->
5045       match fst style with
5046       | RStruct (_, structname) -> update structname RStructOnly
5047       | RStructList (_, structname) -> update structname RStructListOnly
5048       | _ -> ()
5049   ) functions;
5050
5051   (* return key->values as a list of (key,value) *)
5052   Hashtbl.fold (fun key value xs -> (key, value) :: xs) h []
5053
5054 (* Used for testing language bindings. *)
5055 type callt =
5056   | CallString of string
5057   | CallOptString of string option
5058   | CallStringList of string list
5059   | CallInt of int
5060   | CallInt64 of int64
5061   | CallBool of bool
5062   | CallBuffer of string
5063
5064 (* Used to memoize the result of pod2text. *)
5065 let pod2text_memo_filename = "src/.pod2text.data"
5066 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
5067   try
5068     let chan = open_in pod2text_memo_filename in
5069     let v = input_value chan in
5070     close_in chan;
5071     v
5072   with
5073     _ -> Hashtbl.create 13
5074 let pod2text_memo_updated () =
5075   let chan = open_out pod2text_memo_filename in
5076   output_value chan pod2text_memo;
5077   close_out chan
5078
5079 (* Useful functions.
5080  * Note we don't want to use any external OCaml libraries which
5081  * makes this a bit harder than it should be.
5082  *)
5083 module StringMap = Map.Make (String)
5084
5085 let failwithf fs = ksprintf failwith fs
5086
5087 let unique = let i = ref 0 in fun () -> incr i; !i
5088
5089 let replace_char s c1 c2 =
5090   let s2 = String.copy s in
5091   let r = ref false in
5092   for i = 0 to String.length s2 - 1 do
5093     if String.unsafe_get s2 i = c1 then (
5094       String.unsafe_set s2 i c2;
5095       r := true
5096     )
5097   done;
5098   if not !r then s else s2
5099
5100 let isspace c =
5101   c = ' '
5102   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
5103
5104 let triml ?(test = isspace) str =
5105   let i = ref 0 in
5106   let n = ref (String.length str) in
5107   while !n > 0 && test str.[!i]; do
5108     decr n;
5109     incr i
5110   done;
5111   if !i = 0 then str
5112   else String.sub str !i !n
5113
5114 let trimr ?(test = isspace) str =
5115   let n = ref (String.length str) in
5116   while !n > 0 && test str.[!n-1]; do
5117     decr n
5118   done;
5119   if !n = String.length str then str
5120   else String.sub str 0 !n
5121
5122 let trim ?(test = isspace) str =
5123   trimr ~test (triml ~test str)
5124
5125 let rec find s sub =
5126   let len = String.length s in
5127   let sublen = String.length sub in
5128   let rec loop i =
5129     if i <= len-sublen then (
5130       let rec loop2 j =
5131         if j < sublen then (
5132           if s.[i+j] = sub.[j] then loop2 (j+1)
5133           else -1
5134         ) else
5135           i (* found *)
5136       in
5137       let r = loop2 0 in
5138       if r = -1 then loop (i+1) else r
5139     ) else
5140       -1 (* not found *)
5141   in
5142   loop 0
5143
5144 let rec replace_str s s1 s2 =
5145   let len = String.length s in
5146   let sublen = String.length s1 in
5147   let i = find s s1 in
5148   if i = -1 then s
5149   else (
5150     let s' = String.sub s 0 i in
5151     let s'' = String.sub s (i+sublen) (len-i-sublen) in
5152     s' ^ s2 ^ replace_str s'' s1 s2
5153   )
5154
5155 let rec string_split sep str =
5156   let len = String.length str in
5157   let seplen = String.length sep in
5158   let i = find str sep in
5159   if i = -1 then [str]
5160   else (
5161     let s' = String.sub str 0 i in
5162     let s'' = String.sub str (i+seplen) (len-i-seplen) in
5163     s' :: string_split sep s''
5164   )
5165
5166 let files_equal n1 n2 =
5167   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
5168   match Sys.command cmd with
5169   | 0 -> true
5170   | 1 -> false
5171   | i -> failwithf "%s: failed with error code %d" cmd i
5172
5173 let rec filter_map f = function
5174   | [] -> []
5175   | x :: xs ->
5176       match f x with
5177       | Some y -> y :: filter_map f xs
5178       | None -> filter_map f xs
5179
5180 let rec find_map f = function
5181   | [] -> raise Not_found
5182   | x :: xs ->
5183       match f x with
5184       | Some y -> y
5185       | None -> find_map f xs
5186
5187 let iteri f xs =
5188   let rec loop i = function
5189     | [] -> ()
5190     | x :: xs -> f i x; loop (i+1) xs
5191   in
5192   loop 0 xs
5193
5194 let mapi f xs =
5195   let rec loop i = function
5196     | [] -> []
5197     | x :: xs -> let r = f i x in r :: loop (i+1) xs
5198   in
5199   loop 0 xs
5200
5201 let count_chars c str =
5202   let count = ref 0 in
5203   for i = 0 to String.length str - 1 do
5204     if c = String.unsafe_get str i then incr count
5205   done;
5206   !count
5207
5208 let explode str =
5209   let r = ref [] in
5210   for i = 0 to String.length str - 1 do
5211     let c = String.unsafe_get str i in
5212     r := c :: !r;
5213   done;
5214   List.rev !r
5215
5216 let map_chars f str =
5217   List.map f (explode str)
5218
5219 let name_of_argt = function
5220   | Pathname n | Device n | Dev_or_Path n | String n | OptString n
5221   | StringList n | DeviceList n | Bool n | Int n | Int64 n
5222   | FileIn n | FileOut n | BufferIn n -> n
5223
5224 let java_name_of_struct typ =
5225   try List.assoc typ java_structs
5226   with Not_found ->
5227     failwithf
5228       "java_name_of_struct: no java_structs entry corresponding to %s" typ
5229
5230 let cols_of_struct typ =
5231   try List.assoc typ structs
5232   with Not_found ->
5233     failwithf "cols_of_struct: unknown struct %s" typ
5234
5235 let seq_of_test = function
5236   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
5237   | TestOutputListOfDevices (s, _)
5238   | TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
5239   | TestOutputTrue s | TestOutputFalse s
5240   | TestOutputLength (s, _) | TestOutputBuffer (s, _)
5241   | TestOutputStruct (s, _)
5242   | TestLastFail s -> s
5243
5244 (* Handling for function flags. *)
5245 let protocol_limit_warning =
5246   "Because of the message protocol, there is a transfer limit
5247 of somewhere between 2MB and 4MB.  See L<guestfs(3)/PROTOCOL LIMITS>."
5248
5249 let danger_will_robinson =
5250   "B<This command is dangerous.  Without careful use you
5251 can easily destroy all your data>."
5252
5253 let deprecation_notice flags =
5254   try
5255     let alt =
5256       find_map (function DeprecatedBy str -> Some str | _ -> None) flags in
5257     let txt =
5258       sprintf "This function is deprecated.
5259 In new code, use the C<%s> call instead.
5260
5261 Deprecated functions will not be removed from the API, but the
5262 fact that they are deprecated indicates that there are problems
5263 with correct use of these functions." alt in
5264     Some txt
5265   with
5266     Not_found -> None
5267
5268 (* Create list of optional groups. *)
5269 let optgroups =
5270   let h = Hashtbl.create 13 in
5271   List.iter (
5272     fun (name, _, _, flags, _, _, _) ->
5273       List.iter (
5274         function
5275         | Optional group ->
5276             let names = try Hashtbl.find h group with Not_found -> [] in
5277             Hashtbl.replace h group (name :: names)
5278         | _ -> ()
5279       ) flags
5280   ) daemon_functions;
5281   let groups = Hashtbl.fold (fun k _ ks -> k :: ks) h [] in
5282   let groups =
5283     List.map (
5284       fun group -> group, List.sort compare (Hashtbl.find h group)
5285     ) groups in
5286   List.sort (fun x y -> compare (fst x) (fst y)) groups
5287
5288 (* Check function names etc. for consistency. *)
5289 let check_functions () =
5290   let contains_uppercase str =
5291     let len = String.length str in
5292     let rec loop i =
5293       if i >= len then false
5294       else (
5295         let c = str.[i] in
5296         if c >= 'A' && c <= 'Z' then true
5297         else loop (i+1)
5298       )
5299     in
5300     loop 0
5301   in
5302
5303   (* Check function names. *)
5304   List.iter (
5305     fun (name, _, _, _, _, _, _) ->
5306       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
5307         failwithf "function name %s does not need 'guestfs' prefix" name;
5308       if name = "" then
5309         failwithf "function name is empty";
5310       if name.[0] < 'a' || name.[0] > 'z' then
5311         failwithf "function name %s must start with lowercase a-z" name;
5312       if String.contains name '-' then
5313         failwithf "function name %s should not contain '-', use '_' instead."
5314           name
5315   ) all_functions;
5316
5317   (* Check function parameter/return names. *)
5318   List.iter (
5319     fun (name, style, _, _, _, _, _) ->
5320       let check_arg_ret_name n =
5321         if contains_uppercase n then
5322           failwithf "%s param/ret %s should not contain uppercase chars"
5323             name n;
5324         if String.contains n '-' || String.contains n '_' then
5325           failwithf "%s param/ret %s should not contain '-' or '_'"
5326             name n;
5327         if n = "value" then
5328           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;
5329         if n = "int" || n = "char" || n = "short" || n = "long" then
5330           failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
5331         if n = "i" || n = "n" then
5332           failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
5333         if n = "argv" || n = "args" then
5334           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name;
5335
5336         (* List Haskell, OCaml and C keywords here.
5337          * http://www.haskell.org/haskellwiki/Keywords
5338          * http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#operator-char
5339          * http://en.wikipedia.org/wiki/C_syntax#Reserved_keywords
5340          * Formatted via: cat c haskell ocaml|sort -u|grep -vE '_|^val$' \
5341          *   |perl -pe 's/(.+)/"$1";/'|fmt -70
5342          * Omitting _-containing words, since they're handled above.
5343          * Omitting the OCaml reserved word, "val", is ok,
5344          * and saves us from renaming several parameters.
5345          *)
5346         let reserved = [
5347           "and"; "as"; "asr"; "assert"; "auto"; "begin"; "break"; "case";
5348           "char"; "class"; "const"; "constraint"; "continue"; "data";
5349           "default"; "deriving"; "do"; "done"; "double"; "downto"; "else";
5350           "end"; "enum"; "exception"; "extern"; "external"; "false"; "float";
5351           "for"; "forall"; "foreign"; "fun"; "function"; "functor"; "goto";
5352           "hiding"; "if"; "import"; "in"; "include"; "infix"; "infixl";
5353           "infixr"; "inherit"; "initializer"; "inline"; "instance"; "int";
5354           "interface";
5355           "land"; "lazy"; "let"; "long"; "lor"; "lsl"; "lsr"; "lxor";
5356           "match"; "mdo"; "method"; "mod"; "module"; "mutable"; "new";
5357           "newtype"; "object"; "of"; "open"; "or"; "private"; "qualified";
5358           "rec"; "register"; "restrict"; "return"; "short"; "sig"; "signed";
5359           "sizeof"; "static"; "struct"; "switch"; "then"; "to"; "true"; "try";
5360           "type"; "typedef"; "union"; "unsigned"; "virtual"; "void";
5361           "volatile"; "when"; "where"; "while";
5362           ] in
5363         if List.mem n reserved then
5364           failwithf "%s has param/ret using reserved word %s" name n;
5365       in
5366
5367       (match fst style with
5368        | RErr -> ()
5369        | RInt n | RInt64 n | RBool n
5370        | RConstString n | RConstOptString n | RString n
5371        | RStringList n | RStruct (n, _) | RStructList (n, _)
5372        | RHashtable n | RBufferOut n ->
5373            check_arg_ret_name n
5374       );
5375       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
5376   ) all_functions;
5377
5378   (* Check short descriptions. *)
5379   List.iter (
5380     fun (name, _, _, _, _, shortdesc, _) ->
5381       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
5382         failwithf "short description of %s should begin with lowercase." name;
5383       let c = shortdesc.[String.length shortdesc-1] in
5384       if c = '\n' || c = '.' then
5385         failwithf "short description of %s should not end with . or \\n." name
5386   ) all_functions;
5387
5388   (* Check long descriptions. *)
5389   List.iter (
5390     fun (name, _, _, _, _, _, longdesc) ->
5391       if longdesc.[String.length longdesc-1] = '\n' then
5392         failwithf "long description of %s should not end with \\n." name
5393   ) all_functions;
5394
5395   (* Check proc_nrs. *)
5396   List.iter (
5397     fun (name, _, proc_nr, _, _, _, _) ->
5398       if proc_nr <= 0 then
5399         failwithf "daemon function %s should have proc_nr > 0" name
5400   ) daemon_functions;
5401
5402   List.iter (
5403     fun (name, _, proc_nr, _, _, _, _) ->
5404       if proc_nr <> -1 then
5405         failwithf "non-daemon function %s should have proc_nr -1" name
5406   ) non_daemon_functions;
5407
5408   let proc_nrs =
5409     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
5410       daemon_functions in
5411   let proc_nrs =
5412     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
5413   let rec loop = function
5414     | [] -> ()
5415     | [_] -> ()
5416     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
5417         loop rest
5418     | (name1,nr1) :: (name2,nr2) :: _ ->
5419         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
5420           name1 name2 nr1 nr2
5421   in
5422   loop proc_nrs;
5423
5424   (* Check tests. *)
5425   List.iter (
5426     function
5427       (* Ignore functions that have no tests.  We generate a
5428        * warning when the user does 'make check' instead.
5429        *)
5430     | name, _, _, _, [], _, _ -> ()
5431     | name, _, _, _, tests, _, _ ->
5432         let funcs =
5433           List.map (
5434             fun (_, _, test) ->
5435               match seq_of_test test with
5436               | [] ->
5437                   failwithf "%s has a test containing an empty sequence" name
5438               | cmds -> List.map List.hd cmds
5439           ) tests in
5440         let funcs = List.flatten funcs in
5441
5442         let tested = List.mem name funcs in
5443
5444         if not tested then
5445           failwithf "function %s has tests but does not test itself" name
5446   ) all_functions
5447
5448 (* 'pr' prints to the current output file. *)
5449 let chan = ref Pervasives.stdout
5450 let lines = ref 0
5451 let pr fs =
5452   ksprintf
5453     (fun str ->
5454        let i = count_chars '\n' str in
5455        lines := !lines + i;
5456        output_string !chan str
5457     ) fs
5458
5459 let copyright_years =
5460   let this_year = 1900 + (localtime (time ())).tm_year in
5461   if this_year > 2009 then sprintf "2009-%04d" this_year else "2009"
5462
5463 (* Generate a header block in a number of standard styles. *)
5464 type comment_style =
5465     CStyle | CPlusPlusStyle | HashStyle | OCamlStyle | HaskellStyle
5466 type license = GPLv2plus | LGPLv2plus
5467
5468 let generate_header ?(extra_inputs = []) comment license =
5469   let inputs = "src/generator.ml" :: extra_inputs in
5470   let c = match comment with
5471     | CStyle ->         pr "/* "; " *"
5472     | CPlusPlusStyle -> pr "// "; "//"
5473     | HashStyle ->      pr "# ";  "#"
5474     | OCamlStyle ->     pr "(* "; " *"
5475     | HaskellStyle ->   pr "{- "; "  " in
5476   pr "libguestfs generated file\n";
5477   pr "%s WARNING: THIS FILE IS GENERATED FROM:\n" c;
5478   List.iter (pr "%s   %s\n" c) inputs;
5479   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
5480   pr "%s\n" c;
5481   pr "%s Copyright (C) %s Red Hat Inc.\n" c copyright_years;
5482   pr "%s\n" c;
5483   (match license with
5484    | GPLv2plus ->
5485        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
5486        pr "%s it under the terms of the GNU General Public License as published by\n" c;
5487        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
5488        pr "%s (at your option) any later version.\n" c;
5489        pr "%s\n" c;
5490        pr "%s This program is distributed in the hope that it will be useful,\n" c;
5491        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
5492        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
5493        pr "%s GNU General Public License for more details.\n" c;
5494        pr "%s\n" c;
5495        pr "%s You should have received a copy of the GNU General Public License along\n" c;
5496        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
5497        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
5498
5499    | LGPLv2plus ->
5500        pr "%s This library is free software; you can redistribute it and/or\n" c;
5501        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
5502        pr "%s License as published by the Free Software Foundation; either\n" c;
5503        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
5504        pr "%s\n" c;
5505        pr "%s This library is distributed in the hope that it will be useful,\n" c;
5506        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
5507        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
5508        pr "%s Lesser General Public License for more details.\n" c;
5509        pr "%s\n" c;
5510        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
5511        pr "%s License along with this library; if not, write to the Free Software\n" c;
5512        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
5513   );
5514   (match comment with
5515    | CStyle -> pr " */\n"
5516    | CPlusPlusStyle
5517    | HashStyle -> ()
5518    | OCamlStyle -> pr " *)\n"
5519    | HaskellStyle -> pr "-}\n"
5520   );
5521   pr "\n"
5522
5523 (* Start of main code generation functions below this line. *)
5524
5525 (* Generate the pod documentation for the C API. *)
5526 let rec generate_actions_pod () =
5527   List.iter (
5528     fun (shortname, style, _, flags, _, _, longdesc) ->
5529       if not (List.mem NotInDocs flags) then (
5530         let name = "guestfs_" ^ shortname in
5531         pr "=head2 %s\n\n" name;
5532         pr " ";
5533         generate_prototype ~extern:false ~handle:"g" name style;
5534         pr "\n\n";
5535         pr "%s\n\n" longdesc;
5536         (match fst style with
5537          | RErr ->
5538              pr "This function returns 0 on success or -1 on error.\n\n"
5539          | RInt _ ->
5540              pr "On error this function returns -1.\n\n"
5541          | RInt64 _ ->
5542              pr "On error this function returns -1.\n\n"
5543          | RBool _ ->
5544              pr "This function returns a C truth value on success or -1 on error.\n\n"
5545          | RConstString _ ->
5546              pr "This function returns a string, or NULL on error.
5547 The string is owned by the guest handle and must I<not> be freed.\n\n"
5548          | RConstOptString _ ->
5549              pr "This function returns a string which may be NULL.
5550 There is way to return an error from this function.
5551 The string is owned by the guest handle and must I<not> be freed.\n\n"
5552          | RString _ ->
5553              pr "This function returns a string, or NULL on error.
5554 I<The caller must free the returned string after use>.\n\n"
5555          | RStringList _ ->
5556              pr "This function returns a NULL-terminated array of strings
5557 (like L<environ(3)>), or NULL if there was an error.
5558 I<The caller must free the strings and the array after use>.\n\n"
5559          | RStruct (_, typ) ->
5560              pr "This function returns a C<struct guestfs_%s *>,
5561 or NULL if there was an error.
5562 I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ
5563          | RStructList (_, typ) ->
5564              pr "This function returns a C<struct guestfs_%s_list *>
5565 (see E<lt>guestfs-structs.hE<gt>),
5566 or NULL if there was an error.
5567 I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ
5568          | RHashtable _ ->
5569              pr "This function returns a NULL-terminated array of
5570 strings, or NULL if there was an error.
5571 The array of strings will always have length C<2n+1>, where
5572 C<n> keys and values alternate, followed by the trailing NULL entry.
5573 I<The caller must free the strings and the array after use>.\n\n"
5574          | RBufferOut _ ->
5575              pr "This function returns a buffer, or NULL on error.
5576 The size of the returned buffer is written to C<*size_r>.
5577 I<The caller must free the returned buffer after use>.\n\n"
5578         );
5579         if List.mem ProtocolLimitWarning flags then
5580           pr "%s\n\n" protocol_limit_warning;
5581         if List.mem DangerWillRobinson flags then
5582           pr "%s\n\n" danger_will_robinson;
5583         match deprecation_notice flags with
5584         | None -> ()
5585         | Some txt -> pr "%s\n\n" txt
5586       )
5587   ) all_functions_sorted
5588
5589 and generate_structs_pod () =
5590   (* Structs documentation. *)
5591   List.iter (
5592     fun (typ, cols) ->
5593       pr "=head2 guestfs_%s\n" typ;
5594       pr "\n";
5595       pr " struct guestfs_%s {\n" typ;
5596       List.iter (
5597         function
5598         | name, FChar -> pr "   char %s;\n" name
5599         | name, FUInt32 -> pr "   uint32_t %s;\n" name
5600         | name, FInt32 -> pr "   int32_t %s;\n" name
5601         | name, (FUInt64|FBytes) -> pr "   uint64_t %s;\n" name
5602         | name, FInt64 -> pr "   int64_t %s;\n" name
5603         | name, FString -> pr "   char *%s;\n" name
5604         | name, FBuffer ->
5605             pr "   /* The next two fields describe a byte array. */\n";
5606             pr "   uint32_t %s_len;\n" name;
5607             pr "   char *%s;\n" name
5608         | name, FUUID ->
5609             pr "   /* The next field is NOT nul-terminated, be careful when printing it: */\n";
5610             pr "   char %s[32];\n" name
5611         | name, FOptPercent ->
5612             pr "   /* The next field is [0..100] or -1 meaning 'not present': */\n";
5613             pr "   float %s;\n" name
5614       ) cols;
5615       pr " };\n";
5616       pr " \n";
5617       pr " struct guestfs_%s_list {\n" typ;
5618       pr "   uint32_t len; /* Number of elements in list. */\n";
5619       pr "   struct guestfs_%s *val; /* Elements. */\n" typ;
5620       pr " };\n";
5621       pr " \n";
5622       pr " void guestfs_free_%s (struct guestfs_free_%s *);\n" typ typ;
5623       pr " void guestfs_free_%s_list (struct guestfs_free_%s_list *);\n"
5624         typ typ;
5625       pr "\n"
5626   ) structs
5627
5628 and generate_availability_pod () =
5629   (* Availability documentation. *)
5630   pr "=over 4\n";
5631   pr "\n";
5632   List.iter (
5633     fun (group, functions) ->
5634       pr "=item B<%s>\n" group;
5635       pr "\n";
5636       pr "The following functions:\n";
5637       List.iter (pr "L</guestfs_%s>\n") functions;
5638       pr "\n"
5639   ) optgroups;
5640   pr "=back\n";
5641   pr "\n"
5642
5643 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
5644  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
5645  *
5646  * We have to use an underscore instead of a dash because otherwise
5647  * rpcgen generates incorrect code.
5648  *
5649  * This header is NOT exported to clients, but see also generate_structs_h.
5650  *)
5651 and generate_xdr () =
5652   generate_header CStyle LGPLv2plus;
5653
5654   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
5655   pr "typedef string str<>;\n";
5656   pr "\n";
5657
5658   (* Internal structures. *)
5659   List.iter (
5660     function
5661     | typ, cols ->
5662         pr "struct guestfs_int_%s {\n" typ;
5663         List.iter (function
5664                    | name, FChar -> pr "  char %s;\n" name
5665                    | name, FString -> pr "  string %s<>;\n" name
5666                    | name, FBuffer -> pr "  opaque %s<>;\n" name
5667                    | name, FUUID -> pr "  opaque %s[32];\n" name
5668                    | name, (FInt32|FUInt32) -> pr "  int %s;\n" name
5669                    | name, (FInt64|FUInt64|FBytes) -> pr "  hyper %s;\n" name
5670                    | name, FOptPercent -> pr "  float %s;\n" name
5671                   ) cols;
5672         pr "};\n";
5673         pr "\n";
5674         pr "typedef struct guestfs_int_%s guestfs_int_%s_list<>;\n" typ typ;
5675         pr "\n";
5676   ) structs;
5677
5678   List.iter (
5679     fun (shortname, style, _, _, _, _, _) ->
5680       let name = "guestfs_" ^ shortname in
5681
5682       (match snd style with
5683        | [] -> ()
5684        | args ->
5685            pr "struct %s_args {\n" name;
5686            List.iter (
5687              function
5688              | Pathname n | Device n | Dev_or_Path n | String n ->
5689                  pr "  string %s<>;\n" n
5690              | OptString n -> pr "  str *%s;\n" n
5691              | StringList n | DeviceList n -> pr "  str %s<>;\n" n
5692              | Bool n -> pr "  bool %s;\n" n
5693              | Int n -> pr "  int %s;\n" n
5694              | Int64 n -> pr "  hyper %s;\n" n
5695              | BufferIn n ->
5696                  pr "  opaque %s<>;\n" n
5697              | FileIn _ | FileOut _ -> ()
5698            ) args;
5699            pr "};\n\n"
5700       );
5701       (match fst style with
5702        | RErr -> ()
5703        | RInt n ->
5704            pr "struct %s_ret {\n" name;
5705            pr "  int %s;\n" n;
5706            pr "};\n\n"
5707        | RInt64 n ->
5708            pr "struct %s_ret {\n" name;
5709            pr "  hyper %s;\n" n;
5710            pr "};\n\n"
5711        | RBool n ->
5712            pr "struct %s_ret {\n" name;
5713            pr "  bool %s;\n" n;
5714            pr "};\n\n"
5715        | RConstString _ | RConstOptString _ ->
5716            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5717        | RString n ->
5718            pr "struct %s_ret {\n" name;
5719            pr "  string %s<>;\n" n;
5720            pr "};\n\n"
5721        | RStringList n ->
5722            pr "struct %s_ret {\n" name;
5723            pr "  str %s<>;\n" n;
5724            pr "};\n\n"
5725        | RStruct (n, typ) ->
5726            pr "struct %s_ret {\n" name;
5727            pr "  guestfs_int_%s %s;\n" typ n;
5728            pr "};\n\n"
5729        | RStructList (n, typ) ->
5730            pr "struct %s_ret {\n" name;
5731            pr "  guestfs_int_%s_list %s;\n" typ n;
5732            pr "};\n\n"
5733        | RHashtable n ->
5734            pr "struct %s_ret {\n" name;
5735            pr "  str %s<>;\n" n;
5736            pr "};\n\n"
5737        | RBufferOut n ->
5738            pr "struct %s_ret {\n" name;
5739            pr "  opaque %s<>;\n" n;
5740            pr "};\n\n"
5741       );
5742   ) daemon_functions;
5743
5744   (* Table of procedure numbers. *)
5745   pr "enum guestfs_procedure {\n";
5746   List.iter (
5747     fun (shortname, _, proc_nr, _, _, _, _) ->
5748       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
5749   ) daemon_functions;
5750   pr "  GUESTFS_PROC_NR_PROCS\n";
5751   pr "};\n";
5752   pr "\n";
5753
5754   (* Having to choose a maximum message size is annoying for several
5755    * reasons (it limits what we can do in the API), but it (a) makes
5756    * the protocol a lot simpler, and (b) provides a bound on the size
5757    * of the daemon which operates in limited memory space.
5758    *)
5759   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
5760   pr "\n";
5761
5762   (* Message header, etc. *)
5763   pr "\
5764 /* The communication protocol is now documented in the guestfs(3)
5765  * manpage.
5766  */
5767
5768 const GUESTFS_PROGRAM = 0x2000F5F5;
5769 const GUESTFS_PROTOCOL_VERSION = 1;
5770
5771 /* These constants must be larger than any possible message length. */
5772 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
5773 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
5774
5775 enum guestfs_message_direction {
5776   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
5777   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
5778 };
5779
5780 enum guestfs_message_status {
5781   GUESTFS_STATUS_OK = 0,
5782   GUESTFS_STATUS_ERROR = 1
5783 };
5784
5785 const GUESTFS_ERROR_LEN = 256;
5786
5787 struct guestfs_message_error {
5788   string error_message<GUESTFS_ERROR_LEN>;
5789 };
5790
5791 struct guestfs_message_header {
5792   unsigned prog;                     /* GUESTFS_PROGRAM */
5793   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
5794   guestfs_procedure proc;            /* GUESTFS_PROC_x */
5795   guestfs_message_direction direction;
5796   unsigned serial;                   /* message serial number */
5797   guestfs_message_status status;
5798 };
5799
5800 const GUESTFS_MAX_CHUNK_SIZE = 8192;
5801
5802 struct guestfs_chunk {
5803   int cancel;                        /* if non-zero, transfer is cancelled */
5804   /* data size is 0 bytes if the transfer has finished successfully */
5805   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
5806 };
5807 "
5808
5809 (* Generate the guestfs-structs.h file. *)
5810 and generate_structs_h () =
5811   generate_header CStyle LGPLv2plus;
5812
5813   (* This is a public exported header file containing various
5814    * structures.  The structures are carefully written to have
5815    * exactly the same in-memory format as the XDR structures that
5816    * we use on the wire to the daemon.  The reason for creating
5817    * copies of these structures here is just so we don't have to
5818    * export the whole of guestfs_protocol.h (which includes much
5819    * unrelated and XDR-dependent stuff that we don't want to be
5820    * public, or required by clients).
5821    *
5822    * To reiterate, we will pass these structures to and from the
5823    * client with a simple assignment or memcpy, so the format
5824    * must be identical to what rpcgen / the RFC defines.
5825    *)
5826
5827   (* Public structures. *)
5828   List.iter (
5829     fun (typ, cols) ->
5830       pr "struct guestfs_%s {\n" typ;
5831       List.iter (
5832         function
5833         | name, FChar -> pr "  char %s;\n" name
5834         | name, FString -> pr "  char *%s;\n" name
5835         | name, FBuffer ->
5836             pr "  uint32_t %s_len;\n" name;
5837             pr "  char *%s;\n" name
5838         | name, FUUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
5839         | name, FUInt32 -> pr "  uint32_t %s;\n" name
5840         | name, FInt32 -> pr "  int32_t %s;\n" name
5841         | name, (FUInt64|FBytes) -> pr "  uint64_t %s;\n" name
5842         | name, FInt64 -> pr "  int64_t %s;\n" name
5843         | name, FOptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
5844       ) cols;
5845       pr "};\n";
5846       pr "\n";
5847       pr "struct guestfs_%s_list {\n" typ;
5848       pr "  uint32_t len;\n";
5849       pr "  struct guestfs_%s *val;\n" typ;
5850       pr "};\n";
5851       pr "\n";
5852       pr "extern void guestfs_free_%s (struct guestfs_%s *);\n" typ typ;
5853       pr "extern void guestfs_free_%s_list (struct guestfs_%s_list *);\n" typ typ;
5854       pr "\n"
5855   ) structs
5856
5857 (* Generate the guestfs-actions.h file. *)
5858 and generate_actions_h () =
5859   generate_header CStyle LGPLv2plus;
5860   List.iter (
5861     fun (shortname, style, _, _, _, _, _) ->
5862       let name = "guestfs_" ^ shortname in
5863       generate_prototype ~single_line:true ~newline:true ~handle:"g"
5864         name style
5865   ) all_functions
5866
5867 (* Generate the guestfs-internal-actions.h file. *)
5868 and generate_internal_actions_h () =
5869   generate_header CStyle LGPLv2plus;
5870   List.iter (
5871     fun (shortname, style, _, _, _, _, _) ->
5872       let name = "guestfs__" ^ shortname in
5873       generate_prototype ~single_line:true ~newline:true ~handle:"g"
5874         name style
5875   ) non_daemon_functions
5876
5877 (* Generate the client-side dispatch stubs. *)
5878 and generate_client_actions () =
5879   generate_header CStyle LGPLv2plus;
5880
5881   pr "\
5882 #include <stdio.h>
5883 #include <stdlib.h>
5884 #include <stdint.h>
5885 #include <string.h>
5886 #include <inttypes.h>
5887
5888 #include \"guestfs.h\"
5889 #include \"guestfs-internal.h\"
5890 #include \"guestfs-internal-actions.h\"
5891 #include \"guestfs_protocol.h\"
5892
5893 #define error guestfs_error
5894 //#define perrorf guestfs_perrorf
5895 #define safe_malloc guestfs_safe_malloc
5896 #define safe_realloc guestfs_safe_realloc
5897 //#define safe_strdup guestfs_safe_strdup
5898 #define safe_memdup guestfs_safe_memdup
5899
5900 /* Check the return message from a call for validity. */
5901 static int
5902 check_reply_header (guestfs_h *g,
5903                     const struct guestfs_message_header *hdr,
5904                     unsigned int proc_nr, unsigned int serial)
5905 {
5906   if (hdr->prog != GUESTFS_PROGRAM) {
5907     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
5908     return -1;
5909   }
5910   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
5911     error (g, \"wrong protocol version (%%d/%%d)\",
5912            hdr->vers, GUESTFS_PROTOCOL_VERSION);
5913     return -1;
5914   }
5915   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
5916     error (g, \"unexpected message direction (%%d/%%d)\",
5917            hdr->direction, GUESTFS_DIRECTION_REPLY);
5918     return -1;
5919   }
5920   if (hdr->proc != proc_nr) {
5921     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
5922     return -1;
5923   }
5924   if (hdr->serial != serial) {
5925     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
5926     return -1;
5927   }
5928
5929   return 0;
5930 }
5931
5932 /* Check we are in the right state to run a high-level action. */
5933 static int
5934 check_state (guestfs_h *g, const char *caller)
5935 {
5936   if (!guestfs__is_ready (g)) {
5937     if (guestfs__is_config (g) || guestfs__is_launching (g))
5938       error (g, \"%%s: call launch before using this function\\n(in guestfish, don't forget to use the 'run' command)\",
5939         caller);
5940     else
5941       error (g, \"%%s called from the wrong state, %%d != READY\",
5942         caller, guestfs__get_state (g));
5943     return -1;
5944   }
5945   return 0;
5946 }
5947
5948 ";
5949
5950   let error_code_of = function
5951     | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
5952     | RConstString _ | RConstOptString _
5953     | RString _ | RStringList _
5954     | RStruct _ | RStructList _
5955     | RHashtable _ | RBufferOut _ -> "NULL"
5956   in
5957
5958   (* Generate code to check String-like parameters are not passed in
5959    * as NULL (returning an error if they are).
5960    *)
5961   let check_null_strings shortname style =
5962     let pr_newline = ref false in
5963     List.iter (
5964       function
5965       (* parameters which should not be NULL *)
5966       | String n
5967       | Device n
5968       | Pathname n
5969       | Dev_or_Path n
5970       | FileIn n
5971       | FileOut n
5972       | BufferIn n
5973       | StringList n
5974       | DeviceList n ->
5975           pr "  if (%s == NULL) {\n" n;
5976           pr "    error (g, \"%%s: %%s: parameter cannot be NULL\",\n";
5977           pr "           \"%s\", \"%s\");\n" shortname n;
5978           pr "    return %s;\n" (error_code_of (fst style));
5979           pr "  }\n";
5980           pr_newline := true
5981
5982       (* can be NULL *)
5983       | OptString _
5984
5985       (* not applicable *)
5986       | Bool _
5987       | Int _
5988       | Int64 _ -> ()
5989     ) (snd style);
5990
5991     if !pr_newline then pr "\n";
5992   in
5993
5994   (* Generate code to generate guestfish call traces. *)
5995   let trace_call shortname style =
5996     pr "  if (guestfs__get_trace (g)) {\n";
5997
5998     let needs_i =
5999       List.exists (function
6000                    | StringList _ | DeviceList _ -> true
6001                    | _ -> false) (snd style) in
6002     if needs_i then (
6003       pr "    int i;\n";
6004       pr "\n"
6005     );
6006
6007     pr "    printf (\"%s\");\n" shortname;
6008     List.iter (
6009       function
6010       | String n                        (* strings *)
6011       | Device n
6012       | Pathname n
6013       | Dev_or_Path n
6014       | FileIn n
6015       | FileOut n
6016       | BufferIn n ->
6017           (* guestfish doesn't support string escaping, so neither do we *)
6018           pr "    printf (\" \\\"%%s\\\"\", %s);\n" n
6019       | OptString n ->                  (* string option *)
6020           pr "    if (%s) printf (\" \\\"%%s\\\"\", %s);\n" n n;
6021           pr "    else printf (\" null\");\n"
6022       | StringList n
6023       | DeviceList n ->                 (* string list *)
6024           pr "    putchar (' ');\n";
6025           pr "    putchar ('\"');\n";
6026           pr "    for (i = 0; %s[i]; ++i) {\n" n;
6027           pr "      if (i > 0) putchar (' ');\n";
6028           pr "      fputs (%s[i], stdout);\n" n;
6029           pr "    }\n";
6030           pr "    putchar ('\"');\n";
6031       | Bool n ->                       (* boolean *)
6032           pr "    fputs (%s ? \" true\" : \" false\", stdout);\n" n
6033       | Int n ->                        (* int *)
6034           pr "    printf (\" %%d\", %s);\n" n
6035       | Int64 n ->
6036           pr "    printf (\" %%\" PRIi64, %s);\n" n
6037     ) (snd style);
6038     pr "    putchar ('\\n');\n";
6039     pr "  }\n";
6040     pr "\n";
6041   in
6042
6043   (* For non-daemon functions, generate a wrapper around each function. *)
6044   List.iter (
6045     fun (shortname, style, _, _, _, _, _) ->
6046       let name = "guestfs_" ^ shortname in
6047
6048       generate_prototype ~extern:false ~semicolon:false ~newline:true
6049         ~handle:"g" name style;
6050       pr "{\n";
6051       check_null_strings shortname style;
6052       trace_call shortname style;
6053       pr "  return guestfs__%s " shortname;
6054       generate_c_call_args ~handle:"g" style;
6055       pr ";\n";
6056       pr "}\n";
6057       pr "\n"
6058   ) non_daemon_functions;
6059
6060   (* Client-side stubs for each function. *)
6061   List.iter (
6062     fun (shortname, style, _, _, _, _, _) ->
6063       let name = "guestfs_" ^ shortname in
6064       let error_code = error_code_of (fst style) in
6065
6066       (* Generate the action stub. *)
6067       generate_prototype ~extern:false ~semicolon:false ~newline:true
6068         ~handle:"g" name style;
6069
6070       pr "{\n";
6071
6072       (match snd style with
6073        | [] -> ()
6074        | _ -> pr "  struct %s_args args;\n" name
6075       );
6076
6077       pr "  guestfs_message_header hdr;\n";
6078       pr "  guestfs_message_error err;\n";
6079       let has_ret =
6080         match fst style with
6081         | RErr -> false
6082         | RConstString _ | RConstOptString _ ->
6083             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
6084         | RInt _ | RInt64 _
6085         | RBool _ | RString _ | RStringList _
6086         | RStruct _ | RStructList _
6087         | RHashtable _ | RBufferOut _ ->
6088             pr "  struct %s_ret ret;\n" name;
6089             true in
6090
6091       pr "  int serial;\n";
6092       pr "  int r;\n";
6093       pr "\n";
6094       check_null_strings shortname style;
6095       trace_call shortname style;
6096       pr "  if (check_state (g, \"%s\") == -1) return %s;\n"
6097         shortname error_code;
6098       pr "  guestfs___set_busy (g);\n";
6099       pr "\n";
6100
6101       (* Send the main header and arguments. *)
6102       (match snd style with
6103        | [] ->
6104            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s, NULL, NULL);\n"
6105              (String.uppercase shortname)
6106        | args ->
6107            List.iter (
6108              function
6109              | Pathname n | Device n | Dev_or_Path n | String n ->
6110                  pr "  args.%s = (char *) %s;\n" n n
6111              | OptString n ->
6112                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
6113              | StringList n | DeviceList n ->
6114                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
6115                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
6116              | Bool n ->
6117                  pr "  args.%s = %s;\n" n n
6118              | Int n ->
6119                  pr "  args.%s = %s;\n" n n
6120              | Int64 n ->
6121                  pr "  args.%s = %s;\n" n n
6122              | FileIn _ | FileOut _ -> ()
6123              | BufferIn n ->
6124                  pr "  /* Just catch grossly large sizes. XDR encoding will make this precise. */\n";
6125                  pr "  if (%s_size >= GUESTFS_MESSAGE_MAX) {\n" n;
6126                  pr "    error (g, \"%%s: size of input buffer too large\", \"%s\");\n"
6127                    shortname;
6128                  pr "    guestfs___end_busy (g);\n";
6129                  pr "    return %s;\n" error_code;
6130                  pr "  }\n";
6131                  pr "  args.%s.%s_val = (char *) %s;\n" n n n;
6132                  pr "  args.%s.%s_len = %s_size;\n" n n n
6133            ) args;
6134            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s,\n"
6135              (String.uppercase shortname);
6136            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
6137              name;
6138       );
6139       pr "  if (serial == -1) {\n";
6140       pr "    guestfs___end_busy (g);\n";
6141       pr "    return %s;\n" error_code;
6142       pr "  }\n";
6143       pr "\n";
6144
6145       (* Send any additional files (FileIn) requested. *)
6146       let need_read_reply_label = ref false in
6147       List.iter (
6148         function
6149         | FileIn n ->
6150             pr "  r = guestfs___send_file (g, %s);\n" n;
6151             pr "  if (r == -1) {\n";
6152             pr "    guestfs___end_busy (g);\n";
6153             pr "    return %s;\n" error_code;
6154             pr "  }\n";
6155             pr "  if (r == -2) /* daemon cancelled */\n";
6156             pr "    goto read_reply;\n";
6157             need_read_reply_label := true;
6158             pr "\n";
6159         | _ -> ()
6160       ) (snd style);
6161
6162       (* Wait for the reply from the remote end. *)
6163       if !need_read_reply_label then pr " read_reply:\n";
6164       pr "  memset (&hdr, 0, sizeof hdr);\n";
6165       pr "  memset (&err, 0, sizeof err);\n";
6166       if has_ret then pr "  memset (&ret, 0, sizeof ret);\n";
6167       pr "\n";
6168       pr "  r = guestfs___recv (g, \"%s\", &hdr, &err,\n        " shortname;
6169       if not has_ret then
6170         pr "NULL, NULL"
6171       else
6172         pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" shortname;
6173       pr ");\n";
6174
6175       pr "  if (r == -1) {\n";
6176       pr "    guestfs___end_busy (g);\n";
6177       pr "    return %s;\n" error_code;
6178       pr "  }\n";
6179       pr "\n";
6180
6181       pr "  if (check_reply_header (g, &hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
6182         (String.uppercase shortname);
6183       pr "    guestfs___end_busy (g);\n";
6184       pr "    return %s;\n" error_code;
6185       pr "  }\n";
6186       pr "\n";
6187
6188       pr "  if (hdr.status == GUESTFS_STATUS_ERROR) {\n";
6189       pr "    error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" shortname;
6190       pr "    free (err.error_message);\n";
6191       pr "    guestfs___end_busy (g);\n";
6192       pr "    return %s;\n" error_code;
6193       pr "  }\n";
6194       pr "\n";
6195
6196       (* Expecting to receive further files (FileOut)? *)
6197       List.iter (
6198         function
6199         | FileOut n ->
6200             pr "  if (guestfs___recv_file (g, %s) == -1) {\n" n;
6201             pr "    guestfs___end_busy (g);\n";
6202             pr "    return %s;\n" error_code;
6203             pr "  }\n";
6204             pr "\n";
6205         | _ -> ()
6206       ) (snd style);
6207
6208       pr "  guestfs___end_busy (g);\n";
6209
6210       (match fst style with
6211        | RErr -> pr "  return 0;\n"
6212        | RInt n | RInt64 n | RBool n ->
6213            pr "  return ret.%s;\n" n
6214        | RConstString _ | RConstOptString _ ->
6215            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
6216        | RString n ->
6217            pr "  return ret.%s; /* caller will free */\n" n
6218        | RStringList n | RHashtable n ->
6219            pr "  /* caller will free this, but we need to add a NULL entry */\n";
6220            pr "  ret.%s.%s_val =\n" n n;
6221            pr "    safe_realloc (g, ret.%s.%s_val,\n" n n;
6222            pr "                  sizeof (char *) * (ret.%s.%s_len + 1));\n"
6223              n n;
6224            pr "  ret.%s.%s_val[ret.%s.%s_len] = NULL;\n" n n n n;
6225            pr "  return ret.%s.%s_val;\n" n n
6226        | RStruct (n, _) ->
6227            pr "  /* caller will free this */\n";
6228            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
6229        | RStructList (n, _) ->
6230            pr "  /* caller will free this */\n";
6231            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
6232        | RBufferOut n ->
6233            pr "  /* RBufferOut is tricky: If the buffer is zero-length, then\n";
6234            pr "   * _val might be NULL here.  To make the API saner for\n";
6235            pr "   * callers, we turn this case into a unique pointer (using\n";
6236            pr "   * malloc(1)).\n";
6237            pr "   */\n";
6238            pr "  if (ret.%s.%s_len > 0) {\n" n n;
6239            pr "    *size_r = ret.%s.%s_len;\n" n n;
6240            pr "    return ret.%s.%s_val; /* caller will free */\n" n n;
6241            pr "  } else {\n";
6242            pr "    free (ret.%s.%s_val);\n" n n;
6243            pr "    char *p = safe_malloc (g, 1);\n";
6244            pr "    *size_r = ret.%s.%s_len;\n" n n;
6245            pr "    return p;\n";
6246            pr "  }\n";
6247       );
6248
6249       pr "}\n\n"
6250   ) daemon_functions;
6251
6252   (* Functions to free structures. *)
6253   pr "/* Structure-freeing functions.  These rely on the fact that the\n";
6254   pr " * structure format is identical to the XDR format.  See note in\n";
6255   pr " * generator.ml.\n";
6256   pr " */\n";
6257   pr "\n";
6258
6259   List.iter (
6260     fun (typ, _) ->
6261       pr "void\n";
6262       pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
6263       pr "{\n";
6264       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
6265       pr "  free (x);\n";
6266       pr "}\n";
6267       pr "\n";
6268
6269       pr "void\n";
6270       pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
6271       pr "{\n";
6272       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
6273       pr "  free (x);\n";
6274       pr "}\n";
6275       pr "\n";
6276
6277   ) structs;
6278
6279 (* Generate daemon/actions.h. *)
6280 and generate_daemon_actions_h () =
6281   generate_header CStyle GPLv2plus;
6282
6283   pr "#include \"../src/guestfs_protocol.h\"\n";
6284   pr "\n";
6285
6286   List.iter (
6287     fun (name, style, _, _, _, _, _) ->
6288       generate_prototype
6289         ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
6290         name style;
6291   ) daemon_functions
6292
6293 (* Generate the linker script which controls the visibility of
6294  * symbols in the public ABI and ensures no other symbols get
6295  * exported accidentally.
6296  *)
6297 and generate_linker_script () =
6298   generate_header HashStyle GPLv2plus;
6299
6300   let globals = [
6301     "guestfs_create";
6302     "guestfs_close";
6303     "guestfs_get_error_handler";
6304     "guestfs_get_out_of_memory_handler";
6305     "guestfs_last_error";
6306     "guestfs_set_error_handler";
6307     "guestfs_set_launch_done_callback";
6308     "guestfs_set_log_message_callback";
6309     "guestfs_set_out_of_memory_handler";
6310     "guestfs_set_subprocess_quit_callback";
6311
6312     (* Unofficial parts of the API: the bindings code use these
6313      * functions, so it is useful to export them.
6314      *)
6315     "guestfs_safe_calloc";
6316     "guestfs_safe_malloc";
6317   ] in
6318   let functions =
6319     List.map (fun (name, _, _, _, _, _, _) -> "guestfs_" ^ name)
6320       all_functions in
6321   let structs =
6322     List.concat (
6323       List.map (fun (typ, _) ->
6324                   ["guestfs_free_" ^ typ; "guestfs_free_" ^ typ ^ "_list"])
6325         structs
6326     ) in
6327   let globals = List.sort compare (globals @ functions @ structs) in
6328
6329   pr "{\n";
6330   pr "    global:\n";
6331   List.iter (pr "        %s;\n") globals;
6332   pr "\n";
6333
6334   pr "    local:\n";
6335   pr "        *;\n";
6336   pr "};\n"
6337
6338 (* Generate the server-side stubs. *)
6339 and generate_daemon_actions () =
6340   generate_header CStyle GPLv2plus;
6341
6342   pr "#include <config.h>\n";
6343   pr "\n";
6344   pr "#include <stdio.h>\n";
6345   pr "#include <stdlib.h>\n";
6346   pr "#include <string.h>\n";
6347   pr "#include <inttypes.h>\n";
6348   pr "#include <rpc/types.h>\n";
6349   pr "#include <rpc/xdr.h>\n";
6350   pr "\n";
6351   pr "#include \"daemon.h\"\n";
6352   pr "#include \"c-ctype.h\"\n";
6353   pr "#include \"../src/guestfs_protocol.h\"\n";
6354   pr "#include \"actions.h\"\n";
6355   pr "\n";
6356
6357   List.iter (
6358     fun (name, style, _, _, _, _, _) ->
6359       (* Generate server-side stubs. *)
6360       pr "static void %s_stub (XDR *xdr_in)\n" name;
6361       pr "{\n";
6362       let error_code =
6363         match fst style with
6364         | RErr | RInt _ -> pr "  int r;\n"; "-1"
6365         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
6366         | RBool _ -> pr "  int r;\n"; "-1"
6367         | RConstString _ | RConstOptString _ ->
6368             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
6369         | RString _ -> pr "  char *r;\n"; "NULL"
6370         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
6371         | RStruct (_, typ) -> pr "  guestfs_int_%s *r;\n" typ; "NULL"
6372         | RStructList (_, typ) -> pr "  guestfs_int_%s_list *r;\n" typ; "NULL"
6373         | RBufferOut _ ->
6374             pr "  size_t size = 1;\n";
6375             pr "  char *r;\n";
6376             "NULL" in
6377
6378       (match snd style with
6379        | [] -> ()
6380        | args ->
6381            pr "  struct guestfs_%s_args args;\n" name;
6382            List.iter (
6383              function
6384              | Device n | Dev_or_Path n
6385              | Pathname n
6386              | String n -> ()
6387              | OptString n -> pr "  char *%s;\n" n
6388              | StringList n | DeviceList n -> pr "  char **%s;\n" n
6389              | Bool n -> pr "  int %s;\n" n
6390              | Int n -> pr "  int %s;\n" n
6391              | Int64 n -> pr "  int64_t %s;\n" n
6392              | FileIn _ | FileOut _ -> ()
6393              | BufferIn n ->
6394                  pr "  const char *%s;\n" n;
6395                  pr "  size_t %s_size;\n" n
6396            ) args
6397       );
6398       pr "\n";
6399
6400       let is_filein =
6401         List.exists (function FileIn _ -> true | _ -> false) (snd style) in
6402
6403       (match snd style with
6404        | [] -> ()
6405        | args ->
6406            pr "  memset (&args, 0, sizeof args);\n";
6407            pr "\n";
6408            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
6409            if is_filein then
6410              pr "    if (cancel_receive () != -2)\n";
6411            pr "      reply_with_error (\"daemon failed to decode procedure arguments\");\n";
6412            pr "    goto done;\n";
6413            pr "  }\n";
6414            let pr_args n =
6415              pr "  char *%s = args.%s;\n" n n
6416            in
6417            let pr_list_handling_code n =
6418              pr "  %s = realloc (args.%s.%s_val,\n" n n n;
6419              pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
6420              pr "  if (%s == NULL) {\n" n;
6421              if is_filein then
6422                pr "    if (cancel_receive () != -2)\n";
6423              pr "      reply_with_perror (\"realloc\");\n";
6424              pr "    goto done;\n";
6425              pr "  }\n";
6426              pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
6427              pr "  args.%s.%s_val = %s;\n" n n n;
6428            in
6429            List.iter (
6430              function
6431              | Pathname n ->
6432                  pr_args n;
6433                  pr "  ABS_PATH (%s, %s, goto done);\n"
6434                    n (if is_filein then "cancel_receive ()" else "0");
6435              | Device n ->
6436                  pr_args n;
6437                  pr "  RESOLVE_DEVICE (%s, %s, goto done);\n"
6438                    n (if is_filein then "cancel_receive ()" else "0");
6439              | Dev_or_Path n ->
6440                  pr_args n;
6441                  pr "  REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, %s, goto done);\n"
6442                    n (if is_filein then "cancel_receive ()" else "0");
6443              | String n -> pr_args n
6444              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
6445              | StringList n ->
6446                  pr_list_handling_code n;
6447              | DeviceList n ->
6448                  pr_list_handling_code n;
6449                  pr "  /* Ensure that each is a device,\n";
6450                  pr "   * and perform device name translation. */\n";
6451                  pr "  { int pvi; for (pvi = 0; physvols[pvi] != NULL; ++pvi)\n";
6452                  pr "    RESOLVE_DEVICE (physvols[pvi], %s, goto done);\n"
6453                    (if is_filein then "cancel_receive ()" else "0");
6454                  pr "  }\n";
6455              | Bool n -> pr "  %s = args.%s;\n" n n
6456              | Int n -> pr "  %s = args.%s;\n" n n
6457              | Int64 n -> pr "  %s = args.%s;\n" n n
6458              | FileIn _ | FileOut _ -> ()
6459              | BufferIn n ->
6460                  pr "  %s = args.%s.%s_val;\n" n n n;
6461                  pr "  %s_size = args.%s.%s_len;\n" n n n
6462            ) args;
6463            pr "\n"
6464       );
6465
6466       (* this is used at least for do_equal *)
6467       if List.exists (function Pathname _ -> true | _ -> false) (snd style) then (
6468         (* Emit NEED_ROOT just once, even when there are two or
6469            more Pathname args *)
6470         pr "  NEED_ROOT (%s, goto done);\n"
6471           (if is_filein then "cancel_receive ()" else "0");
6472       );
6473
6474       (* Don't want to call the impl with any FileIn or FileOut
6475        * parameters, since these go "outside" the RPC protocol.
6476        *)
6477       let args' =
6478         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
6479           (snd style) in
6480       pr "  r = do_%s " name;
6481       generate_c_call_args (fst style, args');
6482       pr ";\n";
6483
6484       (match fst style with
6485        | RErr | RInt _ | RInt64 _ | RBool _
6486        | RConstString _ | RConstOptString _
6487        | RString _ | RStringList _ | RHashtable _
6488        | RStruct (_, _) | RStructList (_, _) ->
6489            pr "  if (r == %s)\n" error_code;
6490            pr "    /* do_%s has already called reply_with_error */\n" name;
6491            pr "    goto done;\n";
6492            pr "\n"
6493        | RBufferOut _ ->
6494            pr "  /* size == 0 && r == NULL could be a non-error case (just\n";
6495            pr "   * an ordinary zero-length buffer), so be careful ...\n";
6496            pr "   */\n";
6497            pr "  if (size == 1 && r == %s)\n" error_code;
6498            pr "    /* do_%s has already called reply_with_error */\n" name;
6499            pr "    goto done;\n";
6500            pr "\n"
6501       );
6502
6503       (* If there are any FileOut parameters, then the impl must
6504        * send its own reply.
6505        *)
6506       let no_reply =
6507         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
6508       if no_reply then
6509         pr "  /* do_%s has already sent a reply */\n" name
6510       else (
6511         match fst style with
6512         | RErr -> pr "  reply (NULL, NULL);\n"
6513         | RInt n | RInt64 n | RBool n ->
6514             pr "  struct guestfs_%s_ret ret;\n" name;
6515             pr "  ret.%s = r;\n" n;
6516             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6517               name
6518         | RConstString _ | RConstOptString _ ->
6519             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
6520         | RString n ->
6521             pr "  struct guestfs_%s_ret ret;\n" name;
6522             pr "  ret.%s = r;\n" n;
6523             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6524               name;
6525             pr "  free (r);\n"
6526         | RStringList n | RHashtable n ->
6527             pr "  struct guestfs_%s_ret ret;\n" name;
6528             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
6529             pr "  ret.%s.%s_val = r;\n" n n;
6530             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6531               name;
6532             pr "  free_strings (r);\n"
6533         | RStruct (n, _) ->
6534             pr "  struct guestfs_%s_ret ret;\n" name;
6535             pr "  ret.%s = *r;\n" n;
6536             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6537               name;
6538             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6539               name
6540         | RStructList (n, _) ->
6541             pr "  struct guestfs_%s_ret ret;\n" name;
6542             pr "  ret.%s = *r;\n" n;
6543             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6544               name;
6545             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
6546               name
6547         | RBufferOut n ->
6548             pr "  struct guestfs_%s_ret ret;\n" name;
6549             pr "  ret.%s.%s_val = r;\n" n n;
6550             pr "  ret.%s.%s_len = size;\n" n n;
6551             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
6552               name;
6553             pr "  free (r);\n"
6554       );
6555
6556       (* Free the args. *)
6557       pr "done:\n";
6558       (match snd style with
6559        | [] -> ()
6560        | _ ->
6561            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
6562              name
6563       );
6564       pr "  return;\n";
6565       pr "}\n\n";
6566   ) daemon_functions;
6567
6568   (* Dispatch function. *)
6569   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
6570   pr "{\n";
6571   pr "  switch (proc_nr) {\n";
6572
6573   List.iter (
6574     fun (name, style, _, _, _, _, _) ->
6575       pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
6576       pr "      %s_stub (xdr_in);\n" name;
6577       pr "      break;\n"
6578   ) daemon_functions;
6579
6580   pr "    default:\n";
6581   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";
6582   pr "  }\n";
6583   pr "}\n";
6584   pr "\n";
6585
6586   (* LVM columns and tokenization functions. *)
6587   (* XXX This generates crap code.  We should rethink how we
6588    * do this parsing.
6589    *)
6590   List.iter (
6591     function
6592     | typ, cols ->
6593         pr "static const char *lvm_%s_cols = \"%s\";\n"
6594           typ (String.concat "," (List.map fst cols));
6595         pr "\n";
6596
6597         pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
6598         pr "{\n";
6599         pr "  char *tok, *p, *next;\n";
6600         pr "  int i, j;\n";
6601         pr "\n";
6602         (*
6603           pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
6604           pr "\n";
6605         *)
6606         pr "  if (!str) {\n";
6607         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
6608         pr "    return -1;\n";
6609         pr "  }\n";
6610         pr "  if (!*str || c_isspace (*str)) {\n";
6611         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
6612         pr "    return -1;\n";
6613         pr "  }\n";
6614         pr "  tok = str;\n";
6615         List.iter (
6616           fun (name, coltype) ->
6617             pr "  if (!tok) {\n";
6618             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
6619             pr "    return -1;\n";
6620             pr "  }\n";
6621             pr "  p = strchrnul (tok, ',');\n";
6622             pr "  if (*p) next = p+1; else next = NULL;\n";
6623             pr "  *p = '\\0';\n";
6624             (match coltype with
6625              | FString ->
6626                  pr "  r->%s = strdup (tok);\n" name;
6627                  pr "  if (r->%s == NULL) {\n" name;
6628                  pr "    perror (\"strdup\");\n";
6629                  pr "    return -1;\n";
6630                  pr "  }\n"
6631              | FUUID ->
6632                  pr "  for (i = j = 0; i < 32; ++j) {\n";
6633                  pr "    if (tok[j] == '\\0') {\n";
6634                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
6635                  pr "      return -1;\n";
6636                  pr "    } else if (tok[j] != '-')\n";
6637                  pr "      r->%s[i++] = tok[j];\n" name;
6638                  pr "  }\n";
6639              | FBytes ->
6640                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
6641                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6642                  pr "    return -1;\n";
6643                  pr "  }\n";
6644              | FInt64 ->
6645                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
6646                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6647                  pr "    return -1;\n";
6648                  pr "  }\n";
6649              | FOptPercent ->
6650                  pr "  if (tok[0] == '\\0')\n";
6651                  pr "    r->%s = -1;\n" name;
6652                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
6653                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
6654                  pr "    return -1;\n";
6655                  pr "  }\n";
6656              | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
6657                  assert false (* can never be an LVM column *)
6658             );
6659             pr "  tok = next;\n";
6660         ) cols;
6661
6662         pr "  if (tok != NULL) {\n";
6663         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
6664         pr "    return -1;\n";
6665         pr "  }\n";
6666         pr "  return 0;\n";
6667         pr "}\n";
6668         pr "\n";
6669
6670         pr "guestfs_int_lvm_%s_list *\n" typ;
6671         pr "parse_command_line_%ss (void)\n" typ;
6672         pr "{\n";
6673         pr "  char *out, *err;\n";
6674         pr "  char *p, *pend;\n";
6675         pr "  int r, i;\n";
6676         pr "  guestfs_int_lvm_%s_list *ret;\n" typ;
6677         pr "  void *newp;\n";
6678         pr "\n";
6679         pr "  ret = malloc (sizeof *ret);\n";
6680         pr "  if (!ret) {\n";
6681         pr "    reply_with_perror (\"malloc\");\n";
6682         pr "    return NULL;\n";
6683         pr "  }\n";
6684         pr "\n";
6685         pr "  ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
6686         pr "  ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
6687         pr "\n";
6688         pr "  r = command (&out, &err,\n";
6689         pr "           \"lvm\", \"%ss\",\n" typ;
6690         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
6691         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
6692         pr "  if (r == -1) {\n";
6693         pr "    reply_with_error (\"%%s\", err);\n";
6694         pr "    free (out);\n";
6695         pr "    free (err);\n";
6696         pr "    free (ret);\n";
6697         pr "    return NULL;\n";
6698         pr "  }\n";
6699         pr "\n";
6700         pr "  free (err);\n";
6701         pr "\n";
6702         pr "  /* Tokenize each line of the output. */\n";
6703         pr "  p = out;\n";
6704         pr "  i = 0;\n";
6705         pr "  while (p) {\n";
6706         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
6707         pr "    if (pend) {\n";
6708         pr "      *pend = '\\0';\n";
6709         pr "      pend++;\n";
6710         pr "    }\n";
6711         pr "\n";
6712         pr "    while (*p && c_isspace (*p))    /* Skip any leading whitespace. */\n";
6713         pr "      p++;\n";
6714         pr "\n";
6715         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
6716         pr "      p = pend;\n";
6717         pr "      continue;\n";
6718         pr "    }\n";
6719         pr "\n";
6720         pr "    /* Allocate some space to store this next entry. */\n";
6721         pr "    newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
6722         pr "                sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
6723         pr "    if (newp == NULL) {\n";
6724         pr "      reply_with_perror (\"realloc\");\n";
6725         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6726         pr "      free (ret);\n";
6727         pr "      free (out);\n";
6728         pr "      return NULL;\n";
6729         pr "    }\n";
6730         pr "    ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
6731         pr "\n";
6732         pr "    /* Tokenize the next entry. */\n";
6733         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
6734         pr "    if (r == -1) {\n";
6735         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
6736         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
6737         pr "      free (ret);\n";
6738         pr "      free (out);\n";
6739         pr "      return NULL;\n";
6740         pr "    }\n";
6741         pr "\n";
6742         pr "    ++i;\n";
6743         pr "    p = pend;\n";
6744         pr "  }\n";
6745         pr "\n";
6746         pr "  ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
6747         pr "\n";
6748         pr "  free (out);\n";
6749         pr "  return ret;\n";
6750         pr "}\n"
6751
6752   ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
6753
6754 (* Generate a list of function names, for debugging in the daemon.. *)
6755 and generate_daemon_names () =
6756   generate_header CStyle GPLv2plus;
6757
6758   pr "#include <config.h>\n";
6759   pr "\n";
6760   pr "#include \"daemon.h\"\n";
6761   pr "\n";
6762
6763   pr "/* This array is indexed by proc_nr.  See guestfs_protocol.x. */\n";
6764   pr "const char *function_names[] = {\n";
6765   List.iter (
6766     fun (name, _, proc_nr, _, _, _, _) -> pr "  [%d] = \"%s\",\n" proc_nr name
6767   ) daemon_functions;
6768   pr "};\n";
6769
6770 (* Generate the optional groups for the daemon to implement
6771  * guestfs_available.
6772  *)
6773 and generate_daemon_optgroups_c () =
6774   generate_header CStyle GPLv2plus;
6775
6776   pr "#include <config.h>\n";
6777   pr "\n";
6778   pr "#include \"daemon.h\"\n";
6779   pr "#include \"optgroups.h\"\n";
6780   pr "\n";
6781
6782   pr "struct optgroup optgroups[] = {\n";
6783   List.iter (
6784     fun (group, _) ->
6785       pr "  { \"%s\", optgroup_%s_available },\n" group group
6786   ) optgroups;
6787   pr "  { NULL, NULL }\n";
6788   pr "};\n"
6789
6790 and generate_daemon_optgroups_h () =
6791   generate_header CStyle GPLv2plus;
6792
6793   List.iter (
6794     fun (group, _) ->
6795       pr "extern int optgroup_%s_available (void);\n" group
6796   ) optgroups
6797
6798 (* Generate the tests. *)
6799 and generate_tests () =
6800   generate_header CStyle GPLv2plus;
6801
6802   pr "\
6803 #include <stdio.h>
6804 #include <stdlib.h>
6805 #include <string.h>
6806 #include <unistd.h>
6807 #include <sys/types.h>
6808 #include <fcntl.h>
6809
6810 #include \"guestfs.h\"
6811 #include \"guestfs-internal.h\"
6812
6813 static guestfs_h *g;
6814 static int suppress_error = 0;
6815
6816 static void print_error (guestfs_h *g, void *data, const char *msg)
6817 {
6818   if (!suppress_error)
6819     fprintf (stderr, \"%%s\\n\", msg);
6820 }
6821
6822 /* FIXME: nearly identical code appears in fish.c */
6823 static void print_strings (char *const *argv)
6824 {
6825   int argc;
6826
6827   for (argc = 0; argv[argc] != NULL; ++argc)
6828     printf (\"\\t%%s\\n\", argv[argc]);
6829 }
6830
6831 /*
6832 static void print_table (char const *const *argv)
6833 {
6834   int i;
6835
6836   for (i = 0; argv[i] != NULL; i += 2)
6837     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
6838 }
6839 */
6840
6841 static int
6842 is_available (const char *group)
6843 {
6844   const char *groups[] = { group, NULL };
6845   int r;
6846
6847   suppress_error = 1;
6848   r = guestfs_available (g, (char **) groups);
6849   suppress_error = 0;
6850
6851   return r == 0;
6852 }
6853
6854 ";
6855
6856   (* Generate a list of commands which are not tested anywhere. *)
6857   pr "static void no_test_warnings (void)\n";
6858   pr "{\n";
6859
6860   let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
6861   List.iter (
6862     fun (_, _, _, _, tests, _, _) ->
6863       let tests = filter_map (
6864         function
6865         | (_, (Always|If _|Unless _), test) -> Some test
6866         | (_, Disabled, _) -> None
6867       ) tests in
6868       let seq = List.concat (List.map seq_of_test tests) in
6869       let cmds_tested = List.map List.hd seq in
6870       List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
6871   ) all_functions;
6872
6873   List.iter (
6874     fun (name, _, _, _, _, _, _) ->
6875       if not (Hashtbl.mem hash name) then
6876         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
6877   ) all_functions;
6878
6879   pr "}\n";
6880   pr "\n";
6881
6882   (* Generate the actual tests.  Note that we generate the tests
6883    * in reverse order, deliberately, so that (in general) the
6884    * newest tests run first.  This makes it quicker and easier to
6885    * debug them.
6886    *)
6887   let test_names =
6888     List.map (
6889       fun (name, _, _, flags, tests, _, _) ->
6890         mapi (generate_one_test name flags) tests
6891     ) (List.rev all_functions) in
6892   let test_names = List.concat test_names in
6893   let nr_tests = List.length test_names in
6894
6895   pr "\
6896 int main (int argc, char *argv[])
6897 {
6898   char c = 0;
6899   unsigned long int n_failed = 0;
6900   const char *filename;
6901   int fd;
6902   int nr_tests, test_num = 0;
6903
6904   setbuf (stdout, NULL);
6905
6906   no_test_warnings ();
6907
6908   g = guestfs_create ();
6909   if (g == NULL) {
6910     printf (\"guestfs_create FAILED\\n\");
6911     exit (EXIT_FAILURE);
6912   }
6913
6914   guestfs_set_error_handler (g, print_error, NULL);
6915
6916   guestfs_set_path (g, \"../appliance\");
6917
6918   filename = \"test1.img\";
6919   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6920   if (fd == -1) {
6921     perror (filename);
6922     exit (EXIT_FAILURE);
6923   }
6924   if (lseek (fd, %d, SEEK_SET) == -1) {
6925     perror (\"lseek\");
6926     close (fd);
6927     unlink (filename);
6928     exit (EXIT_FAILURE);
6929   }
6930   if (write (fd, &c, 1) == -1) {
6931     perror (\"write\");
6932     close (fd);
6933     unlink (filename);
6934     exit (EXIT_FAILURE);
6935   }
6936   if (close (fd) == -1) {
6937     perror (filename);
6938     unlink (filename);
6939     exit (EXIT_FAILURE);
6940   }
6941   if (guestfs_add_drive (g, filename) == -1) {
6942     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6943     exit (EXIT_FAILURE);
6944   }
6945
6946   filename = \"test2.img\";
6947   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6948   if (fd == -1) {
6949     perror (filename);
6950     exit (EXIT_FAILURE);
6951   }
6952   if (lseek (fd, %d, SEEK_SET) == -1) {
6953     perror (\"lseek\");
6954     close (fd);
6955     unlink (filename);
6956     exit (EXIT_FAILURE);
6957   }
6958   if (write (fd, &c, 1) == -1) {
6959     perror (\"write\");
6960     close (fd);
6961     unlink (filename);
6962     exit (EXIT_FAILURE);
6963   }
6964   if (close (fd) == -1) {
6965     perror (filename);
6966     unlink (filename);
6967     exit (EXIT_FAILURE);
6968   }
6969   if (guestfs_add_drive (g, filename) == -1) {
6970     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6971     exit (EXIT_FAILURE);
6972   }
6973
6974   filename = \"test3.img\";
6975   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
6976   if (fd == -1) {
6977     perror (filename);
6978     exit (EXIT_FAILURE);
6979   }
6980   if (lseek (fd, %d, SEEK_SET) == -1) {
6981     perror (\"lseek\");
6982     close (fd);
6983     unlink (filename);
6984     exit (EXIT_FAILURE);
6985   }
6986   if (write (fd, &c, 1) == -1) {
6987     perror (\"write\");
6988     close (fd);
6989     unlink (filename);
6990     exit (EXIT_FAILURE);
6991   }
6992   if (close (fd) == -1) {
6993     perror (filename);
6994     unlink (filename);
6995     exit (EXIT_FAILURE);
6996   }
6997   if (guestfs_add_drive (g, filename) == -1) {
6998     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
6999     exit (EXIT_FAILURE);
7000   }
7001
7002   if (guestfs_add_drive_ro (g, \"../images/test.iso\") == -1) {
7003     printf (\"guestfs_add_drive_ro ../images/test.iso FAILED\\n\");
7004     exit (EXIT_FAILURE);
7005   }
7006
7007   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
7008   alarm (600);
7009
7010   if (guestfs_launch (g) == -1) {
7011     printf (\"guestfs_launch FAILED\\n\");
7012     exit (EXIT_FAILURE);
7013   }
7014
7015   /* Cancel previous alarm. */
7016   alarm (0);
7017
7018   nr_tests = %d;
7019
7020 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
7021
7022   iteri (
7023     fun i test_name ->
7024       pr "  test_num++;\n";
7025       pr "  if (guestfs_get_verbose (g))\n";
7026       pr "    printf (\"-------------------------------------------------------------------------------\\n\");\n";
7027       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
7028       pr "  if (%s () == -1) {\n" test_name;
7029       pr "    printf (\"%s FAILED\\n\");\n" test_name;
7030       pr "    n_failed++;\n";
7031       pr "  }\n";
7032   ) test_names;
7033   pr "\n";
7034
7035   pr "  guestfs_close (g);\n";
7036   pr "  unlink (\"test1.img\");\n";
7037   pr "  unlink (\"test2.img\");\n";
7038   pr "  unlink (\"test3.img\");\n";
7039   pr "\n";
7040
7041   pr "  if (n_failed > 0) {\n";
7042   pr "    printf (\"***** %%lu / %%d tests FAILED *****\\n\", n_failed, nr_tests);\n";
7043   pr "    exit (EXIT_FAILURE);\n";
7044   pr "  }\n";
7045   pr "\n";
7046
7047   pr "  exit (EXIT_SUCCESS);\n";
7048   pr "}\n"
7049
7050 and generate_one_test name flags i (init, prereq, test) =
7051   let test_name = sprintf "test_%s_%d" name i in
7052
7053   pr "\
7054 static int %s_skip (void)
7055 {
7056   const char *str;
7057
7058   str = getenv (\"TEST_ONLY\");
7059   if (str)
7060     return strstr (str, \"%s\") == NULL;
7061   str = getenv (\"SKIP_%s\");
7062   if (str && STREQ (str, \"1\")) return 1;
7063   str = getenv (\"SKIP_TEST_%s\");
7064   if (str && STREQ (str, \"1\")) return 1;
7065   return 0;
7066 }
7067
7068 " test_name name (String.uppercase test_name) (String.uppercase name);
7069
7070   (match prereq with
7071    | Disabled | Always -> ()
7072    | If code | Unless code ->
7073        pr "static int %s_prereq (void)\n" test_name;
7074        pr "{\n";
7075        pr "  %s\n" code;
7076        pr "}\n";
7077        pr "\n";
7078   );
7079
7080   pr "\
7081 static int %s (void)
7082 {
7083   if (%s_skip ()) {
7084     printf (\"        %%s skipped (reason: environment variable set)\\n\", \"%s\");
7085     return 0;
7086   }
7087
7088 " test_name test_name test_name;
7089
7090   (* Optional functions should only be tested if the relevant
7091    * support is available in the daemon.
7092    *)
7093   List.iter (
7094     function
7095     | Optional group ->
7096         pr "  if (!is_available (\"%s\")) {\n" group;
7097         pr "    printf (\"        %%s skipped (reason: group %%s not available in daemon)\\n\", \"%s\", \"%s\");\n" test_name group;
7098         pr "    return 0;\n";
7099         pr "  }\n";
7100     | _ -> ()
7101   ) flags;
7102
7103   (match prereq with
7104    | Disabled ->
7105        pr "  printf (\"        %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
7106    | If _ ->
7107        pr "  if (! %s_prereq ()) {\n" test_name;
7108        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
7109        pr "    return 0;\n";
7110        pr "  }\n";
7111        pr "\n";
7112        generate_one_test_body name i test_name init test;
7113    | Unless _ ->
7114        pr "  if (%s_prereq ()) {\n" test_name;
7115        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
7116        pr "    return 0;\n";
7117        pr "  }\n";
7118        pr "\n";
7119        generate_one_test_body name i test_name init test;
7120    | Always ->
7121        generate_one_test_body name i test_name init test
7122   );
7123
7124   pr "  return 0;\n";
7125   pr "}\n";
7126   pr "\n";
7127   test_name
7128
7129 and generate_one_test_body name i test_name init test =
7130   (match init with
7131    | InitNone (* XXX at some point, InitNone and InitEmpty became
7132                * folded together as the same thing.  Really we should
7133                * make InitNone do nothing at all, but the tests may
7134                * need to be checked to make sure this is OK.
7135                *)
7136    | InitEmpty ->
7137        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
7138        List.iter (generate_test_command_call test_name)
7139          [["blockdev_setrw"; "/dev/sda"];
7140           ["umount_all"];
7141           ["lvm_remove_all"]]
7142    | InitPartition ->
7143        pr "  /* InitPartition for %s: create /dev/sda1 */\n" test_name;
7144        List.iter (generate_test_command_call test_name)
7145          [["blockdev_setrw"; "/dev/sda"];
7146           ["umount_all"];
7147           ["lvm_remove_all"];
7148           ["part_disk"; "/dev/sda"; "mbr"]]
7149    | InitBasicFS ->
7150        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
7151        List.iter (generate_test_command_call test_name)
7152          [["blockdev_setrw"; "/dev/sda"];
7153           ["umount_all"];
7154           ["lvm_remove_all"];
7155           ["part_disk"; "/dev/sda"; "mbr"];
7156           ["mkfs"; "ext2"; "/dev/sda1"];
7157           ["mount_options"; ""; "/dev/sda1"; "/"]]
7158    | InitBasicFSonLVM ->
7159        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
7160          test_name;
7161        List.iter (generate_test_command_call test_name)
7162          [["blockdev_setrw"; "/dev/sda"];
7163           ["umount_all"];
7164           ["lvm_remove_all"];
7165           ["part_disk"; "/dev/sda"; "mbr"];
7166           ["pvcreate"; "/dev/sda1"];
7167           ["vgcreate"; "VG"; "/dev/sda1"];
7168           ["lvcreate"; "LV"; "VG"; "8"];
7169           ["mkfs"; "ext2"; "/dev/VG/LV"];
7170           ["mount_options"; ""; "/dev/VG/LV"; "/"]]
7171    | InitISOFS ->
7172        pr "  /* InitISOFS for %s */\n" test_name;
7173        List.iter (generate_test_command_call test_name)
7174          [["blockdev_setrw"; "/dev/sda"];
7175           ["umount_all"];
7176           ["lvm_remove_all"];
7177           ["mount_ro"; "/dev/sdd"; "/"]]
7178   );
7179
7180   let get_seq_last = function
7181     | [] ->
7182         failwithf "%s: you cannot use [] (empty list) when expecting a command"
7183           test_name
7184     | seq ->
7185         let seq = List.rev seq in
7186         List.rev (List.tl seq), List.hd seq
7187   in
7188
7189   match test with
7190   | TestRun seq ->
7191       pr "  /* TestRun for %s (%d) */\n" name i;
7192       List.iter (generate_test_command_call test_name) seq
7193   | TestOutput (seq, expected) ->
7194       pr "  /* TestOutput for %s (%d) */\n" name i;
7195       pr "  const char *expected = \"%s\";\n" (c_quote expected);
7196       let seq, last = get_seq_last seq in
7197       let test () =
7198         pr "    if (STRNEQ (r, expected)) {\n";
7199         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
7200         pr "      return -1;\n";
7201         pr "    }\n"
7202       in
7203       List.iter (generate_test_command_call test_name) seq;
7204       generate_test_command_call ~test test_name last
7205   | TestOutputList (seq, expected) ->
7206       pr "  /* TestOutputList for %s (%d) */\n" name i;
7207       let seq, last = get_seq_last seq in
7208       let test () =
7209         iteri (
7210           fun i str ->
7211             pr "    if (!r[%d]) {\n" i;
7212             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
7213             pr "      print_strings (r);\n";
7214             pr "      return -1;\n";
7215             pr "    }\n";
7216             pr "    {\n";
7217             pr "      const char *expected = \"%s\";\n" (c_quote str);
7218             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
7219             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
7220             pr "        return -1;\n";
7221             pr "      }\n";
7222             pr "    }\n"
7223         ) expected;
7224         pr "    if (r[%d] != NULL) {\n" (List.length expected);
7225         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
7226           test_name;
7227         pr "      print_strings (r);\n";
7228         pr "      return -1;\n";
7229         pr "    }\n"
7230       in
7231       List.iter (generate_test_command_call test_name) seq;
7232       generate_test_command_call ~test test_name last
7233   | TestOutputListOfDevices (seq, expected) ->
7234       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
7235       let seq, last = get_seq_last seq in
7236       let test () =
7237         iteri (
7238           fun i str ->
7239             pr "    if (!r[%d]) {\n" i;
7240             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
7241             pr "      print_strings (r);\n";
7242             pr "      return -1;\n";
7243             pr "    }\n";
7244             pr "    {\n";
7245             pr "      const char *expected = \"%s\";\n" (c_quote str);
7246             pr "      r[%d][5] = 's';\n" i;
7247             pr "      if (STRNEQ (r[%d], expected)) {\n" i;
7248             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
7249             pr "        return -1;\n";
7250             pr "      }\n";
7251             pr "    }\n"
7252         ) expected;
7253         pr "    if (r[%d] != NULL) {\n" (List.length expected);
7254         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
7255           test_name;
7256         pr "      print_strings (r);\n";
7257         pr "      return -1;\n";
7258         pr "    }\n"
7259       in
7260       List.iter (generate_test_command_call test_name) seq;
7261       generate_test_command_call ~test test_name last
7262   | TestOutputInt (seq, expected) ->
7263       pr "  /* TestOutputInt for %s (%d) */\n" name i;
7264       let seq, last = get_seq_last seq in
7265       let test () =
7266         pr "    if (r != %d) {\n" expected;
7267         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
7268           test_name expected;
7269         pr "               (int) r);\n";
7270         pr "      return -1;\n";
7271         pr "    }\n"
7272       in
7273       List.iter (generate_test_command_call test_name) seq;
7274       generate_test_command_call ~test test_name last
7275   | TestOutputIntOp (seq, op, expected) ->
7276       pr "  /* TestOutputIntOp for %s (%d) */\n" name i;
7277       let seq, last = get_seq_last seq in
7278       let test () =
7279         pr "    if (! (r %s %d)) {\n" op expected;
7280         pr "      fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
7281           test_name op expected;
7282         pr "               (int) r);\n";
7283         pr "      return -1;\n";
7284         pr "    }\n"
7285       in
7286       List.iter (generate_test_command_call test_name) seq;
7287       generate_test_command_call ~test test_name last
7288   | TestOutputTrue seq ->
7289       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
7290       let seq, last = get_seq_last seq in
7291       let test () =
7292         pr "    if (!r) {\n";
7293         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
7294           test_name;
7295         pr "      return -1;\n";
7296         pr "    }\n"
7297       in
7298       List.iter (generate_test_command_call test_name) seq;
7299       generate_test_command_call ~test test_name last
7300   | TestOutputFalse seq ->
7301       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
7302       let seq, last = get_seq_last seq in
7303       let test () =
7304         pr "    if (r) {\n";
7305         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
7306           test_name;
7307         pr "      return -1;\n";
7308         pr "    }\n"
7309       in
7310       List.iter (generate_test_command_call test_name) seq;
7311       generate_test_command_call ~test test_name last
7312   | TestOutputLength (seq, expected) ->
7313       pr "  /* TestOutputLength for %s (%d) */\n" name i;
7314       let seq, last = get_seq_last seq in
7315       let test () =
7316         pr "    int j;\n";
7317         pr "    for (j = 0; j < %d; ++j)\n" expected;
7318         pr "      if (r[j] == NULL) {\n";
7319         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
7320           test_name;
7321         pr "        print_strings (r);\n";
7322         pr "        return -1;\n";
7323         pr "      }\n";
7324         pr "    if (r[j] != NULL) {\n";
7325         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
7326           test_name;
7327         pr "      print_strings (r);\n";
7328         pr "      return -1;\n";
7329         pr "    }\n"
7330       in
7331       List.iter (generate_test_command_call test_name) seq;
7332       generate_test_command_call ~test test_name last
7333   | TestOutputBuffer (seq, expected) ->
7334       pr "  /* TestOutputBuffer for %s (%d) */\n" name i;
7335       pr "  const char *expected = \"%s\";\n" (c_quote expected);
7336       let seq, last = get_seq_last seq in
7337       let len = String.length expected in
7338       let test () =
7339         pr "    if (size != %d) {\n" len;
7340         pr "      fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
7341         pr "      return -1;\n";
7342         pr "    }\n";
7343         pr "    if (STRNEQLEN (r, expected, size)) {\n";
7344         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
7345         pr "      return -1;\n";
7346         pr "    }\n"
7347       in
7348       List.iter (generate_test_command_call test_name) seq;
7349       generate_test_command_call ~test test_name last
7350   | TestOutputStruct (seq, checks) ->
7351       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
7352       let seq, last = get_seq_last seq in
7353       let test () =
7354         List.iter (
7355           function
7356           | CompareWithInt (field, expected) ->
7357               pr "    if (r->%s != %d) {\n" field expected;
7358               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
7359                 test_name field expected;
7360               pr "               (int) r->%s);\n" field;
7361               pr "      return -1;\n";
7362               pr "    }\n"
7363           | CompareWithIntOp (field, op, expected) ->
7364               pr "    if (!(r->%s %s %d)) {\n" field op expected;
7365               pr "      fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
7366                 test_name field op expected;
7367               pr "               (int) r->%s);\n" field;
7368               pr "      return -1;\n";
7369               pr "    }\n"
7370           | CompareWithString (field, expected) ->
7371               pr "    if (STRNEQ (r->%s, \"%s\")) {\n" field expected;
7372               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
7373                 test_name field expected;
7374               pr "               r->%s);\n" field;
7375               pr "      return -1;\n";
7376               pr "    }\n"
7377           | CompareFieldsIntEq (field1, field2) ->
7378               pr "    if (r->%s != r->%s) {\n" field1 field2;
7379               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
7380                 test_name field1 field2;
7381               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
7382               pr "      return -1;\n";
7383               pr "    }\n"
7384           | CompareFieldsStrEq (field1, field2) ->
7385               pr "    if (STRNEQ (r->%s, r->%s)) {\n" field1 field2;
7386               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
7387                 test_name field1 field2;
7388               pr "               r->%s, r->%s);\n" field1 field2;
7389               pr "      return -1;\n";
7390               pr "    }\n"
7391         ) checks
7392       in
7393       List.iter (generate_test_command_call test_name) seq;
7394       generate_test_command_call ~test test_name last
7395   | TestLastFail seq ->
7396       pr "  /* TestLastFail for %s (%d) */\n" name i;
7397       let seq, last = get_seq_last seq in
7398       List.iter (generate_test_command_call test_name) seq;
7399       generate_test_command_call test_name ~expect_error:true last
7400
7401 (* Generate the code to run a command, leaving the result in 'r'.
7402  * If you expect to get an error then you should set expect_error:true.
7403  *)
7404 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
7405   match cmd with
7406   | [] -> assert false
7407   | name :: args ->
7408       (* Look up the command to find out what args/ret it has. *)
7409       let style =
7410         try
7411           let _, style, _, _, _, _, _ =
7412             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
7413           style
7414         with Not_found ->
7415           failwithf "%s: in test, command %s was not found" test_name name in
7416
7417       if List.length (snd style) <> List.length args then
7418         failwithf "%s: in test, wrong number of args given to %s"
7419           test_name name;
7420
7421       pr "  {\n";
7422
7423       List.iter (
7424         function
7425         | OptString n, "NULL" -> ()
7426         | Pathname n, arg
7427         | Device n, arg
7428         | Dev_or_Path n, arg
7429         | String n, arg
7430         | OptString n, arg ->
7431             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
7432         | BufferIn n, arg ->
7433             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
7434             pr "    size_t %s_size = %d;\n" n (String.length arg)
7435         | Int _, _
7436         | Int64 _, _
7437         | Bool _, _
7438         | FileIn _, _ | FileOut _, _ -> ()
7439         | StringList n, "" | DeviceList n, "" ->
7440             pr "    const char *const %s[1] = { NULL };\n" n
7441         | StringList n, arg | DeviceList n, arg ->
7442             let strs = string_split " " arg in
7443             iteri (
7444               fun i str ->
7445                 pr "    const char *%s_%d = \"%s\";\n" n i (c_quote str);
7446             ) strs;
7447             pr "    const char *const %s[] = {\n" n;
7448             iteri (
7449               fun i _ -> pr "      %s_%d,\n" n i
7450             ) strs;
7451             pr "      NULL\n";
7452             pr "    };\n";
7453       ) (List.combine (snd style) args);
7454
7455       let error_code =
7456         match fst style with
7457         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
7458         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
7459         | RConstString _ | RConstOptString _ ->
7460             pr "    const char *r;\n"; "NULL"
7461         | RString _ -> pr "    char *r;\n"; "NULL"
7462         | RStringList _ | RHashtable _ ->
7463             pr "    char **r;\n";
7464             pr "    int i;\n";
7465             "NULL"
7466         | RStruct (_, typ) ->
7467             pr "    struct guestfs_%s *r;\n" typ; "NULL"
7468         | RStructList (_, typ) ->
7469             pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
7470         | RBufferOut _ ->
7471             pr "    char *r;\n";
7472             pr "    size_t size;\n";
7473             "NULL" in
7474
7475       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
7476       pr "    r = guestfs_%s (g" name;
7477
7478       (* Generate the parameters. *)
7479       List.iter (
7480         function
7481         | OptString _, "NULL" -> pr ", NULL"
7482         | Pathname n, _
7483         | Device n, _ | Dev_or_Path n, _
7484         | String n, _
7485         | OptString n, _ ->
7486             pr ", %s" n
7487         | BufferIn n, _ ->
7488             pr ", %s, %s_size" n n
7489         | FileIn _, arg | FileOut _, arg ->
7490             pr ", \"%s\"" (c_quote arg)
7491         | StringList n, _ | DeviceList n, _ ->
7492             pr ", (char **) %s" n
7493         | Int _, arg ->
7494             let i =
7495               try int_of_string arg
7496               with Failure "int_of_string" ->
7497                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
7498             pr ", %d" i
7499         | Int64 _, arg ->
7500             let i =
7501               try Int64.of_string arg
7502               with Failure "int_of_string" ->
7503                 failwithf "%s: expecting an int64, but got '%s'" test_name arg in
7504             pr ", %Ld" i
7505         | Bool _, arg ->
7506             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
7507       ) (List.combine (snd style) args);
7508
7509       (match fst style with
7510        | RBufferOut _ -> pr ", &size"
7511        | _ -> ()
7512       );
7513
7514       pr ");\n";
7515
7516       if not expect_error then
7517         pr "    if (r == %s)\n" error_code
7518       else
7519         pr "    if (r != %s)\n" error_code;
7520       pr "      return -1;\n";
7521
7522       (* Insert the test code. *)
7523       (match test with
7524        | None -> ()
7525        | Some f -> f ()
7526       );
7527
7528       (match fst style with
7529        | RErr | RInt _ | RInt64 _ | RBool _
7530        | RConstString _ | RConstOptString _ -> ()
7531        | RString _ | RBufferOut _ -> pr "    free (r);\n"
7532        | RStringList _ | RHashtable _ ->
7533            pr "    for (i = 0; r[i] != NULL; ++i)\n";
7534            pr "      free (r[i]);\n";
7535            pr "    free (r);\n"
7536        | RStruct (_, typ) ->
7537            pr "    guestfs_free_%s (r);\n" typ
7538        | RStructList (_, typ) ->
7539            pr "    guestfs_free_%s_list (r);\n" typ
7540       );
7541
7542       pr "  }\n"
7543
7544 and c_quote str =
7545   let str = replace_str str "\r" "\\r" in
7546   let str = replace_str str "\n" "\\n" in
7547   let str = replace_str str "\t" "\\t" in
7548   let str = replace_str str "\000" "\\0" in
7549   str
7550
7551 (* Generate a lot of different functions for guestfish. *)
7552 and generate_fish_cmds () =
7553   generate_header CStyle GPLv2plus;
7554
7555   let all_functions =
7556     List.filter (
7557       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7558     ) all_functions in
7559   let all_functions_sorted =
7560     List.filter (
7561       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
7562     ) all_functions_sorted in
7563
7564   pr "#include <config.h>\n";
7565   pr "\n";
7566   pr "#include <stdio.h>\n";
7567   pr "#include <stdlib.h>\n";
7568   pr "#include <string.h>\n";
7569   pr "#include <inttypes.h>\n";
7570   pr "\n";
7571   pr "#include <guestfs.h>\n";
7572   pr "#include \"c-ctype.h\"\n";
7573   pr "#include \"full-write.h\"\n";
7574   pr "#include \"xstrtol.h\"\n";
7575   pr "#include \"fish.h\"\n";
7576   pr "\n";
7577   pr "/* Valid suffixes allowed for numbers.  See Gnulib xstrtol function. */\n";
7578   pr "static const char *xstrtol_suffixes = \"0kKMGTPEZY\";\n";
7579   pr "\n";
7580
7581   (* list_commands function, which implements guestfish -h *)
7582   pr "void list_commands (void)\n";
7583   pr "{\n";
7584   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
7585   pr "  list_builtin_commands ();\n";
7586   List.iter (
7587     fun (name, _, _, flags, _, shortdesc, _) ->
7588       let name = replace_char name '_' '-' in
7589       pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
7590         name shortdesc
7591   ) all_functions_sorted;
7592   pr "  printf (\"    %%s\\n\",";
7593   pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
7594   pr "}\n";
7595   pr "\n";
7596
7597   (* display_command function, which implements guestfish -h cmd *)
7598   pr "int display_command (const char *cmd)\n";
7599   pr "{\n";
7600   List.iter (
7601     fun (name, style, _, flags, _, shortdesc, longdesc) ->
7602       let name2 = replace_char name '_' '-' in
7603       let alias =
7604         try find_map (function FishAlias n -> Some n | _ -> None) flags
7605         with Not_found -> name in
7606       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
7607       let synopsis =
7608         match snd style with
7609         | [] -> name2
7610         | args ->
7611             sprintf "%s %s"
7612               name2 (String.concat " " (List.map name_of_argt args)) in
7613
7614       let warnings =
7615         if List.mem ProtocolLimitWarning flags then
7616           ("\n\n" ^ protocol_limit_warning)
7617         else "" in
7618
7619       (* For DangerWillRobinson commands, we should probably have
7620        * guestfish prompt before allowing you to use them (especially
7621        * in interactive mode). XXX
7622        *)
7623       let warnings =
7624         warnings ^
7625           if List.mem DangerWillRobinson flags then
7626             ("\n\n" ^ danger_will_robinson)
7627           else "" in
7628
7629       let warnings =
7630         warnings ^
7631           match deprecation_notice flags with
7632           | None -> ""
7633           | Some txt -> "\n\n" ^ txt in
7634
7635       let describe_alias =
7636         if name <> alias then
7637           sprintf "\n\nYou can use '%s' as an alias for this command." alias
7638         else "" in
7639
7640       pr "  if (";
7641       pr "STRCASEEQ (cmd, \"%s\")" name;
7642       if name <> name2 then
7643         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7644       if name <> alias then
7645         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7646       pr ") {\n";
7647       pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
7648         name2 shortdesc
7649         ("=head1 SYNOPSIS\n\n " ^ synopsis ^ "\n\n" ^
7650          "=head1 DESCRIPTION\n\n" ^
7651          longdesc ^ warnings ^ describe_alias);
7652       pr "    return 0;\n";
7653       pr "  }\n";
7654       pr "  else\n"
7655   ) all_functions;
7656   pr "    return display_builtin_command (cmd);\n";
7657   pr "}\n";
7658   pr "\n";
7659
7660   let emit_print_list_function typ =
7661     pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
7662       typ typ typ;
7663     pr "{\n";
7664     pr "  unsigned int i;\n";
7665     pr "\n";
7666     pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
7667     pr "    printf (\"[%%d] = {\\n\", i);\n";
7668     pr "    print_%s_indent (&%ss->val[i], \"  \");\n" typ typ;
7669     pr "    printf (\"}\\n\");\n";
7670     pr "  }\n";
7671     pr "}\n";
7672     pr "\n";
7673   in
7674
7675   (* print_* functions *)
7676   List.iter (
7677     fun (typ, cols) ->
7678       let needs_i =
7679         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
7680
7681       pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
7682       pr "{\n";
7683       if needs_i then (
7684         pr "  unsigned int i;\n";
7685         pr "\n"
7686       );
7687       List.iter (
7688         function
7689         | name, FString ->
7690             pr "  printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
7691         | name, FUUID ->
7692             pr "  printf (\"%%s%s: \", indent);\n" name;
7693             pr "  for (i = 0; i < 32; ++i)\n";
7694             pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
7695             pr "  printf (\"\\n\");\n"
7696         | name, FBuffer ->
7697             pr "  printf (\"%%s%s: \", indent);\n" name;
7698             pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
7699             pr "    if (c_isprint (%s->%s[i]))\n" typ name;
7700             pr "      printf (\"%%c\", %s->%s[i]);\n" typ name;
7701             pr "    else\n";
7702             pr "      printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
7703             pr "  printf (\"\\n\");\n"
7704         | name, (FUInt64|FBytes) ->
7705             pr "  printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
7706               name typ name
7707         | name, FInt64 ->
7708             pr "  printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
7709               name typ name
7710         | name, FUInt32 ->
7711             pr "  printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
7712               name typ name
7713         | name, FInt32 ->
7714             pr "  printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
7715               name typ name
7716         | name, FChar ->
7717             pr "  printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
7718               name typ name
7719         | name, FOptPercent ->
7720             pr "  if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
7721               typ name name typ name;
7722             pr "  else printf (\"%%s%s: \\n\", indent);\n" name
7723       ) cols;
7724       pr "}\n";
7725       pr "\n";
7726   ) structs;
7727
7728   (* Emit a print_TYPE_list function definition only if that function is used. *)
7729   List.iter (
7730     function
7731     | typ, (RStructListOnly | RStructAndList) ->
7732         (* generate the function for typ *)
7733         emit_print_list_function typ
7734     | typ, _ -> () (* empty *)
7735   ) (rstructs_used_by all_functions);
7736
7737   (* Emit a print_TYPE function definition only if that function is used. *)
7738   List.iter (
7739     function
7740     | typ, (RStructOnly | RStructAndList) ->
7741         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
7742         pr "{\n";
7743         pr "  print_%s_indent (%s, \"\");\n" typ typ;
7744         pr "}\n";
7745         pr "\n";
7746     | typ, _ -> () (* empty *)
7747   ) (rstructs_used_by all_functions);
7748
7749   (* run_<action> actions *)
7750   List.iter (
7751     fun (name, style, _, flags, _, _, _) ->
7752       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
7753       pr "{\n";
7754       (match fst style with
7755        | RErr
7756        | RInt _
7757        | RBool _ -> pr "  int r;\n"
7758        | RInt64 _ -> pr "  int64_t r;\n"
7759        | RConstString _ | RConstOptString _ -> pr "  const char *r;\n"
7760        | RString _ -> pr "  char *r;\n"
7761        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
7762        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
7763        | RStructList (_, typ) -> pr "  struct guestfs_%s_list *r;\n" typ
7764        | RBufferOut _ ->
7765            pr "  char *r;\n";
7766            pr "  size_t size;\n";
7767       );
7768       List.iter (
7769         function
7770         | Device n
7771         | String n
7772         | OptString n -> pr "  const char *%s;\n" n
7773         | Pathname n
7774         | Dev_or_Path n
7775         | FileIn n
7776         | FileOut n -> pr "  char *%s;\n" n
7777         | BufferIn n ->
7778             pr "  const char *%s;\n" n;
7779             pr "  size_t %s_size;\n" n
7780         | StringList n | DeviceList n -> pr "  char **%s;\n" n
7781         | Bool n -> pr "  int %s;\n" n
7782         | Int n -> pr "  int %s;\n" n
7783         | Int64 n -> pr "  int64_t %s;\n" n
7784       ) (snd style);
7785
7786       (* Check and convert parameters. *)
7787       let argc_expected = List.length (snd style) in
7788       pr "  if (argc != %d) {\n" argc_expected;
7789       pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
7790         argc_expected;
7791       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
7792       pr "    return -1;\n";
7793       pr "  }\n";
7794
7795       let parse_integer fn fntyp rtyp range name i =
7796         pr "  {\n";
7797         pr "    strtol_error xerr;\n";
7798         pr "    %s r;\n" fntyp;
7799         pr "\n";
7800         pr "    xerr = %s (argv[%d], NULL, 0, &r, xstrtol_suffixes);\n" fn i;
7801         pr "    if (xerr != LONGINT_OK) {\n";
7802         pr "      fprintf (stderr,\n";
7803         pr "               _(\"%%s: %%s: invalid integer parameter (%%s returned %%d)\\n\"),\n";
7804         pr "               cmd, \"%s\", \"%s\", xerr);\n" name fn;
7805         pr "      return -1;\n";
7806         pr "    }\n";
7807         (match range with
7808          | None -> ()
7809          | Some (min, max, comment) ->
7810              pr "    /* %s */\n" comment;
7811              pr "    if (r < %s || r > %s) {\n" min max;
7812              pr "      fprintf (stderr, _(\"%%s: %%s: integer out of range\\n\"), cmd, \"%s\");\n"
7813                name;
7814              pr "      return -1;\n";
7815              pr "    }\n";
7816              pr "    /* The check above should ensure this assignment does not overflow. */\n";
7817         );
7818         pr "    %s = r;\n" name;
7819         pr "  }\n";
7820       in
7821
7822       iteri (
7823         fun i ->
7824           function
7825           | Device name
7826           | String name ->
7827               pr "  %s = argv[%d];\n" name i
7828           | Pathname name
7829           | Dev_or_Path name ->
7830               pr "  %s = resolve_win_path (argv[%d]);\n" name i;
7831               pr "  if (%s == NULL) return -1;\n" name
7832           | OptString name ->
7833               pr "  %s = STRNEQ (argv[%d], \"\") ? argv[%d] : NULL;\n"
7834                 name i i
7835           | BufferIn name ->
7836               pr "  %s = argv[%d];\n" name i;
7837               pr "  %s_size = strlen (argv[%d]);\n" name i
7838           | FileIn name ->
7839               pr "  %s = file_in (argv[%d]);\n" name i;
7840               pr "  if (%s == NULL) return -1;\n" name
7841           | FileOut name ->
7842               pr "  %s = file_out (argv[%d]);\n" name i;
7843               pr "  if (%s == NULL) return -1;\n" name
7844           | StringList name | DeviceList name ->
7845               pr "  %s = parse_string_list (argv[%d]);\n" name i;
7846               pr "  if (%s == NULL) return -1;\n" name;
7847           | Bool name ->
7848               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
7849           | Int name ->
7850               let range =
7851                 let min = "(-(2LL<<30))"
7852                 and max = "((2LL<<30)-1)"
7853                 and comment =
7854                   "The Int type in the generator is a signed 31 bit int." in
7855                 Some (min, max, comment) in
7856               parse_integer "xstrtoll" "long long" "int" range name i
7857           | Int64 name ->
7858               parse_integer "xstrtoll" "long long" "int64_t" None name i
7859       ) (snd style);
7860
7861       (* Call C API function. *)
7862       pr "  r = guestfs_%s " name;
7863       generate_c_call_args ~handle:"g" style;
7864       pr ";\n";
7865
7866       List.iter (
7867         function
7868         | Device name | String name
7869         | OptString name | Bool name
7870         | Int name | Int64 name
7871         | BufferIn name -> ()
7872         | Pathname name | Dev_or_Path name | FileOut name ->
7873             pr "  free (%s);\n" name
7874         | FileIn name ->
7875             pr "  free_file_in (%s);\n" name
7876         | StringList name | DeviceList name ->
7877             pr "  free_strings (%s);\n" name
7878       ) (snd style);
7879
7880       (* Any output flags? *)
7881       let fish_output =
7882         let flags = filter_map (
7883           function FishOutput flag -> Some flag | _ -> None
7884         ) flags in
7885         match flags with
7886         | [] -> None
7887         | [f] -> Some f
7888         | _ ->
7889             failwithf "%s: more than one FishOutput flag is not allowed" name in
7890
7891       (* Check return value for errors and display command results. *)
7892       (match fst style with
7893        | RErr -> pr "  return r;\n"
7894        | RInt _ ->
7895            pr "  if (r == -1) return -1;\n";
7896            (match fish_output with
7897             | None ->
7898                 pr "  printf (\"%%d\\n\", r);\n";
7899             | Some FishOutputOctal ->
7900                 pr "  printf (\"%%s%%o\\n\", r != 0 ? \"0\" : \"\", r);\n";
7901             | Some FishOutputHexadecimal ->
7902                 pr "  printf (\"%%s%%x\\n\", r != 0 ? \"0x\" : \"\", r);\n");
7903            pr "  return 0;\n"
7904        | RInt64 _ ->
7905            pr "  if (r == -1) return -1;\n";
7906            (match fish_output with
7907             | None ->
7908                 pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
7909             | Some FishOutputOctal ->
7910                 pr "  printf (\"%%s%%\" PRIo64 \"\\n\", r != 0 ? \"0\" : \"\", r);\n";
7911             | Some FishOutputHexadecimal ->
7912                 pr "  printf (\"%%s%%\" PRIx64 \"\\n\", r != 0 ? \"0x\" : \"\", r);\n");
7913            pr "  return 0;\n"
7914        | RBool _ ->
7915            pr "  if (r == -1) return -1;\n";
7916            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
7917            pr "  return 0;\n"
7918        | RConstString _ ->
7919            pr "  if (r == NULL) return -1;\n";
7920            pr "  printf (\"%%s\\n\", r);\n";
7921            pr "  return 0;\n"
7922        | RConstOptString _ ->
7923            pr "  printf (\"%%s\\n\", r ? : \"(null)\");\n";
7924            pr "  return 0;\n"
7925        | RString _ ->
7926            pr "  if (r == NULL) return -1;\n";
7927            pr "  printf (\"%%s\\n\", r);\n";
7928            pr "  free (r);\n";
7929            pr "  return 0;\n"
7930        | RStringList _ ->
7931            pr "  if (r == NULL) return -1;\n";
7932            pr "  print_strings (r);\n";
7933            pr "  free_strings (r);\n";
7934            pr "  return 0;\n"
7935        | RStruct (_, typ) ->
7936            pr "  if (r == NULL) return -1;\n";
7937            pr "  print_%s (r);\n" typ;
7938            pr "  guestfs_free_%s (r);\n" typ;
7939            pr "  return 0;\n"
7940        | RStructList (_, typ) ->
7941            pr "  if (r == NULL) return -1;\n";
7942            pr "  print_%s_list (r);\n" typ;
7943            pr "  guestfs_free_%s_list (r);\n" typ;
7944            pr "  return 0;\n"
7945        | RHashtable _ ->
7946            pr "  if (r == NULL) return -1;\n";
7947            pr "  print_table (r);\n";
7948            pr "  free_strings (r);\n";
7949            pr "  return 0;\n"
7950        | RBufferOut _ ->
7951            pr "  if (r == NULL) return -1;\n";
7952            pr "  if (full_write (1, r, size) != size) {\n";
7953            pr "    perror (\"write\");\n";
7954            pr "    free (r);\n";
7955            pr "    return -1;\n";
7956            pr "  }\n";
7957            pr "  free (r);\n";
7958            pr "  return 0;\n"
7959       );
7960       pr "}\n";
7961       pr "\n"
7962   ) all_functions;
7963
7964   (* run_action function *)
7965   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
7966   pr "{\n";
7967   List.iter (
7968     fun (name, _, _, flags, _, _, _) ->
7969       let name2 = replace_char name '_' '-' in
7970       let alias =
7971         try find_map (function FishAlias n -> Some n | _ -> None) flags
7972         with Not_found -> name in
7973       pr "  if (";
7974       pr "STRCASEEQ (cmd, \"%s\")" name;
7975       if name <> name2 then
7976         pr " || STRCASEEQ (cmd, \"%s\")" name2;
7977       if name <> alias then
7978         pr " || STRCASEEQ (cmd, \"%s\")" alias;
7979       pr ")\n";
7980       pr "    return run_%s (cmd, argc, argv);\n" name;
7981       pr "  else\n";
7982   ) all_functions;
7983   pr "    {\n";
7984   pr "      fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
7985   pr "      if (command_num == 1)\n";
7986   pr "        extended_help_message ();\n";
7987   pr "      return -1;\n";
7988   pr "    }\n";
7989   pr "  return 0;\n";
7990   pr "}\n";
7991   pr "\n"
7992
7993 (* Readline completion for guestfish. *)
7994 and generate_fish_completion () =
7995   generate_header CStyle GPLv2plus;
7996
7997   let all_functions =
7998     List.filter (
7999       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
8000     ) all_functions in
8001
8002   pr "\
8003 #include <config.h>
8004
8005 #include <stdio.h>
8006 #include <stdlib.h>
8007 #include <string.h>
8008
8009 #ifdef HAVE_LIBREADLINE
8010 #include <readline/readline.h>
8011 #endif
8012
8013 #include \"fish.h\"
8014
8015 #ifdef HAVE_LIBREADLINE
8016
8017 static const char *const commands[] = {
8018   BUILTIN_COMMANDS_FOR_COMPLETION,
8019 ";
8020
8021   (* Get the commands, including the aliases.  They don't need to be
8022    * sorted - the generator() function just does a dumb linear search.
8023    *)
8024   let commands =
8025     List.map (
8026       fun (name, _, _, flags, _, _, _) ->
8027         let name2 = replace_char name '_' '-' in
8028         let alias =
8029           try find_map (function FishAlias n -> Some n | _ -> None) flags
8030           with Not_found -> name in
8031
8032         if name <> alias then [name2; alias] else [name2]
8033     ) all_functions in
8034   let commands = List.flatten commands in
8035
8036   List.iter (pr "  \"%s\",\n") commands;
8037
8038   pr "  NULL
8039 };
8040
8041 static char *
8042 generator (const char *text, int state)
8043 {
8044   static int index, len;
8045   const char *name;
8046
8047   if (!state) {
8048     index = 0;
8049     len = strlen (text);
8050   }
8051
8052   rl_attempted_completion_over = 1;
8053
8054   while ((name = commands[index]) != NULL) {
8055     index++;
8056     if (STRCASEEQLEN (name, text, len))
8057       return strdup (name);
8058   }
8059
8060   return NULL;
8061 }
8062
8063 #endif /* HAVE_LIBREADLINE */
8064
8065 #ifdef HAVE_RL_COMPLETION_MATCHES
8066 #define RL_COMPLETION_MATCHES rl_completion_matches
8067 #else
8068 #ifdef HAVE_COMPLETION_MATCHES
8069 #define RL_COMPLETION_MATCHES completion_matches
8070 #endif
8071 #endif /* else just fail if we don't have either symbol */
8072
8073 char **
8074 do_completion (const char *text, int start, int end)
8075 {
8076   char **matches = NULL;
8077
8078 #ifdef HAVE_LIBREADLINE
8079   rl_completion_append_character = ' ';
8080
8081   if (start == 0)
8082     matches = RL_COMPLETION_MATCHES (text, generator);
8083   else if (complete_dest_paths)
8084     matches = RL_COMPLETION_MATCHES (text, complete_dest_paths_generator);
8085 #endif
8086
8087   return matches;
8088 }
8089 ";
8090
8091 (* Generate the POD documentation for guestfish. *)
8092 and generate_fish_actions_pod () =
8093   let all_functions_sorted =
8094     List.filter (
8095       fun (_, _, _, flags, _, _, _) ->
8096         not (List.mem NotInFish flags || List.mem NotInDocs flags)
8097     ) all_functions_sorted in
8098
8099   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
8100
8101   List.iter (
8102     fun (name, style, _, flags, _, _, longdesc) ->
8103       let longdesc =
8104         Str.global_substitute rex (
8105           fun s ->
8106             let sub =
8107               try Str.matched_group 1 s
8108               with Not_found ->
8109                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
8110             "C<" ^ replace_char sub '_' '-' ^ ">"
8111         ) longdesc in
8112       let name = replace_char name '_' '-' in
8113       let alias =
8114         try find_map (function FishAlias n -> Some n | _ -> None) flags
8115         with Not_found -> name in
8116
8117       pr "=head2 %s" name;
8118       if name <> alias then
8119         pr " | %s" alias;
8120       pr "\n";
8121       pr "\n";
8122       pr " %s" name;
8123       List.iter (
8124         function
8125         | Pathname n | Device n | Dev_or_Path n | String n -> pr " %s" n
8126         | OptString n -> pr " %s" n
8127         | StringList n | DeviceList n -> pr " '%s ...'" n
8128         | Bool _ -> pr " true|false"
8129         | Int n -> pr " %s" n
8130         | Int64 n -> pr " %s" n
8131         | FileIn n | FileOut n -> pr " (%s|-)" n
8132         | BufferIn n -> pr " %s" n
8133       ) (snd style);
8134       pr "\n";
8135       pr "\n";
8136       pr "%s\n\n" longdesc;
8137
8138       if List.exists (function FileIn _ | FileOut _ -> true
8139                       | _ -> false) (snd style) then
8140         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
8141
8142       if List.mem ProtocolLimitWarning flags then
8143         pr "%s\n\n" protocol_limit_warning;
8144
8145       if List.mem DangerWillRobinson flags then
8146         pr "%s\n\n" danger_will_robinson;
8147
8148       match deprecation_notice flags with
8149       | None -> ()
8150       | Some txt -> pr "%s\n\n" txt
8151   ) all_functions_sorted
8152
8153 (* Generate a C function prototype. *)
8154 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
8155     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
8156     ?(prefix = "")
8157     ?handle name style =
8158   if extern then pr "extern ";
8159   if static then pr "static ";
8160   (match fst style with
8161    | RErr -> pr "int "
8162    | RInt _ -> pr "int "
8163    | RInt64 _ -> pr "int64_t "
8164    | RBool _ -> pr "int "
8165    | RConstString _ | RConstOptString _ -> pr "const char *"
8166    | RString _ | RBufferOut _ -> pr "char *"
8167    | RStringList _ | RHashtable _ -> pr "char **"
8168    | RStruct (_, typ) ->
8169        if not in_daemon then pr "struct guestfs_%s *" typ
8170        else pr "guestfs_int_%s *" typ
8171    | RStructList (_, typ) ->
8172        if not in_daemon then pr "struct guestfs_%s_list *" typ
8173        else pr "guestfs_int_%s_list *" typ
8174   );
8175   let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
8176   pr "%s%s (" prefix name;
8177   if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
8178     pr "void"
8179   else (
8180     let comma = ref false in
8181     (match handle with
8182      | None -> ()
8183      | Some handle -> pr "guestfs_h *%s" handle; comma := true
8184     );
8185     let next () =
8186       if !comma then (
8187         if single_line then pr ", " else pr ",\n\t\t"
8188       );
8189       comma := true
8190     in
8191     List.iter (
8192       function
8193       | Pathname n
8194       | Device n | Dev_or_Path n
8195       | String n
8196       | OptString n ->
8197           next ();
8198           pr "const char *%s" n
8199       | StringList n | DeviceList n ->
8200           next ();
8201           pr "char *const *%s" n
8202       | Bool n -> next (); pr "int %s" n
8203       | Int n -> next (); pr "int %s" n
8204       | Int64 n -> next (); pr "int64_t %s" n
8205       | FileIn n
8206       | FileOut n ->
8207           if not in_daemon then (next (); pr "const char *%s" n)
8208       | BufferIn n ->
8209           next ();
8210           pr "const char *%s" n;
8211           next ();
8212           pr "size_t %s_size" n
8213     ) (snd style);
8214     if is_RBufferOut then (next (); pr "size_t *size_r");
8215   );
8216   pr ")";
8217   if semicolon then pr ";";
8218   if newline then pr "\n"
8219
8220 (* Generate C call arguments, eg "(handle, foo, bar)" *)
8221 and generate_c_call_args ?handle ?(decl = false) style =
8222   pr "(";
8223   let comma = ref false in
8224   let next () =
8225     if !comma then pr ", ";
8226     comma := true
8227   in
8228   (match handle with
8229    | None -> ()
8230    | Some handle -> pr "%s" handle; comma := true
8231   );
8232   List.iter (
8233     function
8234     | BufferIn n ->
8235         next ();
8236         pr "%s, %s_size" n n
8237     | arg ->
8238         next ();
8239         pr "%s" (name_of_argt arg)
8240   ) (snd style);
8241   (* For RBufferOut calls, add implicit &size parameter. *)
8242   if not decl then (
8243     match fst style with
8244     | RBufferOut _ ->
8245         next ();
8246         pr "&size"
8247     | _ -> ()
8248   );
8249   pr ")"
8250
8251 (* Generate the OCaml bindings interface. *)
8252 and generate_ocaml_mli () =
8253   generate_header OCamlStyle LGPLv2plus;
8254
8255   pr "\
8256 (** For API documentation you should refer to the C API
8257     in the guestfs(3) manual page.  The OCaml API uses almost
8258     exactly the same calls. *)
8259
8260 type t
8261 (** A [guestfs_h] handle. *)
8262
8263 exception Error of string
8264 (** This exception is raised when there is an error. *)
8265
8266 exception Handle_closed of string
8267 (** This exception is raised if you use a {!Guestfs.t} handle
8268     after calling {!close} on it.  The string is the name of
8269     the function. *)
8270
8271 val create : unit -> t
8272 (** Create a {!Guestfs.t} handle. *)
8273
8274 val close : t -> unit
8275 (** Close the {!Guestfs.t} handle and free up all resources used
8276     by it immediately.
8277
8278     Handles are closed by the garbage collector when they become
8279     unreferenced, but callers can call this in order to provide
8280     predictable cleanup. *)
8281
8282 ";
8283   generate_ocaml_structure_decls ();
8284
8285   (* The actions. *)
8286   List.iter (
8287     fun (name, style, _, _, _, shortdesc, _) ->
8288       generate_ocaml_prototype name style;
8289       pr "(** %s *)\n" shortdesc;
8290       pr "\n"
8291   ) all_functions_sorted
8292
8293 (* Generate the OCaml bindings implementation. *)
8294 and generate_ocaml_ml () =
8295   generate_header OCamlStyle LGPLv2plus;
8296
8297   pr "\
8298 type t
8299
8300 exception Error of string
8301 exception Handle_closed of string
8302
8303 external create : unit -> t = \"ocaml_guestfs_create\"
8304 external close : t -> unit = \"ocaml_guestfs_close\"
8305
8306 (* Give the exceptions names, so they can be raised from the C code. *)
8307 let () =
8308   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\");
8309   Callback.register_exception \"ocaml_guestfs_closed\" (Handle_closed \"\")
8310
8311 ";
8312
8313   generate_ocaml_structure_decls ();
8314
8315   (* The actions. *)
8316   List.iter (
8317     fun (name, style, _, _, _, shortdesc, _) ->
8318       generate_ocaml_prototype ~is_external:true name style;
8319   ) all_functions_sorted
8320
8321 (* Generate the OCaml bindings C implementation. *)
8322 and generate_ocaml_c () =
8323   generate_header CStyle LGPLv2plus;
8324
8325   pr "\
8326 #include <stdio.h>
8327 #include <stdlib.h>
8328 #include <string.h>
8329
8330 #include <caml/config.h>
8331 #include <caml/alloc.h>
8332 #include <caml/callback.h>
8333 #include <caml/fail.h>
8334 #include <caml/memory.h>
8335 #include <caml/mlvalues.h>
8336 #include <caml/signals.h>
8337
8338 #include <guestfs.h>
8339
8340 #include \"guestfs_c.h\"
8341
8342 /* Copy a hashtable of string pairs into an assoc-list.  We return
8343  * the list in reverse order, but hashtables aren't supposed to be
8344  * ordered anyway.
8345  */
8346 static CAMLprim value
8347 copy_table (char * const * argv)
8348 {
8349   CAMLparam0 ();
8350   CAMLlocal5 (rv, pairv, kv, vv, cons);
8351   int i;
8352
8353   rv = Val_int (0);
8354   for (i = 0; argv[i] != NULL; i += 2) {
8355     kv = caml_copy_string (argv[i]);
8356     vv = caml_copy_string (argv[i+1]);
8357     pairv = caml_alloc (2, 0);
8358     Store_field (pairv, 0, kv);
8359     Store_field (pairv, 1, vv);
8360     cons = caml_alloc (2, 0);
8361     Store_field (cons, 1, rv);
8362     rv = cons;
8363     Store_field (cons, 0, pairv);
8364   }
8365
8366   CAMLreturn (rv);
8367 }
8368
8369 ";
8370
8371   (* Struct copy functions. *)
8372
8373   let emit_ocaml_copy_list_function typ =
8374     pr "static CAMLprim value\n";
8375     pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n" typ typ typ;
8376     pr "{\n";
8377     pr "  CAMLparam0 ();\n";
8378     pr "  CAMLlocal2 (rv, v);\n";
8379     pr "  unsigned int i;\n";
8380     pr "\n";
8381     pr "  if (%ss->len == 0)\n" typ;
8382     pr "    CAMLreturn (Atom (0));\n";
8383     pr "  else {\n";
8384     pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
8385     pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
8386     pr "      v = copy_%s (&%ss->val[i]);\n" typ typ;
8387     pr "      caml_modify (&Field (rv, i), v);\n";
8388     pr "    }\n";
8389     pr "    CAMLreturn (rv);\n";
8390     pr "  }\n";
8391     pr "}\n";
8392     pr "\n";
8393   in
8394
8395   List.iter (
8396     fun (typ, cols) ->
8397       let has_optpercent_col =
8398         List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
8399
8400       pr "static CAMLprim value\n";
8401       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
8402       pr "{\n";
8403       pr "  CAMLparam0 ();\n";
8404       if has_optpercent_col then
8405         pr "  CAMLlocal3 (rv, v, v2);\n"
8406       else
8407         pr "  CAMLlocal2 (rv, v);\n";
8408       pr "\n";
8409       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
8410       iteri (
8411         fun i col ->
8412           (match col with
8413            | name, FString ->
8414                pr "  v = caml_copy_string (%s->%s);\n" typ name
8415            | name, FBuffer ->
8416                pr "  v = caml_alloc_string (%s->%s_len);\n" typ name;
8417                pr "  memcpy (String_val (v), %s->%s, %s->%s_len);\n"
8418                  typ name typ name
8419            | name, FUUID ->
8420                pr "  v = caml_alloc_string (32);\n";
8421                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
8422            | name, (FBytes|FInt64|FUInt64) ->
8423                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
8424            | name, (FInt32|FUInt32) ->
8425                pr "  v = caml_copy_int32 (%s->%s);\n" typ name
8426            | name, FOptPercent ->
8427                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
8428                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
8429                pr "    v = caml_alloc (1, 0);\n";
8430                pr "    Store_field (v, 0, v2);\n";
8431                pr "  } else /* None */\n";
8432                pr "    v = Val_int (0);\n";
8433            | name, FChar ->
8434                pr "  v = Val_int (%s->%s);\n" typ name
8435           );
8436           pr "  Store_field (rv, %d, v);\n" i
8437       ) cols;
8438       pr "  CAMLreturn (rv);\n";
8439       pr "}\n";
8440       pr "\n";
8441   ) structs;
8442
8443   (* Emit a copy_TYPE_list function definition only if that function is used. *)
8444   List.iter (
8445     function
8446     | typ, (RStructListOnly | RStructAndList) ->
8447         (* generate the function for typ *)
8448         emit_ocaml_copy_list_function typ
8449     | typ, _ -> () (* empty *)
8450   ) (rstructs_used_by all_functions);
8451
8452   (* The wrappers. *)
8453   List.iter (
8454     fun (name, style, _, _, _, _, _) ->
8455       pr "/* Automatically generated wrapper for function\n";
8456       pr " * ";
8457       generate_ocaml_prototype name style;
8458       pr " */\n";
8459       pr "\n";
8460
8461       let params =
8462         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
8463
8464       let needs_extra_vs =
8465         match fst style with RConstOptString _ -> true | _ -> false in
8466
8467       pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
8468       pr "CAMLprim value ocaml_guestfs_%s (value %s" name (List.hd params);
8469       List.iter (pr ", value %s") (List.tl params); pr ");\n";
8470       pr "\n";
8471
8472       pr "CAMLprim value\n";
8473       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
8474       List.iter (pr ", value %s") (List.tl params);
8475       pr ")\n";
8476       pr "{\n";
8477
8478       (match params with
8479        | [p1; p2; p3; p4; p5] ->
8480            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
8481        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
8482            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
8483            pr "  CAMLxparam%d (%s);\n"
8484              (List.length rest) (String.concat ", " rest)
8485        | ps ->
8486            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
8487       );
8488       if not needs_extra_vs then
8489         pr "  CAMLlocal1 (rv);\n"
8490       else
8491         pr "  CAMLlocal3 (rv, v, v2);\n";
8492       pr "\n";
8493
8494       pr "  guestfs_h *g = Guestfs_val (gv);\n";
8495       pr "  if (g == NULL)\n";
8496       pr "    ocaml_guestfs_raise_closed (\"%s\");\n" name;
8497       pr "\n";
8498
8499       List.iter (
8500         function
8501         | Pathname n
8502         | Device n | Dev_or_Path n
8503         | String n
8504         | FileIn n
8505         | FileOut n ->
8506             pr "  const char *%s = String_val (%sv);\n" n n
8507         | OptString n ->
8508             pr "  const char *%s =\n" n;
8509             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
8510               n n
8511         | BufferIn n ->
8512             pr "  const char *%s = String_val (%sv);\n" n n;
8513             pr "  size_t %s_size = caml_string_length (%sv);\n" n n
8514         | StringList n | DeviceList n ->
8515             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
8516         | Bool n ->
8517             pr "  int %s = Bool_val (%sv);\n" n n
8518         | Int n ->
8519             pr "  int %s = Int_val (%sv);\n" n n
8520         | Int64 n ->
8521             pr "  int64_t %s = Int64_val (%sv);\n" n n
8522       ) (snd style);
8523       let error_code =
8524         match fst style with
8525         | RErr -> pr "  int r;\n"; "-1"
8526         | RInt _ -> pr "  int r;\n"; "-1"
8527         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
8528         | RBool _ -> pr "  int r;\n"; "-1"
8529         | RConstString _ | RConstOptString _ ->
8530             pr "  const char *r;\n"; "NULL"
8531         | RString _ -> pr "  char *r;\n"; "NULL"
8532         | RStringList _ ->
8533             pr "  int i;\n";
8534             pr "  char **r;\n";
8535             "NULL"
8536         | RStruct (_, typ) ->
8537             pr "  struct guestfs_%s *r;\n" typ; "NULL"
8538         | RStructList (_, typ) ->
8539             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
8540         | RHashtable _ ->
8541             pr "  int i;\n";
8542             pr "  char **r;\n";
8543             "NULL"
8544         | RBufferOut _ ->
8545             pr "  char *r;\n";
8546             pr "  size_t size;\n";
8547             "NULL" in
8548       pr "\n";
8549
8550       pr "  caml_enter_blocking_section ();\n";
8551       pr "  r = guestfs_%s " name;
8552       generate_c_call_args ~handle:"g" style;
8553       pr ";\n";
8554       pr "  caml_leave_blocking_section ();\n";
8555
8556       List.iter (
8557         function
8558         | StringList n | DeviceList n ->
8559             pr "  ocaml_guestfs_free_strings (%s);\n" n;
8560         | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
8561         | Bool _ | Int _ | Int64 _
8562         | FileIn _ | FileOut _ | BufferIn _ -> ()
8563       ) (snd style);
8564
8565       pr "  if (r == %s)\n" error_code;
8566       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
8567       pr "\n";
8568
8569       (match fst style with
8570        | RErr -> pr "  rv = Val_unit;\n"
8571        | RInt _ -> pr "  rv = Val_int (r);\n"
8572        | RInt64 _ ->
8573            pr "  rv = caml_copy_int64 (r);\n"
8574        | RBool _ -> pr "  rv = Val_bool (r);\n"
8575        | RConstString _ ->
8576            pr "  rv = caml_copy_string (r);\n"
8577        | RConstOptString _ ->
8578            pr "  if (r) { /* Some string */\n";
8579            pr "    v = caml_alloc (1, 0);\n";
8580            pr "    v2 = caml_copy_string (r);\n";
8581            pr "    Store_field (v, 0, v2);\n";
8582            pr "  } else /* None */\n";
8583            pr "    v = Val_int (0);\n";
8584        | RString _ ->
8585            pr "  rv = caml_copy_string (r);\n";
8586            pr "  free (r);\n"
8587        | RStringList _ ->
8588            pr "  rv = caml_copy_string_array ((const char **) r);\n";
8589            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
8590            pr "  free (r);\n"
8591        | RStruct (_, typ) ->
8592            pr "  rv = copy_%s (r);\n" typ;
8593            pr "  guestfs_free_%s (r);\n" typ;
8594        | RStructList (_, typ) ->
8595            pr "  rv = copy_%s_list (r);\n" typ;
8596            pr "  guestfs_free_%s_list (r);\n" typ;
8597        | RHashtable _ ->
8598            pr "  rv = copy_table (r);\n";
8599            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
8600            pr "  free (r);\n";
8601        | RBufferOut _ ->
8602            pr "  rv = caml_alloc_string (size);\n";
8603            pr "  memcpy (String_val (rv), r, size);\n";
8604       );
8605
8606       pr "  CAMLreturn (rv);\n";
8607       pr "}\n";
8608       pr "\n";
8609
8610       if List.length params > 5 then (
8611         pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
8612         pr "CAMLprim value ";
8613         pr "ocaml_guestfs_%s_byte (value *argv, int argn);\n" name;
8614         pr "CAMLprim value\n";
8615         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
8616         pr "{\n";
8617         pr "  return ocaml_guestfs_%s (argv[0]" name;
8618         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
8619         pr ");\n";
8620         pr "}\n";
8621         pr "\n"
8622       )
8623   ) all_functions_sorted
8624
8625 and generate_ocaml_structure_decls () =
8626   List.iter (
8627     fun (typ, cols) ->
8628       pr "type %s = {\n" typ;
8629       List.iter (
8630         function
8631         | name, FString -> pr "  %s : string;\n" name
8632         | name, FBuffer -> pr "  %s : string;\n" name
8633         | name, FUUID -> pr "  %s : string;\n" name
8634         | name, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
8635         | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
8636         | name, FChar -> pr "  %s : char;\n" name
8637         | name, FOptPercent -> pr "  %s : float option;\n" name
8638       ) cols;
8639       pr "}\n";
8640       pr "\n"
8641   ) structs
8642
8643 and generate_ocaml_prototype ?(is_external = false) name style =
8644   if is_external then pr "external " else pr "val ";
8645   pr "%s : t -> " name;
8646   List.iter (
8647     function
8648     | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _
8649     | BufferIn _ -> pr "string -> "
8650     | OptString _ -> pr "string option -> "
8651     | StringList _ | DeviceList _ -> pr "string array -> "
8652     | Bool _ -> pr "bool -> "
8653     | Int _ -> pr "int -> "
8654     | Int64 _ -> pr "int64 -> "
8655   ) (snd style);
8656   (match fst style with
8657    | RErr -> pr "unit" (* all errors are turned into exceptions *)
8658    | RInt _ -> pr "int"
8659    | RInt64 _ -> pr "int64"
8660    | RBool _ -> pr "bool"
8661    | RConstString _ -> pr "string"
8662    | RConstOptString _ -> pr "string option"
8663    | RString _ | RBufferOut _ -> pr "string"
8664    | RStringList _ -> pr "string array"
8665    | RStruct (_, typ) -> pr "%s" typ
8666    | RStructList (_, typ) -> pr "%s array" typ
8667    | RHashtable _ -> pr "(string * string) list"
8668   );
8669   if is_external then (
8670     pr " = ";
8671     if List.length (snd style) + 1 > 5 then
8672       pr "\"ocaml_guestfs_%s_byte\" " name;
8673     pr "\"ocaml_guestfs_%s\"" name
8674   );
8675   pr "\n"
8676
8677 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
8678 and generate_perl_xs () =
8679   generate_header CStyle LGPLv2plus;
8680
8681   pr "\
8682 #include \"EXTERN.h\"
8683 #include \"perl.h\"
8684 #include \"XSUB.h\"
8685
8686 #include <guestfs.h>
8687
8688 #ifndef PRId64
8689 #define PRId64 \"lld\"
8690 #endif
8691
8692 static SV *
8693 my_newSVll(long long val) {
8694 #ifdef USE_64_BIT_ALL
8695   return newSViv(val);
8696 #else
8697   char buf[100];
8698   int len;
8699   len = snprintf(buf, 100, \"%%\" PRId64, val);
8700   return newSVpv(buf, len);
8701 #endif
8702 }
8703
8704 #ifndef PRIu64
8705 #define PRIu64 \"llu\"
8706 #endif
8707
8708 static SV *
8709 my_newSVull(unsigned long long val) {
8710 #ifdef USE_64_BIT_ALL
8711   return newSVuv(val);
8712 #else
8713   char buf[100];
8714   int len;
8715   len = snprintf(buf, 100, \"%%\" PRIu64, val);
8716   return newSVpv(buf, len);
8717 #endif
8718 }
8719
8720 /* http://www.perlmonks.org/?node_id=680842 */
8721 static char **
8722 XS_unpack_charPtrPtr (SV *arg) {
8723   char **ret;
8724   AV *av;
8725   I32 i;
8726
8727   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
8728     croak (\"array reference expected\");
8729
8730   av = (AV *)SvRV (arg);
8731   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
8732   if (!ret)
8733     croak (\"malloc failed\");
8734
8735   for (i = 0; i <= av_len (av); i++) {
8736     SV **elem = av_fetch (av, i, 0);
8737
8738     if (!elem || !*elem)
8739       croak (\"missing element in list\");
8740
8741     ret[i] = SvPV_nolen (*elem);
8742   }
8743
8744   ret[i] = NULL;
8745
8746   return ret;
8747 }
8748
8749 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
8750
8751 PROTOTYPES: ENABLE
8752
8753 guestfs_h *
8754 _create ()
8755    CODE:
8756       RETVAL = guestfs_create ();
8757       if (!RETVAL)
8758         croak (\"could not create guestfs handle\");
8759       guestfs_set_error_handler (RETVAL, NULL, NULL);
8760  OUTPUT:
8761       RETVAL
8762
8763 void
8764 DESTROY (g)
8765       guestfs_h *g;
8766  PPCODE:
8767       guestfs_close (g);
8768
8769 ";
8770
8771   List.iter (
8772     fun (name, style, _, _, _, _, _) ->
8773       (match fst style with
8774        | RErr -> pr "void\n"
8775        | RInt _ -> pr "SV *\n"
8776        | RInt64 _ -> pr "SV *\n"
8777        | RBool _ -> pr "SV *\n"
8778        | RConstString _ -> pr "SV *\n"
8779        | RConstOptString _ -> pr "SV *\n"
8780        | RString _ -> pr "SV *\n"
8781        | RBufferOut _ -> pr "SV *\n"
8782        | RStringList _
8783        | RStruct _ | RStructList _
8784        | RHashtable _ ->
8785            pr "void\n" (* all lists returned implictly on the stack *)
8786       );
8787       (* Call and arguments. *)
8788       pr "%s (g" name;
8789       List.iter (
8790         fun arg -> pr ", %s" (name_of_argt arg)
8791       ) (snd style);
8792       pr ")\n";
8793       pr "      guestfs_h *g;\n";
8794       iteri (
8795         fun i ->
8796           function
8797           | Pathname n | Device n | Dev_or_Path n | String n
8798           | FileIn n | FileOut n ->
8799               pr "      char *%s;\n" n
8800           | BufferIn n ->
8801               pr "      char *%s;\n" n;
8802               pr "      size_t %s_size = SvCUR (ST(%d));\n" n (i+1)
8803           | OptString n ->
8804               (* http://www.perlmonks.org/?node_id=554277
8805                * Note that the implicit handle argument means we have
8806                * to add 1 to the ST(x) operator.
8807                *)
8808               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
8809           | StringList n | DeviceList n -> pr "      char **%s;\n" n
8810           | Bool n -> pr "      int %s;\n" n
8811           | Int n -> pr "      int %s;\n" n
8812           | Int64 n -> pr "      int64_t %s;\n" n
8813       ) (snd style);
8814
8815       let do_cleanups () =
8816         List.iter (
8817           function
8818           | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
8819           | Bool _ | Int _ | Int64 _
8820           | FileIn _ | FileOut _
8821           | BufferIn _ -> ()
8822           | StringList n | DeviceList n -> pr "      free (%s);\n" n
8823         ) (snd style)
8824       in
8825
8826       (* Code. *)
8827       (match fst style with
8828        | RErr ->
8829            pr "PREINIT:\n";
8830            pr "      int r;\n";
8831            pr " PPCODE:\n";
8832            pr "      r = guestfs_%s " name;
8833            generate_c_call_args ~handle:"g" style;
8834            pr ";\n";
8835            do_cleanups ();
8836            pr "      if (r == -1)\n";
8837            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8838        | RInt n
8839        | RBool n ->
8840            pr "PREINIT:\n";
8841            pr "      int %s;\n" n;
8842            pr "   CODE:\n";
8843            pr "      %s = guestfs_%s " n name;
8844            generate_c_call_args ~handle:"g" style;
8845            pr ";\n";
8846            do_cleanups ();
8847            pr "      if (%s == -1)\n" n;
8848            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8849            pr "      RETVAL = newSViv (%s);\n" n;
8850            pr " OUTPUT:\n";
8851            pr "      RETVAL\n"
8852        | RInt64 n ->
8853            pr "PREINIT:\n";
8854            pr "      int64_t %s;\n" n;
8855            pr "   CODE:\n";
8856            pr "      %s = guestfs_%s " n name;
8857            generate_c_call_args ~handle:"g" style;
8858            pr ";\n";
8859            do_cleanups ();
8860            pr "      if (%s == -1)\n" n;
8861            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8862            pr "      RETVAL = my_newSVll (%s);\n" n;
8863            pr " OUTPUT:\n";
8864            pr "      RETVAL\n"
8865        | RConstString n ->
8866            pr "PREINIT:\n";
8867            pr "      const char *%s;\n" n;
8868            pr "   CODE:\n";
8869            pr "      %s = guestfs_%s " n name;
8870            generate_c_call_args ~handle:"g" style;
8871            pr ";\n";
8872            do_cleanups ();
8873            pr "      if (%s == NULL)\n" n;
8874            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8875            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8876            pr " OUTPUT:\n";
8877            pr "      RETVAL\n"
8878        | RConstOptString n ->
8879            pr "PREINIT:\n";
8880            pr "      const char *%s;\n" n;
8881            pr "   CODE:\n";
8882            pr "      %s = guestfs_%s " n name;
8883            generate_c_call_args ~handle:"g" style;
8884            pr ";\n";
8885            do_cleanups ();
8886            pr "      if (%s == NULL)\n" n;
8887            pr "        RETVAL = &PL_sv_undef;\n";
8888            pr "      else\n";
8889            pr "        RETVAL = newSVpv (%s, 0);\n" n;
8890            pr " OUTPUT:\n";
8891            pr "      RETVAL\n"
8892        | RString n ->
8893            pr "PREINIT:\n";
8894            pr "      char *%s;\n" n;
8895            pr "   CODE:\n";
8896            pr "      %s = guestfs_%s " n name;
8897            generate_c_call_args ~handle:"g" style;
8898            pr ";\n";
8899            do_cleanups ();
8900            pr "      if (%s == NULL)\n" n;
8901            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8902            pr "      RETVAL = newSVpv (%s, 0);\n" n;
8903            pr "      free (%s);\n" n;
8904            pr " OUTPUT:\n";
8905            pr "      RETVAL\n"
8906        | RStringList n | RHashtable n ->
8907            pr "PREINIT:\n";
8908            pr "      char **%s;\n" n;
8909            pr "      int i, n;\n";
8910            pr " PPCODE:\n";
8911            pr "      %s = guestfs_%s " n name;
8912            generate_c_call_args ~handle:"g" style;
8913            pr ";\n";
8914            do_cleanups ();
8915            pr "      if (%s == NULL)\n" n;
8916            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8917            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
8918            pr "      EXTEND (SP, n);\n";
8919            pr "      for (i = 0; i < n; ++i) {\n";
8920            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
8921            pr "        free (%s[i]);\n" n;
8922            pr "      }\n";
8923            pr "      free (%s);\n" n;
8924        | RStruct (n, typ) ->
8925            let cols = cols_of_struct typ in
8926            generate_perl_struct_code typ cols name style n do_cleanups
8927        | RStructList (n, typ) ->
8928            let cols = cols_of_struct typ in
8929            generate_perl_struct_list_code typ cols name style n do_cleanups
8930        | RBufferOut n ->
8931            pr "PREINIT:\n";
8932            pr "      char *%s;\n" n;
8933            pr "      size_t size;\n";
8934            pr "   CODE:\n";
8935            pr "      %s = guestfs_%s " n name;
8936            generate_c_call_args ~handle:"g" style;
8937            pr ";\n";
8938            do_cleanups ();
8939            pr "      if (%s == NULL)\n" n;
8940            pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8941            pr "      RETVAL = newSVpvn (%s, size);\n" n;
8942            pr "      free (%s);\n" n;
8943            pr " OUTPUT:\n";
8944            pr "      RETVAL\n"
8945       );
8946
8947       pr "\n"
8948   ) all_functions
8949
8950 and generate_perl_struct_list_code typ cols name style n do_cleanups =
8951   pr "PREINIT:\n";
8952   pr "      struct guestfs_%s_list *%s;\n" typ n;
8953   pr "      int i;\n";
8954   pr "      HV *hv;\n";
8955   pr " PPCODE:\n";
8956   pr "      %s = guestfs_%s " n name;
8957   generate_c_call_args ~handle:"g" style;
8958   pr ";\n";
8959   do_cleanups ();
8960   pr "      if (%s == NULL)\n" n;
8961   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
8962   pr "      EXTEND (SP, %s->len);\n" n;
8963   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
8964   pr "        hv = newHV ();\n";
8965   List.iter (
8966     function
8967     | name, FString ->
8968         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
8969           name (String.length name) n name
8970     | name, FUUID ->
8971         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
8972           name (String.length name) n name
8973     | name, FBuffer ->
8974         pr "        (void) hv_store (hv, \"%s\", %d, newSVpvn (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
8975           name (String.length name) n name n name
8976     | name, (FBytes|FUInt64) ->
8977         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
8978           name (String.length name) n name
8979     | name, FInt64 ->
8980         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
8981           name (String.length name) n name
8982     | name, (FInt32|FUInt32) ->
8983         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8984           name (String.length name) n name
8985     | name, FChar ->
8986         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
8987           name (String.length name) n name
8988     | name, FOptPercent ->
8989         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
8990           name (String.length name) n name
8991   ) cols;
8992   pr "        PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
8993   pr "      }\n";
8994   pr "      guestfs_free_%s_list (%s);\n" typ n
8995
8996 and generate_perl_struct_code typ cols name style n do_cleanups =
8997   pr "PREINIT:\n";
8998   pr "      struct guestfs_%s *%s;\n" typ n;
8999   pr " PPCODE:\n";
9000   pr "      %s = guestfs_%s " n name;
9001   generate_c_call_args ~handle:"g" style;
9002   pr ";\n";
9003   do_cleanups ();
9004   pr "      if (%s == NULL)\n" n;
9005   pr "        croak (\"%%s\", guestfs_last_error (g));\n";
9006   pr "      EXTEND (SP, 2 * %d);\n" (List.length cols);
9007   List.iter (
9008     fun ((name, _) as col) ->
9009       pr "      PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
9010
9011       match col with
9012       | name, FString ->
9013           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
9014             n name
9015       | name, FBuffer ->
9016           pr "      PUSHs (sv_2mortal (newSVpvn (%s->%s, %s->%s_len)));\n"
9017             n name n name
9018       | name, FUUID ->
9019           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
9020             n name
9021       | name, (FBytes|FUInt64) ->
9022           pr "      PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
9023             n name
9024       | name, FInt64 ->
9025           pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
9026             n name
9027       | name, (FInt32|FUInt32) ->
9028           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
9029             n name
9030       | name, FChar ->
9031           pr "      PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
9032             n name
9033       | name, FOptPercent ->
9034           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
9035             n name
9036   ) cols;
9037   pr "      free (%s);\n" n
9038
9039 (* Generate Sys/Guestfs.pm. *)
9040 and generate_perl_pm () =
9041   generate_header HashStyle LGPLv2plus;
9042
9043   pr "\
9044 =pod
9045
9046 =head1 NAME
9047
9048 Sys::Guestfs - Perl bindings for libguestfs
9049
9050 =head1 SYNOPSIS
9051
9052  use Sys::Guestfs;
9053
9054  my $h = Sys::Guestfs->new ();
9055  $h->add_drive ('guest.img');
9056  $h->launch ();
9057  $h->mount ('/dev/sda1', '/');
9058  $h->touch ('/hello');
9059  $h->sync ();
9060
9061 =head1 DESCRIPTION
9062
9063 The C<Sys::Guestfs> module provides a Perl XS binding to the
9064 libguestfs API for examining and modifying virtual machine
9065 disk images.
9066
9067 Amongst the things this is good for: making batch configuration
9068 changes to guests, getting disk used/free statistics (see also:
9069 virt-df), migrating between virtualization systems (see also:
9070 virt-p2v), performing partial backups, performing partial guest
9071 clones, cloning guests and changing registry/UUID/hostname info, and
9072 much else besides.
9073
9074 Libguestfs uses Linux kernel and qemu code, and can access any type of
9075 guest filesystem that Linux and qemu can, including but not limited
9076 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
9077 schemes, qcow, qcow2, vmdk.
9078
9079 Libguestfs provides ways to enumerate guest storage (eg. partitions,
9080 LVs, what filesystem is in each LV, etc.).  It can also run commands
9081 in the context of the guest.  Also you can access filesystems over
9082 FUSE.
9083
9084 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
9085 functions for using libguestfs from Perl, including integration
9086 with libvirt.
9087
9088 =head1 ERRORS
9089
9090 All errors turn into calls to C<croak> (see L<Carp(3)>).
9091
9092 =head1 METHODS
9093
9094 =over 4
9095
9096 =cut
9097
9098 package Sys::Guestfs;
9099
9100 use strict;
9101 use warnings;
9102
9103 # This version number changes whenever a new function
9104 # is added to the libguestfs API.  It is not directly
9105 # related to the libguestfs version number.
9106 use vars qw($VERSION);
9107 $VERSION = '0.%d';
9108
9109 require XSLoader;
9110 XSLoader::load ('Sys::Guestfs');
9111
9112 =item $h = Sys::Guestfs->new ();
9113
9114 Create a new guestfs handle.
9115
9116 =cut
9117
9118 sub new {
9119   my $proto = shift;
9120   my $class = ref ($proto) || $proto;
9121
9122   my $self = Sys::Guestfs::_create ();
9123   bless $self, $class;
9124   return $self;
9125 }
9126
9127 " max_proc_nr;
9128
9129   (* Actions.  We only need to print documentation for these as
9130    * they are pulled in from the XS code automatically.
9131    *)
9132   List.iter (
9133     fun (name, style, _, flags, _, _, longdesc) ->
9134       if not (List.mem NotInDocs flags) then (
9135         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
9136         pr "=item ";
9137         generate_perl_prototype name style;
9138         pr "\n\n";
9139         pr "%s\n\n" longdesc;
9140         if List.mem ProtocolLimitWarning flags then
9141           pr "%s\n\n" protocol_limit_warning;
9142         if List.mem DangerWillRobinson flags then
9143           pr "%s\n\n" danger_will_robinson;
9144         match deprecation_notice flags with
9145         | None -> ()
9146         | Some txt -> pr "%s\n\n" txt
9147       )
9148   ) all_functions_sorted;
9149
9150   (* End of file. *)
9151   pr "\
9152 =cut
9153
9154 1;
9155
9156 =back
9157
9158 =head1 COPYRIGHT
9159
9160 Copyright (C) %s Red Hat Inc.
9161
9162 =head1 LICENSE
9163
9164 Please see the file COPYING.LIB for the full license.
9165
9166 =head1 SEE ALSO
9167
9168 L<guestfs(3)>,
9169 L<guestfish(1)>,
9170 L<http://libguestfs.org>,
9171 L<Sys::Guestfs::Lib(3)>.
9172
9173 =cut
9174 " copyright_years
9175
9176 and generate_perl_prototype name style =
9177   (match fst style with
9178    | RErr -> ()
9179    | RBool n
9180    | RInt n
9181    | RInt64 n
9182    | RConstString n
9183    | RConstOptString n
9184    | RString n
9185    | RBufferOut n -> pr "$%s = " n
9186    | RStruct (n,_)
9187    | RHashtable n -> pr "%%%s = " n
9188    | RStringList n
9189    | RStructList (n,_) -> pr "@%s = " n
9190   );
9191   pr "$h->%s (" name;
9192   let comma = ref false in
9193   List.iter (
9194     fun arg ->
9195       if !comma then pr ", ";
9196       comma := true;
9197       match arg with
9198       | Pathname n | Device n | Dev_or_Path n | String n
9199       | OptString n | Bool n | Int n | Int64 n | FileIn n | FileOut n
9200       | BufferIn n ->
9201           pr "$%s" n
9202       | StringList n | DeviceList n ->
9203           pr "\\@%s" n
9204   ) (snd style);
9205   pr ");"
9206
9207 (* Generate Python C module. *)
9208 and generate_python_c () =
9209   generate_header CStyle LGPLv2plus;
9210
9211   pr "\
9212 #define PY_SSIZE_T_CLEAN 1
9213 #include <Python.h>
9214
9215 #if PY_VERSION_HEX < 0x02050000
9216 typedef int Py_ssize_t;
9217 #define PY_SSIZE_T_MAX INT_MAX
9218 #define PY_SSIZE_T_MIN INT_MIN
9219 #endif
9220
9221 #include <stdio.h>
9222 #include <stdlib.h>
9223 #include <assert.h>
9224
9225 #include \"guestfs.h\"
9226
9227 typedef struct {
9228   PyObject_HEAD
9229   guestfs_h *g;
9230 } Pyguestfs_Object;
9231
9232 static guestfs_h *
9233 get_handle (PyObject *obj)
9234 {
9235   assert (obj);
9236   assert (obj != Py_None);
9237   return ((Pyguestfs_Object *) obj)->g;
9238 }
9239
9240 static PyObject *
9241 put_handle (guestfs_h *g)
9242 {
9243   assert (g);
9244   return
9245     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
9246 }
9247
9248 /* This list should be freed (but not the strings) after use. */
9249 static char **
9250 get_string_list (PyObject *obj)
9251 {
9252   int i, len;
9253   char **r;
9254
9255   assert (obj);
9256
9257   if (!PyList_Check (obj)) {
9258     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
9259     return NULL;
9260   }
9261
9262   len = PyList_Size (obj);
9263   r = malloc (sizeof (char *) * (len+1));
9264   if (r == NULL) {
9265     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
9266     return NULL;
9267   }
9268
9269   for (i = 0; i < len; ++i)
9270     r[i] = PyString_AsString (PyList_GetItem (obj, i));
9271   r[len] = NULL;
9272
9273   return r;
9274 }
9275
9276 static PyObject *
9277 put_string_list (char * const * const argv)
9278 {
9279   PyObject *list;
9280   int argc, i;
9281
9282   for (argc = 0; argv[argc] != NULL; ++argc)
9283     ;
9284
9285   list = PyList_New (argc);
9286   for (i = 0; i < argc; ++i)
9287     PyList_SetItem (list, i, PyString_FromString (argv[i]));
9288
9289   return list;
9290 }
9291
9292 static PyObject *
9293 put_table (char * const * const argv)
9294 {
9295   PyObject *list, *item;
9296   int argc, i;
9297
9298   for (argc = 0; argv[argc] != NULL; ++argc)
9299     ;
9300
9301   list = PyList_New (argc >> 1);
9302   for (i = 0; i < argc; i += 2) {
9303     item = PyTuple_New (2);
9304     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
9305     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
9306     PyList_SetItem (list, i >> 1, item);
9307   }
9308
9309   return list;
9310 }
9311
9312 static void
9313 free_strings (char **argv)
9314 {
9315   int argc;
9316
9317   for (argc = 0; argv[argc] != NULL; ++argc)
9318     free (argv[argc]);
9319   free (argv);
9320 }
9321
9322 static PyObject *
9323 py_guestfs_create (PyObject *self, PyObject *args)
9324 {
9325   guestfs_h *g;
9326
9327   g = guestfs_create ();
9328   if (g == NULL) {
9329     PyErr_SetString (PyExc_RuntimeError,
9330                      \"guestfs.create: failed to allocate handle\");
9331     return NULL;
9332   }
9333   guestfs_set_error_handler (g, NULL, NULL);
9334   return put_handle (g);
9335 }
9336
9337 static PyObject *
9338 py_guestfs_close (PyObject *self, PyObject *args)
9339 {
9340   PyObject *py_g;
9341   guestfs_h *g;
9342
9343   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
9344     return NULL;
9345   g = get_handle (py_g);
9346
9347   guestfs_close (g);
9348
9349   Py_INCREF (Py_None);
9350   return Py_None;
9351 }
9352
9353 ";
9354
9355   let emit_put_list_function typ =
9356     pr "static PyObject *\n";
9357     pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
9358     pr "{\n";
9359     pr "  PyObject *list;\n";
9360     pr "  int i;\n";
9361     pr "\n";
9362     pr "  list = PyList_New (%ss->len);\n" typ;
9363     pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
9364     pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
9365     pr "  return list;\n";
9366     pr "};\n";
9367     pr "\n"
9368   in
9369
9370   (* Structures, turned into Python dictionaries. *)
9371   List.iter (
9372     fun (typ, cols) ->
9373       pr "static PyObject *\n";
9374       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
9375       pr "{\n";
9376       pr "  PyObject *dict;\n";
9377       pr "\n";
9378       pr "  dict = PyDict_New ();\n";
9379       List.iter (
9380         function
9381         | name, FString ->
9382             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9383             pr "                        PyString_FromString (%s->%s));\n"
9384               typ name
9385         | name, FBuffer ->
9386             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9387             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
9388               typ name typ name
9389         | name, FUUID ->
9390             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9391             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
9392               typ name
9393         | name, (FBytes|FUInt64) ->
9394             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9395             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
9396               typ name
9397         | name, FInt64 ->
9398             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9399             pr "                        PyLong_FromLongLong (%s->%s));\n"
9400               typ name
9401         | name, FUInt32 ->
9402             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9403             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
9404               typ name
9405         | name, FInt32 ->
9406             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9407             pr "                        PyLong_FromLong (%s->%s));\n"
9408               typ name
9409         | name, FOptPercent ->
9410             pr "  if (%s->%s >= 0)\n" typ name;
9411             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
9412             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
9413               typ name;
9414             pr "  else {\n";
9415             pr "    Py_INCREF (Py_None);\n";
9416             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);\n" name;
9417             pr "  }\n"
9418         | name, FChar ->
9419             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
9420             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
9421       ) cols;
9422       pr "  return dict;\n";
9423       pr "};\n";
9424       pr "\n";
9425
9426   ) structs;
9427
9428   (* Emit a put_TYPE_list function definition only if that function is used. *)
9429   List.iter (
9430     function
9431     | typ, (RStructListOnly | RStructAndList) ->
9432         (* generate the function for typ *)
9433         emit_put_list_function typ
9434     | typ, _ -> () (* empty *)
9435   ) (rstructs_used_by all_functions);
9436
9437   (* Python wrapper functions. *)
9438   List.iter (
9439     fun (name, style, _, _, _, _, _) ->
9440       pr "static PyObject *\n";
9441       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
9442       pr "{\n";
9443
9444       pr "  PyObject *py_g;\n";
9445       pr "  guestfs_h *g;\n";
9446       pr "  PyObject *py_r;\n";
9447
9448       let error_code =
9449         match fst style with
9450         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
9451         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
9452         | RConstString _ | RConstOptString _ ->
9453             pr "  const char *r;\n"; "NULL"
9454         | RString _ -> pr "  char *r;\n"; "NULL"
9455         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
9456         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
9457         | RStructList (_, typ) ->
9458             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
9459         | RBufferOut _ ->
9460             pr "  char *r;\n";
9461             pr "  size_t size;\n";
9462             "NULL" in
9463
9464       List.iter (
9465         function
9466         | Pathname n | Device n | Dev_or_Path n | String n
9467         | FileIn n | FileOut n ->
9468             pr "  const char *%s;\n" n
9469         | OptString n -> pr "  const char *%s;\n" n
9470         | BufferIn n ->
9471             pr "  const char *%s;\n" n;
9472             pr "  Py_ssize_t %s_size;\n" n
9473         | StringList n | DeviceList n ->
9474             pr "  PyObject *py_%s;\n" n;
9475             pr "  char **%s;\n" n
9476         | Bool n -> pr "  int %s;\n" n
9477         | Int n -> pr "  int %s;\n" n
9478         | Int64 n -> pr "  long long %s;\n" n
9479       ) (snd style);
9480
9481       pr "\n";
9482
9483       (* Convert the parameters. *)
9484       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
9485       List.iter (
9486         function
9487         | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "s"
9488         | OptString _ -> pr "z"
9489         | StringList _ | DeviceList _ -> pr "O"
9490         | Bool _ -> pr "i" (* XXX Python has booleans? *)
9491         | Int _ -> pr "i"
9492         | Int64 _ -> pr "L" (* XXX Whoever thought it was a good idea to
9493                              * emulate C's int/long/long long in Python?
9494                              *)
9495         | BufferIn _ -> pr "s#"
9496       ) (snd style);
9497       pr ":guestfs_%s\",\n" name;
9498       pr "                         &py_g";
9499       List.iter (
9500         function
9501         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n -> pr ", &%s" n
9502         | OptString n -> pr ", &%s" n
9503         | StringList n | DeviceList n -> pr ", &py_%s" n
9504         | Bool n -> pr ", &%s" n
9505         | Int n -> pr ", &%s" n
9506         | Int64 n -> pr ", &%s" n
9507         | BufferIn n -> pr ", &%s, &%s_size" n n
9508       ) (snd style);
9509
9510       pr "))\n";
9511       pr "    return NULL;\n";
9512
9513       pr "  g = get_handle (py_g);\n";
9514       List.iter (
9515         function
9516         | Pathname _ | Device _ | Dev_or_Path _ | String _
9517         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
9518         | BufferIn _ -> ()
9519         | StringList n | DeviceList n ->
9520             pr "  %s = get_string_list (py_%s);\n" n n;
9521             pr "  if (!%s) return NULL;\n" n
9522       ) (snd style);
9523
9524       pr "\n";
9525
9526       pr "  r = guestfs_%s " name;
9527       generate_c_call_args ~handle:"g" style;
9528       pr ";\n";
9529
9530       List.iter (
9531         function
9532         | Pathname _ | Device _ | Dev_or_Path _ | String _
9533         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
9534         | BufferIn _ -> ()
9535         | StringList n | DeviceList n ->
9536             pr "  free (%s);\n" n
9537       ) (snd style);
9538
9539       pr "  if (r == %s) {\n" error_code;
9540       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
9541       pr "    return NULL;\n";
9542       pr "  }\n";
9543       pr "\n";
9544
9545       (match fst style with
9546        | RErr ->
9547            pr "  Py_INCREF (Py_None);\n";
9548            pr "  py_r = Py_None;\n"
9549        | RInt _
9550        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
9551        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
9552        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
9553        | RConstOptString _ ->
9554            pr "  if (r)\n";
9555            pr "    py_r = PyString_FromString (r);\n";
9556            pr "  else {\n";
9557            pr "    Py_INCREF (Py_None);\n";
9558            pr "    py_r = Py_None;\n";
9559            pr "  }\n"
9560        | RString _ ->
9561            pr "  py_r = PyString_FromString (r);\n";
9562            pr "  free (r);\n"
9563        | RStringList _ ->
9564            pr "  py_r = put_string_list (r);\n";
9565            pr "  free_strings (r);\n"
9566        | RStruct (_, typ) ->
9567            pr "  py_r = put_%s (r);\n" typ;
9568            pr "  guestfs_free_%s (r);\n" typ
9569        | RStructList (_, typ) ->
9570            pr "  py_r = put_%s_list (r);\n" typ;
9571            pr "  guestfs_free_%s_list (r);\n" typ
9572        | RHashtable n ->
9573            pr "  py_r = put_table (r);\n";
9574            pr "  free_strings (r);\n"
9575        | RBufferOut _ ->
9576            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
9577            pr "  free (r);\n"
9578       );
9579
9580       pr "  return py_r;\n";
9581       pr "}\n";
9582       pr "\n"
9583   ) all_functions;
9584
9585   (* Table of functions. *)
9586   pr "static PyMethodDef methods[] = {\n";
9587   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
9588   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
9589   List.iter (
9590     fun (name, _, _, _, _, _, _) ->
9591       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
9592         name name
9593   ) all_functions;
9594   pr "  { NULL, NULL, 0, NULL }\n";
9595   pr "};\n";
9596   pr "\n";
9597
9598   (* Init function. *)
9599   pr "\
9600 void
9601 initlibguestfsmod (void)
9602 {
9603   static int initialized = 0;
9604
9605   if (initialized) return;
9606   Py_InitModule ((char *) \"libguestfsmod\", methods);
9607   initialized = 1;
9608 }
9609 "
9610
9611 (* Generate Python module. *)
9612 and generate_python_py () =
9613   generate_header HashStyle LGPLv2plus;
9614
9615   pr "\
9616 u\"\"\"Python bindings for libguestfs
9617
9618 import guestfs
9619 g = guestfs.GuestFS ()
9620 g.add_drive (\"guest.img\")
9621 g.launch ()
9622 parts = g.list_partitions ()
9623
9624 The guestfs module provides a Python binding to the libguestfs API
9625 for examining and modifying virtual machine disk images.
9626
9627 Amongst the things this is good for: making batch configuration
9628 changes to guests, getting disk used/free statistics (see also:
9629 virt-df), migrating between virtualization systems (see also:
9630 virt-p2v), performing partial backups, performing partial guest
9631 clones, cloning guests and changing registry/UUID/hostname info, and
9632 much else besides.
9633
9634 Libguestfs uses Linux kernel and qemu code, and can access any type of
9635 guest filesystem that Linux and qemu can, including but not limited
9636 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
9637 schemes, qcow, qcow2, vmdk.
9638
9639 Libguestfs provides ways to enumerate guest storage (eg. partitions,
9640 LVs, what filesystem is in each LV, etc.).  It can also run commands
9641 in the context of the guest.  Also you can access filesystems over
9642 FUSE.
9643
9644 Errors which happen while using the API are turned into Python
9645 RuntimeError exceptions.
9646
9647 To create a guestfs handle you usually have to perform the following
9648 sequence of calls:
9649
9650 # Create the handle, call add_drive at least once, and possibly
9651 # several times if the guest has multiple block devices:
9652 g = guestfs.GuestFS ()
9653 g.add_drive (\"guest.img\")
9654
9655 # Launch the qemu subprocess and wait for it to become ready:
9656 g.launch ()
9657
9658 # Now you can issue commands, for example:
9659 logvols = g.lvs ()
9660
9661 \"\"\"
9662
9663 import libguestfsmod
9664
9665 class GuestFS:
9666     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
9667
9668     def __init__ (self):
9669         \"\"\"Create a new libguestfs handle.\"\"\"
9670         self._o = libguestfsmod.create ()
9671
9672     def __del__ (self):
9673         libguestfsmod.close (self._o)
9674
9675 ";
9676
9677   List.iter (
9678     fun (name, style, _, flags, _, _, longdesc) ->
9679       pr "    def %s " name;
9680       generate_py_call_args ~handle:"self" (snd style);
9681       pr ":\n";
9682
9683       if not (List.mem NotInDocs flags) then (
9684         let doc = replace_str longdesc "C<guestfs_" "C<g." in
9685         let doc =
9686           match fst style with
9687           | RErr | RInt _ | RInt64 _ | RBool _
9688           | RConstOptString _ | RConstString _
9689           | RString _ | RBufferOut _ -> doc
9690           | RStringList _ ->
9691               doc ^ "\n\nThis function returns a list of strings."
9692           | RStruct (_, typ) ->
9693               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
9694           | RStructList (_, typ) ->
9695               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
9696           | RHashtable _ ->
9697               doc ^ "\n\nThis function returns a dictionary." in
9698         let doc =
9699           if List.mem ProtocolLimitWarning flags then
9700             doc ^ "\n\n" ^ protocol_limit_warning
9701           else doc in
9702         let doc =
9703           if List.mem DangerWillRobinson flags then
9704             doc ^ "\n\n" ^ danger_will_robinson
9705           else doc in
9706         let doc =
9707           match deprecation_notice flags with
9708           | None -> doc
9709           | Some txt -> doc ^ "\n\n" ^ txt in
9710         let doc = pod2text ~width:60 name doc in
9711         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
9712         let doc = String.concat "\n        " doc in
9713         pr "        u\"\"\"%s\"\"\"\n" doc;
9714       );
9715       pr "        return libguestfsmod.%s " name;
9716       generate_py_call_args ~handle:"self._o" (snd style);
9717       pr "\n";
9718       pr "\n";
9719   ) all_functions
9720
9721 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
9722 and generate_py_call_args ~handle args =
9723   pr "(%s" handle;
9724   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
9725   pr ")"
9726
9727 (* Useful if you need the longdesc POD text as plain text.  Returns a
9728  * list of lines.
9729  *
9730  * Because this is very slow (the slowest part of autogeneration),
9731  * we memoize the results.
9732  *)
9733 and pod2text ~width name longdesc =
9734   let key = width, name, longdesc in
9735   try Hashtbl.find pod2text_memo key
9736   with Not_found ->
9737     let filename, chan = Filename.open_temp_file "gen" ".tmp" in
9738     fprintf chan "=head1 %s\n\n%s\n" name longdesc;
9739     close_out chan;
9740     let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
9741     let chan = open_process_in cmd in
9742     let lines = ref [] in
9743     let rec loop i =
9744       let line = input_line chan in
9745       if i = 1 then             (* discard the first line of output *)
9746         loop (i+1)
9747       else (
9748         let line = triml line in
9749         lines := line :: !lines;
9750         loop (i+1)
9751       ) in
9752     let lines = try loop 1 with End_of_file -> List.rev !lines in
9753     unlink filename;
9754     (match close_process_in chan with
9755      | WEXITED 0 -> ()
9756      | WEXITED i ->
9757          failwithf "pod2text: process exited with non-zero status (%d)" i
9758      | WSIGNALED i | WSTOPPED i ->
9759          failwithf "pod2text: process signalled or stopped by signal %d" i
9760     );
9761     Hashtbl.add pod2text_memo key lines;
9762     pod2text_memo_updated ();
9763     lines
9764
9765 (* Generate ruby bindings. *)
9766 and generate_ruby_c () =
9767   generate_header CStyle LGPLv2plus;
9768
9769   pr "\
9770 #include <stdio.h>
9771 #include <stdlib.h>
9772
9773 #include <ruby.h>
9774
9775 #include \"guestfs.h\"
9776
9777 #include \"extconf.h\"
9778
9779 /* For Ruby < 1.9 */
9780 #ifndef RARRAY_LEN
9781 #define RARRAY_LEN(r) (RARRAY((r))->len)
9782 #endif
9783
9784 static VALUE m_guestfs;                 /* guestfs module */
9785 static VALUE c_guestfs;                 /* guestfs_h handle */
9786 static VALUE e_Error;                   /* used for all errors */
9787
9788 static void ruby_guestfs_free (void *p)
9789 {
9790   if (!p) return;
9791   guestfs_close ((guestfs_h *) p);
9792 }
9793
9794 static VALUE ruby_guestfs_create (VALUE m)
9795 {
9796   guestfs_h *g;
9797
9798   g = guestfs_create ();
9799   if (!g)
9800     rb_raise (e_Error, \"failed to create guestfs handle\");
9801
9802   /* Don't print error messages to stderr by default. */
9803   guestfs_set_error_handler (g, NULL, NULL);
9804
9805   /* Wrap it, and make sure the close function is called when the
9806    * handle goes away.
9807    */
9808   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
9809 }
9810
9811 static VALUE ruby_guestfs_close (VALUE gv)
9812 {
9813   guestfs_h *g;
9814   Data_Get_Struct (gv, guestfs_h, g);
9815
9816   ruby_guestfs_free (g);
9817   DATA_PTR (gv) = NULL;
9818
9819   return Qnil;
9820 }
9821
9822 ";
9823
9824   List.iter (
9825     fun (name, style, _, _, _, _, _) ->
9826       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
9827       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
9828       pr ")\n";
9829       pr "{\n";
9830       pr "  guestfs_h *g;\n";
9831       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
9832       pr "  if (!g)\n";
9833       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
9834         name;
9835       pr "\n";
9836
9837       List.iter (
9838         function
9839         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
9840             pr "  Check_Type (%sv, T_STRING);\n" n;
9841             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
9842             pr "  if (!%s)\n" n;
9843             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
9844             pr "              \"%s\", \"%s\");\n" n name
9845         | BufferIn n ->
9846             pr "  Check_Type (%sv, T_STRING);\n" n;
9847             pr "  const char *%s = RSTRING (%sv)->ptr;\n" n n;
9848             pr "  if (!%s)\n" n;
9849             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
9850             pr "              \"%s\", \"%s\");\n" n name;
9851             pr "  size_t %s_size = RSTRING (%sv)->len;\n" n n
9852         | OptString n ->
9853             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
9854         | StringList n | DeviceList n ->
9855             pr "  char **%s;\n" n;
9856             pr "  Check_Type (%sv, T_ARRAY);\n" n;
9857             pr "  {\n";
9858             pr "    int i, len;\n";
9859             pr "    len = RARRAY_LEN (%sv);\n" n;
9860             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
9861               n;
9862             pr "    for (i = 0; i < len; ++i) {\n";
9863             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
9864             pr "      %s[i] = StringValueCStr (v);\n" n;
9865             pr "    }\n";
9866             pr "    %s[len] = NULL;\n" n;
9867             pr "  }\n";
9868         | Bool n ->
9869             pr "  int %s = RTEST (%sv);\n" n n
9870         | Int n ->
9871             pr "  int %s = NUM2INT (%sv);\n" n n
9872         | Int64 n ->
9873             pr "  long long %s = NUM2LL (%sv);\n" n n
9874       ) (snd style);
9875       pr "\n";
9876
9877       let error_code =
9878         match fst style with
9879         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
9880         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
9881         | RConstString _ | RConstOptString _ ->
9882             pr "  const char *r;\n"; "NULL"
9883         | RString _ -> pr "  char *r;\n"; "NULL"
9884         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
9885         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
9886         | RStructList (_, typ) ->
9887             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
9888         | RBufferOut _ ->
9889             pr "  char *r;\n";
9890             pr "  size_t size;\n";
9891             "NULL" in
9892       pr "\n";
9893
9894       pr "  r = guestfs_%s " name;
9895       generate_c_call_args ~handle:"g" style;
9896       pr ";\n";
9897
9898       List.iter (
9899         function
9900         | Pathname _ | Device _ | Dev_or_Path _ | String _
9901         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
9902         | BufferIn _ -> ()
9903         | StringList n | DeviceList n ->
9904             pr "  free (%s);\n" n
9905       ) (snd style);
9906
9907       pr "  if (r == %s)\n" error_code;
9908       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
9909       pr "\n";
9910
9911       (match fst style with
9912        | RErr ->
9913            pr "  return Qnil;\n"
9914        | RInt _ | RBool _ ->
9915            pr "  return INT2NUM (r);\n"
9916        | RInt64 _ ->
9917            pr "  return ULL2NUM (r);\n"
9918        | RConstString _ ->
9919            pr "  return rb_str_new2 (r);\n";
9920        | RConstOptString _ ->
9921            pr "  if (r)\n";
9922            pr "    return rb_str_new2 (r);\n";
9923            pr "  else\n";
9924            pr "    return Qnil;\n";
9925        | RString _ ->
9926            pr "  VALUE rv = rb_str_new2 (r);\n";
9927            pr "  free (r);\n";
9928            pr "  return rv;\n";
9929        | RStringList _ ->
9930            pr "  int i, len = 0;\n";
9931            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
9932            pr "  VALUE rv = rb_ary_new2 (len);\n";
9933            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
9934            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
9935            pr "    free (r[i]);\n";
9936            pr "  }\n";
9937            pr "  free (r);\n";
9938            pr "  return rv;\n"
9939        | RStruct (_, typ) ->
9940            let cols = cols_of_struct typ in
9941            generate_ruby_struct_code typ cols
9942        | RStructList (_, typ) ->
9943            let cols = cols_of_struct typ in
9944            generate_ruby_struct_list_code typ cols
9945        | RHashtable _ ->
9946            pr "  VALUE rv = rb_hash_new ();\n";
9947            pr "  int i;\n";
9948            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
9949            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
9950            pr "    free (r[i]);\n";
9951            pr "    free (r[i+1]);\n";
9952            pr "  }\n";
9953            pr "  free (r);\n";
9954            pr "  return rv;\n"
9955        | RBufferOut _ ->
9956            pr "  VALUE rv = rb_str_new (r, size);\n";
9957            pr "  free (r);\n";
9958            pr "  return rv;\n";
9959       );
9960
9961       pr "}\n";
9962       pr "\n"
9963   ) all_functions;
9964
9965   pr "\
9966 /* Initialize the module. */
9967 void Init__guestfs ()
9968 {
9969   m_guestfs = rb_define_module (\"Guestfs\");
9970   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
9971   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
9972
9973   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
9974   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
9975
9976 ";
9977   (* Define the rest of the methods. *)
9978   List.iter (
9979     fun (name, style, _, _, _, _, _) ->
9980       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
9981       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
9982   ) all_functions;
9983
9984   pr "}\n"
9985
9986 (* Ruby code to return a struct. *)
9987 and generate_ruby_struct_code typ cols =
9988   pr "  VALUE rv = rb_hash_new ();\n";
9989   List.iter (
9990     function
9991     | name, FString ->
9992         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
9993     | name, FBuffer ->
9994         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
9995     | name, FUUID ->
9996         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
9997     | name, (FBytes|FUInt64) ->
9998         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
9999     | name, FInt64 ->
10000         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
10001     | name, FUInt32 ->
10002         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
10003     | name, FInt32 ->
10004         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
10005     | name, FOptPercent ->
10006         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
10007     | name, FChar -> (* XXX wrong? *)
10008         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
10009   ) cols;
10010   pr "  guestfs_free_%s (r);\n" typ;
10011   pr "  return rv;\n"
10012
10013 (* Ruby code to return a struct list. *)
10014 and generate_ruby_struct_list_code typ cols =
10015   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
10016   pr "  int i;\n";
10017   pr "  for (i = 0; i < r->len; ++i) {\n";
10018   pr "    VALUE hv = rb_hash_new ();\n";
10019   List.iter (
10020     function
10021     | name, FString ->
10022         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
10023     | name, FBuffer ->
10024         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
10025     | name, FUUID ->
10026         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
10027     | name, (FBytes|FUInt64) ->
10028         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
10029     | name, FInt64 ->
10030         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
10031     | name, FUInt32 ->
10032         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
10033     | name, FInt32 ->
10034         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
10035     | name, FOptPercent ->
10036         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
10037     | name, FChar -> (* XXX wrong? *)
10038         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
10039   ) cols;
10040   pr "    rb_ary_push (rv, hv);\n";
10041   pr "  }\n";
10042   pr "  guestfs_free_%s_list (r);\n" typ;
10043   pr "  return rv;\n"
10044
10045 (* Generate Java bindings GuestFS.java file. *)
10046 and generate_java_java () =
10047   generate_header CStyle LGPLv2plus;
10048
10049   pr "\
10050 package com.redhat.et.libguestfs;
10051
10052 import java.util.HashMap;
10053 import com.redhat.et.libguestfs.LibGuestFSException;
10054 import com.redhat.et.libguestfs.PV;
10055 import com.redhat.et.libguestfs.VG;
10056 import com.redhat.et.libguestfs.LV;
10057 import com.redhat.et.libguestfs.Stat;
10058 import com.redhat.et.libguestfs.StatVFS;
10059 import com.redhat.et.libguestfs.IntBool;
10060 import com.redhat.et.libguestfs.Dirent;
10061
10062 /**
10063  * The GuestFS object is a libguestfs handle.
10064  *
10065  * @author rjones
10066  */
10067 public class GuestFS {
10068   // Load the native code.
10069   static {
10070     System.loadLibrary (\"guestfs_jni\");
10071   }
10072
10073   /**
10074    * The native guestfs_h pointer.
10075    */
10076   long g;
10077
10078   /**
10079    * Create a libguestfs handle.
10080    *
10081    * @throws LibGuestFSException
10082    */
10083   public GuestFS () throws LibGuestFSException
10084   {
10085     g = _create ();
10086   }
10087   private native long _create () throws LibGuestFSException;
10088
10089   /**
10090    * Close a libguestfs handle.
10091    *
10092    * You can also leave handles to be collected by the garbage
10093    * collector, but this method ensures that the resources used
10094    * by the handle are freed up immediately.  If you call any
10095    * other methods after closing the handle, you will get an
10096    * exception.
10097    *
10098    * @throws LibGuestFSException
10099    */
10100   public void close () throws LibGuestFSException
10101   {
10102     if (g != 0)
10103       _close (g);
10104     g = 0;
10105   }
10106   private native void _close (long g) throws LibGuestFSException;
10107
10108   public void finalize () throws LibGuestFSException
10109   {
10110     close ();
10111   }
10112
10113 ";
10114
10115   List.iter (
10116     fun (name, style, _, flags, _, shortdesc, longdesc) ->
10117       if not (List.mem NotInDocs flags); then (
10118         let doc = replace_str longdesc "C<guestfs_" "C<g." in
10119         let doc =
10120           if List.mem ProtocolLimitWarning flags then
10121             doc ^ "\n\n" ^ protocol_limit_warning
10122           else doc in
10123         let doc =
10124           if List.mem DangerWillRobinson flags then
10125             doc ^ "\n\n" ^ danger_will_robinson
10126           else doc in
10127         let doc =
10128           match deprecation_notice flags with
10129           | None -> doc
10130           | Some txt -> doc ^ "\n\n" ^ txt in
10131         let doc = pod2text ~width:60 name doc in
10132         let doc = List.map (            (* RHBZ#501883 *)
10133           function
10134           | "" -> "<p>"
10135           | nonempty -> nonempty
10136         ) doc in
10137         let doc = String.concat "\n   * " doc in
10138
10139         pr "  /**\n";
10140         pr "   * %s\n" shortdesc;
10141         pr "   * <p>\n";
10142         pr "   * %s\n" doc;
10143         pr "   * @throws LibGuestFSException\n";
10144         pr "   */\n";
10145         pr "  ";
10146       );
10147       generate_java_prototype ~public:true ~semicolon:false name style;
10148       pr "\n";
10149       pr "  {\n";
10150       pr "    if (g == 0)\n";
10151       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
10152         name;
10153       pr "    ";
10154       if fst style <> RErr then pr "return ";
10155       pr "_%s " name;
10156       generate_java_call_args ~handle:"g" (snd style);
10157       pr ";\n";
10158       pr "  }\n";
10159       pr "  ";
10160       generate_java_prototype ~privat:true ~native:true name style;
10161       pr "\n";
10162       pr "\n";
10163   ) all_functions;
10164
10165   pr "}\n"
10166
10167 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
10168 and generate_java_call_args ~handle args =
10169   pr "(%s" handle;
10170   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
10171   pr ")"
10172
10173 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
10174     ?(semicolon=true) name style =
10175   if privat then pr "private ";
10176   if public then pr "public ";
10177   if native then pr "native ";
10178
10179   (* return type *)
10180   (match fst style with
10181    | RErr -> pr "void ";
10182    | RInt _ -> pr "int ";
10183    | RInt64 _ -> pr "long ";
10184    | RBool _ -> pr "boolean ";
10185    | RConstString _ | RConstOptString _ | RString _
10186    | RBufferOut _ -> pr "String ";
10187    | RStringList _ -> pr "String[] ";
10188    | RStruct (_, typ) ->
10189        let name = java_name_of_struct typ in
10190        pr "%s " name;
10191    | RStructList (_, typ) ->
10192        let name = java_name_of_struct typ in
10193        pr "%s[] " name;
10194    | RHashtable _ -> pr "HashMap<String,String> ";
10195   );
10196
10197   if native then pr "_%s " name else pr "%s " name;
10198   pr "(";
10199   let needs_comma = ref false in
10200   if native then (
10201     pr "long g";
10202     needs_comma := true
10203   );
10204
10205   (* args *)
10206   List.iter (
10207     fun arg ->
10208       if !needs_comma then pr ", ";
10209       needs_comma := true;
10210
10211       match arg with
10212       | Pathname n
10213       | Device n | Dev_or_Path n
10214       | String n
10215       | OptString n
10216       | FileIn n
10217       | FileOut n ->
10218           pr "String %s" n
10219       | BufferIn n ->
10220           pr "byte[] %s" n
10221       | StringList n | DeviceList n ->
10222           pr "String[] %s" n
10223       | Bool n ->
10224           pr "boolean %s" n
10225       | Int n ->
10226           pr "int %s" n
10227       | Int64 n ->
10228           pr "long %s" n
10229   ) (snd style);
10230
10231   pr ")\n";
10232   pr "    throws LibGuestFSException";
10233   if semicolon then pr ";"
10234
10235 and generate_java_struct jtyp cols () =
10236   generate_header CStyle LGPLv2plus;
10237
10238   pr "\
10239 package com.redhat.et.libguestfs;
10240
10241 /**
10242  * Libguestfs %s structure.
10243  *
10244  * @author rjones
10245  * @see GuestFS
10246  */
10247 public class %s {
10248 " jtyp jtyp;
10249
10250   List.iter (
10251     function
10252     | name, FString
10253     | name, FUUID
10254     | name, FBuffer -> pr "  public String %s;\n" name
10255     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
10256     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
10257     | name, FChar -> pr "  public char %s;\n" name
10258     | name, FOptPercent ->
10259         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
10260         pr "  public float %s;\n" name
10261   ) cols;
10262
10263   pr "}\n"
10264
10265 and generate_java_c () =
10266   generate_header CStyle LGPLv2plus;
10267
10268   pr "\
10269 #include <stdio.h>
10270 #include <stdlib.h>
10271 #include <string.h>
10272
10273 #include \"com_redhat_et_libguestfs_GuestFS.h\"
10274 #include \"guestfs.h\"
10275
10276 /* Note that this function returns.  The exception is not thrown
10277  * until after the wrapper function returns.
10278  */
10279 static void
10280 throw_exception (JNIEnv *env, const char *msg)
10281 {
10282   jclass cl;
10283   cl = (*env)->FindClass (env,
10284                           \"com/redhat/et/libguestfs/LibGuestFSException\");
10285   (*env)->ThrowNew (env, cl, msg);
10286 }
10287
10288 JNIEXPORT jlong JNICALL
10289 Java_com_redhat_et_libguestfs_GuestFS__1create
10290   (JNIEnv *env, jobject obj)
10291 {
10292   guestfs_h *g;
10293
10294   g = guestfs_create ();
10295   if (g == NULL) {
10296     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
10297     return 0;
10298   }
10299   guestfs_set_error_handler (g, NULL, NULL);
10300   return (jlong) (long) g;
10301 }
10302
10303 JNIEXPORT void JNICALL
10304 Java_com_redhat_et_libguestfs_GuestFS__1close
10305   (JNIEnv *env, jobject obj, jlong jg)
10306 {
10307   guestfs_h *g = (guestfs_h *) (long) jg;
10308   guestfs_close (g);
10309 }
10310
10311 ";
10312
10313   List.iter (
10314     fun (name, style, _, _, _, _, _) ->
10315       pr "JNIEXPORT ";
10316       (match fst style with
10317        | RErr -> pr "void ";
10318        | RInt _ -> pr "jint ";
10319        | RInt64 _ -> pr "jlong ";
10320        | RBool _ -> pr "jboolean ";
10321        | RConstString _ | RConstOptString _ | RString _
10322        | RBufferOut _ -> pr "jstring ";
10323        | RStruct _ | RHashtable _ ->
10324            pr "jobject ";
10325        | RStringList _ | RStructList _ ->
10326            pr "jobjectArray ";
10327       );
10328       pr "JNICALL\n";
10329       pr "Java_com_redhat_et_libguestfs_GuestFS_";
10330       pr "%s" (replace_str ("_" ^ name) "_" "_1");
10331       pr "\n";
10332       pr "  (JNIEnv *env, jobject obj, jlong jg";
10333       List.iter (
10334         function
10335         | Pathname n
10336         | Device n | Dev_or_Path n
10337         | String n
10338         | OptString n
10339         | FileIn n
10340         | FileOut n ->
10341             pr ", jstring j%s" n
10342         | BufferIn n ->
10343             pr ", jbyteArray j%s" n
10344         | StringList n | DeviceList n ->
10345             pr ", jobjectArray j%s" n
10346         | Bool n ->
10347             pr ", jboolean j%s" n
10348         | Int n ->
10349             pr ", jint j%s" n
10350         | Int64 n ->
10351             pr ", jlong j%s" n
10352       ) (snd style);
10353       pr ")\n";
10354       pr "{\n";
10355       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
10356       let error_code, no_ret =
10357         match fst style with
10358         | RErr -> pr "  int r;\n"; "-1", ""
10359         | RBool _
10360         | RInt _ -> pr "  int r;\n"; "-1", "0"
10361         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
10362         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
10363         | RConstOptString _ -> pr "  const char *r;\n"; "NULL", "NULL"
10364         | RString _ ->
10365             pr "  jstring jr;\n";
10366             pr "  char *r;\n"; "NULL", "NULL"
10367         | RStringList _ ->
10368             pr "  jobjectArray jr;\n";
10369             pr "  int r_len;\n";
10370             pr "  jclass cl;\n";
10371             pr "  jstring jstr;\n";
10372             pr "  char **r;\n"; "NULL", "NULL"
10373         | RStruct (_, typ) ->
10374             pr "  jobject jr;\n";
10375             pr "  jclass cl;\n";
10376             pr "  jfieldID fl;\n";
10377             pr "  struct guestfs_%s *r;\n" typ; "NULL", "NULL"
10378         | RStructList (_, typ) ->
10379             pr "  jobjectArray jr;\n";
10380             pr "  jclass cl;\n";
10381             pr "  jfieldID fl;\n";
10382             pr "  jobject jfl;\n";
10383             pr "  struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
10384         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL"
10385         | RBufferOut _ ->
10386             pr "  jstring jr;\n";
10387             pr "  char *r;\n";
10388             pr "  size_t size;\n";
10389             "NULL", "NULL" in
10390       List.iter (
10391         function
10392         | Pathname n
10393         | Device n | Dev_or_Path n
10394         | String n
10395         | OptString n
10396         | FileIn n
10397         | FileOut n ->
10398             pr "  const char *%s;\n" n
10399         | BufferIn n ->
10400             pr "  jbyte *%s;\n" n;
10401             pr "  size_t %s_size;\n" n
10402         | StringList n | DeviceList n ->
10403             pr "  int %s_len;\n" n;
10404             pr "  const char **%s;\n" n
10405         | Bool n
10406         | Int n ->
10407             pr "  int %s;\n" n
10408         | Int64 n ->
10409             pr "  int64_t %s;\n" n
10410       ) (snd style);
10411
10412       let needs_i =
10413         (match fst style with
10414          | RStringList _ | RStructList _ -> true
10415          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
10416          | RConstOptString _
10417          | RString _ | RBufferOut _ | RStruct _ | RHashtable _ -> false) ||
10418           List.exists (function
10419                        | StringList _ -> true
10420                        | DeviceList _ -> true
10421                        | _ -> false) (snd style) in
10422       if needs_i then
10423         pr "  int i;\n";
10424
10425       pr "\n";
10426
10427       (* Get the parameters. *)
10428       List.iter (
10429         function
10430         | Pathname n
10431         | Device n | Dev_or_Path n
10432         | String n
10433         | FileIn n
10434         | FileOut n ->
10435             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
10436         | OptString n ->
10437             (* This is completely undocumented, but Java null becomes
10438              * a NULL parameter.
10439              *)
10440             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
10441         | BufferIn n ->
10442             pr "  %s = (*env)->GetByteArrayElements (env, j%s, NULL);\n" n n;
10443             pr "  %s_size = (*env)->GetArrayLength (env, j%s);\n" n n
10444         | StringList n | DeviceList n ->
10445             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
10446             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
10447             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
10448             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
10449               n;
10450             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
10451             pr "  }\n";
10452             pr "  %s[%s_len] = NULL;\n" n n;
10453         | Bool n
10454         | Int n
10455         | Int64 n ->
10456             pr "  %s = j%s;\n" n n
10457       ) (snd style);
10458
10459       (* Make the call. *)
10460       pr "  r = guestfs_%s " name;
10461       generate_c_call_args ~handle:"g" style;
10462       pr ";\n";
10463
10464       (* Release the parameters. *)
10465       List.iter (
10466         function
10467         | Pathname n
10468         | Device n | Dev_or_Path n
10469         | String n
10470         | FileIn n
10471         | FileOut n ->
10472             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
10473         | OptString n ->
10474             pr "  if (j%s)\n" n;
10475             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
10476         | BufferIn n ->
10477             pr "  (*env)->ReleaseByteArrayElements (env, j%s, %s, 0);\n" n n
10478         | StringList n | DeviceList n ->
10479             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
10480             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
10481               n;
10482             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
10483             pr "  }\n";
10484             pr "  free (%s);\n" n
10485         | Bool n
10486         | Int n
10487         | Int64 n -> ()
10488       ) (snd style);
10489
10490       (* Check for errors. *)
10491       pr "  if (r == %s) {\n" error_code;
10492       pr "    throw_exception (env, guestfs_last_error (g));\n";
10493       pr "    return %s;\n" no_ret;
10494       pr "  }\n";
10495
10496       (* Return value. *)
10497       (match fst style with
10498        | RErr -> ()
10499        | RInt _ -> pr "  return (jint) r;\n"
10500        | RBool _ -> pr "  return (jboolean) r;\n"
10501        | RInt64 _ -> pr "  return (jlong) r;\n"
10502        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
10503        | RConstOptString _ ->
10504            pr "  return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
10505        | RString _ ->
10506            pr "  jr = (*env)->NewStringUTF (env, r);\n";
10507            pr "  free (r);\n";
10508            pr "  return jr;\n"
10509        | RStringList _ ->
10510            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
10511            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
10512            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
10513            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
10514            pr "  for (i = 0; i < r_len; ++i) {\n";
10515            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
10516            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
10517            pr "    free (r[i]);\n";
10518            pr "  }\n";
10519            pr "  free (r);\n";
10520            pr "  return jr;\n"
10521        | RStruct (_, typ) ->
10522            let jtyp = java_name_of_struct typ in
10523            let cols = cols_of_struct typ in
10524            generate_java_struct_return typ jtyp cols
10525        | RStructList (_, typ) ->
10526            let jtyp = java_name_of_struct typ in
10527            let cols = cols_of_struct typ in
10528            generate_java_struct_list_return typ jtyp cols
10529        | RHashtable _ ->
10530            (* XXX *)
10531            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
10532            pr "  return NULL;\n"
10533        | RBufferOut _ ->
10534            pr "  jr = (*env)->NewStringUTF (env, r); /* XXX size */\n";
10535            pr "  free (r);\n";
10536            pr "  return jr;\n"
10537       );
10538
10539       pr "}\n";
10540       pr "\n"
10541   ) all_functions
10542
10543 and generate_java_struct_return typ jtyp cols =
10544   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
10545   pr "  jr = (*env)->AllocObject (env, cl);\n";
10546   List.iter (
10547     function
10548     | name, FString ->
10549         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10550         pr "  (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
10551     | name, FUUID ->
10552         pr "  {\n";
10553         pr "    char s[33];\n";
10554         pr "    memcpy (s, r->%s, 32);\n" name;
10555         pr "    s[32] = 0;\n";
10556         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10557         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
10558         pr "  }\n";
10559     | name, FBuffer ->
10560         pr "  {\n";
10561         pr "    int len = r->%s_len;\n" name;
10562         pr "    char s[len+1];\n";
10563         pr "    memcpy (s, r->%s, len);\n" name;
10564         pr "    s[len] = 0;\n";
10565         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10566         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
10567         pr "  }\n";
10568     | name, (FBytes|FUInt64|FInt64) ->
10569         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
10570         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10571     | name, (FUInt32|FInt32) ->
10572         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
10573         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10574     | name, FOptPercent ->
10575         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
10576         pr "  (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
10577     | name, FChar ->
10578         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
10579         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
10580   ) cols;
10581   pr "  free (r);\n";
10582   pr "  return jr;\n"
10583
10584 and generate_java_struct_list_return typ jtyp cols =
10585   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
10586   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
10587   pr "  for (i = 0; i < r->len; ++i) {\n";
10588   pr "    jfl = (*env)->AllocObject (env, cl);\n";
10589   List.iter (
10590     function
10591     | name, FString ->
10592         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10593         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
10594     | name, FUUID ->
10595         pr "    {\n";
10596         pr "      char s[33];\n";
10597         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
10598         pr "      s[32] = 0;\n";
10599         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10600         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
10601         pr "    }\n";
10602     | name, FBuffer ->
10603         pr "    {\n";
10604         pr "      int len = r->val[i].%s_len;\n" name;
10605         pr "      char s[len+1];\n";
10606         pr "      memcpy (s, r->val[i].%s, len);\n" name;
10607         pr "      s[len] = 0;\n";
10608         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
10609         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
10610         pr "    }\n";
10611     | name, (FBytes|FUInt64|FInt64) ->
10612         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
10613         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10614     | name, (FUInt32|FInt32) ->
10615         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
10616         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10617     | name, FOptPercent ->
10618         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
10619         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
10620     | name, FChar ->
10621         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
10622         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
10623   ) cols;
10624   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
10625   pr "  }\n";
10626   pr "  guestfs_free_%s_list (r);\n" typ;
10627   pr "  return jr;\n"
10628
10629 and generate_java_makefile_inc () =
10630   generate_header HashStyle GPLv2plus;
10631
10632   pr "java_built_sources = \\\n";
10633   List.iter (
10634     fun (typ, jtyp) ->
10635         pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp;
10636   ) java_structs;
10637   pr "\tcom/redhat/et/libguestfs/GuestFS.java\n"
10638
10639 and generate_haskell_hs () =
10640   generate_header HaskellStyle LGPLv2plus;
10641
10642   (* XXX We only know how to generate partial FFI for Haskell
10643    * at the moment.  Please help out!
10644    *)
10645   let can_generate style =
10646     match style with
10647     | RErr, _
10648     | RInt _, _
10649     | RInt64 _, _ -> true
10650     | RBool _, _
10651     | RConstString _, _
10652     | RConstOptString _, _
10653     | RString _, _
10654     | RStringList _, _
10655     | RStruct _, _
10656     | RStructList _, _
10657     | RHashtable _, _
10658     | RBufferOut _, _ -> false in
10659
10660   pr "\
10661 {-# INCLUDE <guestfs.h> #-}
10662 {-# LANGUAGE ForeignFunctionInterface #-}
10663
10664 module Guestfs (
10665   create";
10666
10667   (* List out the names of the actions we want to export. *)
10668   List.iter (
10669     fun (name, style, _, _, _, _, _) ->
10670       if can_generate style then pr ",\n  %s" name
10671   ) all_functions;
10672
10673   pr "
10674   ) where
10675
10676 -- Unfortunately some symbols duplicate ones already present
10677 -- in Prelude.  We don't know which, so we hard-code a list
10678 -- here.
10679 import Prelude hiding (truncate)
10680
10681 import Foreign
10682 import Foreign.C
10683 import Foreign.C.Types
10684 import IO
10685 import Control.Exception
10686 import Data.Typeable
10687
10688 data GuestfsS = GuestfsS            -- represents the opaque C struct
10689 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
10690 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
10691
10692 -- XXX define properly later XXX
10693 data PV = PV
10694 data VG = VG
10695 data LV = LV
10696 data IntBool = IntBool
10697 data Stat = Stat
10698 data StatVFS = StatVFS
10699 data Hashtable = Hashtable
10700
10701 foreign import ccall unsafe \"guestfs_create\" c_create
10702   :: IO GuestfsP
10703 foreign import ccall unsafe \"&guestfs_close\" c_close
10704   :: FunPtr (GuestfsP -> IO ())
10705 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
10706   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
10707
10708 create :: IO GuestfsH
10709 create = do
10710   p <- c_create
10711   c_set_error_handler p nullPtr nullPtr
10712   h <- newForeignPtr c_close p
10713   return h
10714
10715 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
10716   :: GuestfsP -> IO CString
10717
10718 -- last_error :: GuestfsH -> IO (Maybe String)
10719 -- last_error h = do
10720 --   str <- withForeignPtr h (\\p -> c_last_error p)
10721 --   maybePeek peekCString str
10722
10723 last_error :: GuestfsH -> IO (String)
10724 last_error h = do
10725   str <- withForeignPtr h (\\p -> c_last_error p)
10726   if (str == nullPtr)
10727     then return \"no error\"
10728     else peekCString str
10729
10730 ";
10731
10732   (* Generate wrappers for each foreign function. *)
10733   List.iter (
10734     fun (name, style, _, _, _, _, _) ->
10735       if can_generate style then (
10736         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
10737         pr "  :: ";
10738         generate_haskell_prototype ~handle:"GuestfsP" style;
10739         pr "\n";
10740         pr "\n";
10741         pr "%s :: " name;
10742         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
10743         pr "\n";
10744         pr "%s %s = do\n" name
10745           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
10746         pr "  r <- ";
10747         (* Convert pointer arguments using with* functions. *)
10748         List.iter (
10749           function
10750           | FileIn n
10751           | FileOut n
10752           | Pathname n | Device n | Dev_or_Path n | String n ->
10753               pr "withCString %s $ \\%s -> " n n
10754           | BufferIn n ->
10755               pr "withCStringLen %s $ \\(%s, %s_size) -> " n n n
10756           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
10757           | StringList n | DeviceList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
10758           | Bool _ | Int _ | Int64 _ -> ()
10759         ) (snd style);
10760         (* Convert integer arguments. *)
10761         let args =
10762           List.map (
10763             function
10764             | Bool n -> sprintf "(fromBool %s)" n
10765             | Int n -> sprintf "(fromIntegral %s)" n
10766             | Int64 n -> sprintf "(fromIntegral %s)" n
10767             | FileIn n | FileOut n
10768             | Pathname n | Device n | Dev_or_Path n | String n | OptString n | StringList n | DeviceList n -> n
10769             | BufferIn n -> sprintf "%s (fromIntegral %s_size)" n n
10770           ) (snd style) in
10771         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
10772           (String.concat " " ("p" :: args));
10773         (match fst style with
10774          | RErr | RInt _ | RInt64 _ | RBool _ ->
10775              pr "  if (r == -1)\n";
10776              pr "    then do\n";
10777              pr "      err <- last_error h\n";
10778              pr "      fail err\n";
10779          | RConstString _ | RConstOptString _ | RString _
10780          | RStringList _ | RStruct _
10781          | RStructList _ | RHashtable _ | RBufferOut _ ->
10782              pr "  if (r == nullPtr)\n";
10783              pr "    then do\n";
10784              pr "      err <- last_error h\n";
10785              pr "      fail err\n";
10786         );
10787         (match fst style with
10788          | RErr ->
10789              pr "    else return ()\n"
10790          | RInt _ ->
10791              pr "    else return (fromIntegral r)\n"
10792          | RInt64 _ ->
10793              pr "    else return (fromIntegral r)\n"
10794          | RBool _ ->
10795              pr "    else return (toBool r)\n"
10796          | RConstString _
10797          | RConstOptString _
10798          | RString _
10799          | RStringList _
10800          | RStruct _
10801          | RStructList _
10802          | RHashtable _
10803          | RBufferOut _ ->
10804              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
10805         );
10806         pr "\n";
10807       )
10808   ) all_functions
10809
10810 and generate_haskell_prototype ~handle ?(hs = false) style =
10811   pr "%s -> " handle;
10812   let string = if hs then "String" else "CString" in
10813   let int = if hs then "Int" else "CInt" in
10814   let bool = if hs then "Bool" else "CInt" in
10815   let int64 = if hs then "Integer" else "Int64" in
10816   List.iter (
10817     fun arg ->
10818       (match arg with
10819        | Pathname _ | Device _ | Dev_or_Path _ | String _ -> pr "%s" string
10820        | BufferIn _ ->
10821            if hs then pr "String"
10822            else pr "CString -> CInt"
10823        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
10824        | StringList _ | DeviceList _ -> if hs then pr "[String]" else pr "Ptr CString"
10825        | Bool _ -> pr "%s" bool
10826        | Int _ -> pr "%s" int
10827        | Int64 _ -> pr "%s" int
10828        | FileIn _ -> pr "%s" string
10829        | FileOut _ -> pr "%s" string
10830       );
10831       pr " -> ";
10832   ) (snd style);
10833   pr "IO (";
10834   (match fst style with
10835    | RErr -> if not hs then pr "CInt"
10836    | RInt _ -> pr "%s" int
10837    | RInt64 _ -> pr "%s" int64
10838    | RBool _ -> pr "%s" bool
10839    | RConstString _ -> pr "%s" string
10840    | RConstOptString _ -> pr "Maybe %s" string
10841    | RString _ -> pr "%s" string
10842    | RStringList _ -> pr "[%s]" string
10843    | RStruct (_, typ) ->
10844        let name = java_name_of_struct typ in
10845        pr "%s" name
10846    | RStructList (_, typ) ->
10847        let name = java_name_of_struct typ in
10848        pr "[%s]" name
10849    | RHashtable _ -> pr "Hashtable"
10850    | RBufferOut _ -> pr "%s" string
10851   );
10852   pr ")"
10853
10854 and generate_csharp () =
10855   generate_header CPlusPlusStyle LGPLv2plus;
10856
10857   (* XXX Make this configurable by the C# assembly users. *)
10858   let library = "libguestfs.so.0" in
10859
10860   pr "\
10861 // These C# bindings are highly experimental at present.
10862 //
10863 // Firstly they only work on Linux (ie. Mono).  In order to get them
10864 // to work on Windows (ie. .Net) you would need to port the library
10865 // itself to Windows first.
10866 //
10867 // The second issue is that some calls are known to be incorrect and
10868 // can cause Mono to segfault.  Particularly: calls which pass or
10869 // return string[], or return any structure value.  This is because
10870 // we haven't worked out the correct way to do this from C#.
10871 //
10872 // The third issue is that when compiling you get a lot of warnings.
10873 // We are not sure whether the warnings are important or not.
10874 //
10875 // Fourthly we do not routinely build or test these bindings as part
10876 // of the make && make check cycle, which means that regressions might
10877 // go unnoticed.
10878 //
10879 // Suggestions and patches are welcome.
10880
10881 // To compile:
10882 //
10883 // gmcs Libguestfs.cs
10884 // mono Libguestfs.exe
10885 //
10886 // (You'll probably want to add a Test class / static main function
10887 // otherwise this won't do anything useful).
10888
10889 using System;
10890 using System.IO;
10891 using System.Runtime.InteropServices;
10892 using System.Runtime.Serialization;
10893 using System.Collections;
10894
10895 namespace Guestfs
10896 {
10897   class Error : System.ApplicationException
10898   {
10899     public Error (string message) : base (message) {}
10900     protected Error (SerializationInfo info, StreamingContext context) {}
10901   }
10902
10903   class Guestfs
10904   {
10905     IntPtr _handle;
10906
10907     [DllImport (\"%s\")]
10908     static extern IntPtr guestfs_create ();
10909
10910     public Guestfs ()
10911     {
10912       _handle = guestfs_create ();
10913       if (_handle == IntPtr.Zero)
10914         throw new Error (\"could not create guestfs handle\");
10915     }
10916
10917     [DllImport (\"%s\")]
10918     static extern void guestfs_close (IntPtr h);
10919
10920     ~Guestfs ()
10921     {
10922       guestfs_close (_handle);
10923     }
10924
10925     [DllImport (\"%s\")]
10926     static extern string guestfs_last_error (IntPtr h);
10927
10928 " library library library;
10929
10930   (* Generate C# structure bindings.  We prefix struct names with
10931    * underscore because C# cannot have conflicting struct names and
10932    * method names (eg. "class stat" and "stat").
10933    *)
10934   List.iter (
10935     fun (typ, cols) ->
10936       pr "    [StructLayout (LayoutKind.Sequential)]\n";
10937       pr "    public class _%s {\n" typ;
10938       List.iter (
10939         function
10940         | name, FChar -> pr "      char %s;\n" name
10941         | name, FString -> pr "      string %s;\n" name
10942         | name, FBuffer ->
10943             pr "      uint %s_len;\n" name;
10944             pr "      string %s;\n" name
10945         | name, FUUID ->
10946             pr "      [MarshalAs (UnmanagedType.ByValTStr, SizeConst=16)]\n";
10947             pr "      string %s;\n" name
10948         | name, FUInt32 -> pr "      uint %s;\n" name
10949         | name, FInt32 -> pr "      int %s;\n" name
10950         | name, (FUInt64|FBytes) -> pr "      ulong %s;\n" name
10951         | name, FInt64 -> pr "      long %s;\n" name
10952         | name, FOptPercent -> pr "      float %s; /* [0..100] or -1 */\n" name
10953       ) cols;
10954       pr "    }\n";
10955       pr "\n"
10956   ) structs;
10957
10958   (* Generate C# function bindings. *)
10959   List.iter (
10960     fun (name, style, _, _, _, shortdesc, _) ->
10961       let rec csharp_return_type () =
10962         match fst style with
10963         | RErr -> "void"
10964         | RBool n -> "bool"
10965         | RInt n -> "int"
10966         | RInt64 n -> "long"
10967         | RConstString n
10968         | RConstOptString n
10969         | RString n
10970         | RBufferOut n -> "string"
10971         | RStruct (_,n) -> "_" ^ n
10972         | RHashtable n -> "Hashtable"
10973         | RStringList n -> "string[]"
10974         | RStructList (_,n) -> sprintf "_%s[]" n
10975
10976       and c_return_type () =
10977         match fst style with
10978         | RErr
10979         | RBool _
10980         | RInt _ -> "int"
10981         | RInt64 _ -> "long"
10982         | RConstString _
10983         | RConstOptString _
10984         | RString _
10985         | RBufferOut _ -> "string"
10986         | RStruct (_,n) -> "_" ^ n
10987         | RHashtable _
10988         | RStringList _ -> "string[]"
10989         | RStructList (_,n) -> sprintf "_%s[]" n
10990
10991       and c_error_comparison () =
10992         match fst style with
10993         | RErr
10994         | RBool _
10995         | RInt _
10996         | RInt64 _ -> "== -1"
10997         | RConstString _
10998         | RConstOptString _
10999         | RString _
11000         | RBufferOut _
11001         | RStruct (_,_)
11002         | RHashtable _
11003         | RStringList _
11004         | RStructList (_,_) -> "== null"
11005
11006       and generate_extern_prototype () =
11007         pr "    static extern %s guestfs_%s (IntPtr h"
11008           (c_return_type ()) name;
11009         List.iter (
11010           function
11011           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
11012           | FileIn n | FileOut n
11013           | BufferIn n ->
11014               pr ", [In] string %s" n
11015           | StringList n | DeviceList n ->
11016               pr ", [In] string[] %s" n
11017           | Bool n ->
11018               pr ", bool %s" n
11019           | Int n ->
11020               pr ", int %s" n
11021           | Int64 n ->
11022               pr ", long %s" n
11023         ) (snd style);
11024         pr ");\n"
11025
11026       and generate_public_prototype () =
11027         pr "    public %s %s (" (csharp_return_type ()) name;
11028         let comma = ref false in
11029         let next () =
11030           if !comma then pr ", ";
11031           comma := true
11032         in
11033         List.iter (
11034           function
11035           | Pathname n | Device n | Dev_or_Path n | String n | OptString n
11036           | FileIn n | FileOut n
11037           | BufferIn n ->
11038               next (); pr "string %s" n
11039           | StringList n | DeviceList n ->
11040               next (); pr "string[] %s" n
11041           | Bool n ->
11042               next (); pr "bool %s" n
11043           | Int n ->
11044               next (); pr "int %s" n
11045           | Int64 n ->
11046               next (); pr "long %s" n
11047         ) (snd style);
11048         pr ")\n"
11049
11050       and generate_call () =
11051         pr "guestfs_%s (_handle" name;
11052         List.iter (fun arg -> pr ", %s" (name_of_argt arg)) (snd style);
11053         pr ");\n";
11054       in
11055
11056       pr "    [DllImport (\"%s\")]\n" library;
11057       generate_extern_prototype ();
11058       pr "\n";
11059       pr "    /// <summary>\n";
11060       pr "    /// %s\n" shortdesc;
11061       pr "    /// </summary>\n";
11062       generate_public_prototype ();
11063       pr "    {\n";
11064       pr "      %s r;\n" (c_return_type ());
11065       pr "      r = ";
11066       generate_call ();
11067       pr "      if (r %s)\n" (c_error_comparison ());
11068       pr "        throw new Error (guestfs_last_error (_handle));\n";
11069       (match fst style with
11070        | RErr -> ()
11071        | RBool _ ->
11072            pr "      return r != 0 ? true : false;\n"
11073        | RHashtable _ ->
11074            pr "      Hashtable rr = new Hashtable ();\n";
11075            pr "      for (int i = 0; i < r.Length; i += 2)\n";
11076            pr "        rr.Add (r[i], r[i+1]);\n";
11077            pr "      return rr;\n"
11078        | RInt _ | RInt64 _ | RConstString _ | RConstOptString _
11079        | RString _ | RBufferOut _ | RStruct _ | RStringList _
11080        | RStructList _ ->
11081            pr "      return r;\n"
11082       );
11083       pr "    }\n";
11084       pr "\n";
11085   ) all_functions_sorted;
11086
11087   pr "  }
11088 }
11089 "
11090
11091 and generate_bindtests () =
11092   generate_header CStyle LGPLv2plus;
11093
11094   pr "\
11095 #include <stdio.h>
11096 #include <stdlib.h>
11097 #include <inttypes.h>
11098 #include <string.h>
11099
11100 #include \"guestfs.h\"
11101 #include \"guestfs-internal.h\"
11102 #include \"guestfs-internal-actions.h\"
11103 #include \"guestfs_protocol.h\"
11104
11105 #define error guestfs_error
11106 #define safe_calloc guestfs_safe_calloc
11107 #define safe_malloc guestfs_safe_malloc
11108
11109 static void
11110 print_strings (char *const *argv)
11111 {
11112   int argc;
11113
11114   printf (\"[\");
11115   for (argc = 0; argv[argc] != NULL; ++argc) {
11116     if (argc > 0) printf (\", \");
11117     printf (\"\\\"%%s\\\"\", argv[argc]);
11118   }
11119   printf (\"]\\n\");
11120 }
11121
11122 /* The test0 function prints its parameters to stdout. */
11123 ";
11124
11125   let test0, tests =
11126     match test_functions with
11127     | [] -> assert false
11128     | test0 :: tests -> test0, tests in
11129
11130   let () =
11131     let (name, style, _, _, _, _, _) = test0 in
11132     generate_prototype ~extern:false ~semicolon:false ~newline:true
11133       ~handle:"g" ~prefix:"guestfs__" name style;
11134     pr "{\n";
11135     List.iter (
11136       function
11137       | Pathname n
11138       | Device n | Dev_or_Path n
11139       | String n
11140       | FileIn n
11141       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
11142       | BufferIn n ->
11143           pr "  {\n";
11144           pr "    size_t i;\n";
11145           pr "    for (i = 0; i < %s_size; ++i)\n" n;
11146           pr "      printf (\"<%%02x>\", %s[i]);\n" n;
11147           pr "    printf (\"\\n\");\n";
11148           pr "  }\n";
11149       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
11150       | StringList n | DeviceList n -> pr "  print_strings (%s);\n" n
11151       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
11152       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
11153       | Int64 n -> pr "  printf (\"%%\" PRIi64 \"\\n\", %s);\n" n
11154     ) (snd style);
11155     pr "  /* Java changes stdout line buffering so we need this: */\n";
11156     pr "  fflush (stdout);\n";
11157     pr "  return 0;\n";
11158     pr "}\n";
11159     pr "\n" in
11160
11161   List.iter (
11162     fun (name, style, _, _, _, _, _) ->
11163       if String.sub name (String.length name - 3) 3 <> "err" then (
11164         pr "/* Test normal return. */\n";
11165         generate_prototype ~extern:false ~semicolon:false ~newline:true
11166           ~handle:"g" ~prefix:"guestfs__" name style;
11167         pr "{\n";
11168         (match fst style with
11169          | RErr ->
11170              pr "  return 0;\n"
11171          | RInt _ ->
11172              pr "  int r;\n";
11173              pr "  sscanf (val, \"%%d\", &r);\n";
11174              pr "  return r;\n"
11175          | RInt64 _ ->
11176              pr "  int64_t r;\n";
11177              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
11178              pr "  return r;\n"
11179          | RBool _ ->
11180              pr "  return STREQ (val, \"true\");\n"
11181          | RConstString _
11182          | RConstOptString _ ->
11183              (* Can't return the input string here.  Return a static
11184               * string so we ensure we get a segfault if the caller
11185               * tries to free it.
11186               *)
11187              pr "  return \"static string\";\n"
11188          | RString _ ->
11189              pr "  return strdup (val);\n"
11190          | RStringList _ ->
11191              pr "  char **strs;\n";
11192              pr "  int n, i;\n";
11193              pr "  sscanf (val, \"%%d\", &n);\n";
11194              pr "  strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
11195              pr "  for (i = 0; i < n; ++i) {\n";
11196              pr "    strs[i] = safe_malloc (g, 16);\n";
11197              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
11198              pr "  }\n";
11199              pr "  strs[n] = NULL;\n";
11200              pr "  return strs;\n"
11201          | RStruct (_, typ) ->
11202              pr "  struct guestfs_%s *r;\n" typ;
11203              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
11204              pr "  return r;\n"
11205          | RStructList (_, typ) ->
11206              pr "  struct guestfs_%s_list *r;\n" typ;
11207              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
11208              pr "  sscanf (val, \"%%d\", &r->len);\n";
11209              pr "  r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
11210              pr "  return r;\n"
11211          | RHashtable _ ->
11212              pr "  char **strs;\n";
11213              pr "  int n, i;\n";
11214              pr "  sscanf (val, \"%%d\", &n);\n";
11215              pr "  strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
11216              pr "  for (i = 0; i < n; ++i) {\n";
11217              pr "    strs[i*2] = safe_malloc (g, 16);\n";
11218              pr "    strs[i*2+1] = safe_malloc (g, 16);\n";
11219              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
11220              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
11221              pr "  }\n";
11222              pr "  strs[n*2] = NULL;\n";
11223              pr "  return strs;\n"
11224          | RBufferOut _ ->
11225              pr "  return strdup (val);\n"
11226         );
11227         pr "}\n";
11228         pr "\n"
11229       ) else (
11230         pr "/* Test error return. */\n";
11231         generate_prototype ~extern:false ~semicolon:false ~newline:true
11232           ~handle:"g" ~prefix:"guestfs__" name style;
11233         pr "{\n";
11234         pr "  error (g, \"error\");\n";
11235         (match fst style with
11236          | RErr | RInt _ | RInt64 _ | RBool _ ->
11237              pr "  return -1;\n"
11238          | RConstString _ | RConstOptString _
11239          | RString _ | RStringList _ | RStruct _
11240          | RStructList _
11241          | RHashtable _
11242          | RBufferOut _ ->
11243              pr "  return NULL;\n"
11244         );
11245         pr "}\n";
11246         pr "\n"
11247       )
11248   ) tests
11249
11250 and generate_ocaml_bindtests () =
11251   generate_header OCamlStyle GPLv2plus;
11252
11253   pr "\
11254 let () =
11255   let g = Guestfs.create () in
11256 ";
11257
11258   let mkargs args =
11259     String.concat " " (
11260       List.map (
11261         function
11262         | CallString s -> "\"" ^ s ^ "\""
11263         | CallOptString None -> "None"
11264         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
11265         | CallStringList xs ->
11266             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
11267         | CallInt i when i >= 0 -> string_of_int i
11268         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
11269         | CallInt64 i when i >= 0L -> Int64.to_string i ^ "L"
11270         | CallInt64 i (* when i < 0L *) -> "(" ^ Int64.to_string i ^ "L)"
11271         | CallBool b -> string_of_bool b
11272         | CallBuffer s -> sprintf "%S" s
11273       ) args
11274     )
11275   in
11276
11277   generate_lang_bindtests (
11278     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
11279   );
11280
11281   pr "print_endline \"EOF\"\n"
11282
11283 and generate_perl_bindtests () =
11284   pr "#!/usr/bin/perl -w\n";
11285   generate_header HashStyle GPLv2plus;
11286
11287   pr "\
11288 use strict;
11289
11290 use Sys::Guestfs;
11291
11292 my $g = Sys::Guestfs->new ();
11293 ";
11294
11295   let mkargs args =
11296     String.concat ", " (
11297       List.map (
11298         function
11299         | CallString s -> "\"" ^ s ^ "\""
11300         | CallOptString None -> "undef"
11301         | CallOptString (Some s) -> sprintf "\"%s\"" s
11302         | CallStringList xs ->
11303             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
11304         | CallInt i -> string_of_int i
11305         | CallInt64 i -> Int64.to_string i
11306         | CallBool b -> if b then "1" else "0"
11307         | CallBuffer s -> "\"" ^ c_quote s ^ "\""
11308       ) args
11309     )
11310   in
11311
11312   generate_lang_bindtests (
11313     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
11314   );
11315
11316   pr "print \"EOF\\n\"\n"
11317
11318 and generate_python_bindtests () =
11319   generate_header HashStyle GPLv2plus;
11320
11321   pr "\
11322 import guestfs
11323
11324 g = guestfs.GuestFS ()
11325 ";
11326
11327   let mkargs args =
11328     String.concat ", " (
11329       List.map (
11330         function
11331         | CallString s -> "\"" ^ s ^ "\""
11332         | CallOptString None -> "None"
11333         | CallOptString (Some s) -> sprintf "\"%s\"" s
11334         | CallStringList xs ->
11335             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
11336         | CallInt i -> string_of_int i
11337         | CallInt64 i -> Int64.to_string i
11338         | CallBool b -> if b then "1" else "0"
11339         | CallBuffer s -> "\"" ^ c_quote s ^ "\""
11340       ) args
11341     )
11342   in
11343
11344   generate_lang_bindtests (
11345     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
11346   );
11347
11348   pr "print \"EOF\"\n"
11349
11350 and generate_ruby_bindtests () =
11351   generate_header HashStyle GPLv2plus;
11352
11353   pr "\
11354 require 'guestfs'
11355
11356 g = Guestfs::create()
11357 ";
11358
11359   let mkargs args =
11360     String.concat ", " (
11361       List.map (
11362         function
11363         | CallString s -> "\"" ^ s ^ "\""
11364         | CallOptString None -> "nil"
11365         | CallOptString (Some s) -> sprintf "\"%s\"" s
11366         | CallStringList xs ->
11367             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
11368         | CallInt i -> string_of_int i
11369         | CallInt64 i -> Int64.to_string i
11370         | CallBool b -> string_of_bool b
11371         | CallBuffer s -> "\"" ^ c_quote s ^ "\""
11372       ) args
11373     )
11374   in
11375
11376   generate_lang_bindtests (
11377     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
11378   );
11379
11380   pr "print \"EOF\\n\"\n"
11381
11382 and generate_java_bindtests () =
11383   generate_header CStyle GPLv2plus;
11384
11385   pr "\
11386 import com.redhat.et.libguestfs.*;
11387
11388 public class Bindtests {
11389     public static void main (String[] argv)
11390     {
11391         try {
11392             GuestFS g = new GuestFS ();
11393 ";
11394
11395   let mkargs args =
11396     String.concat ", " (
11397       List.map (
11398         function
11399         | CallString s -> "\"" ^ s ^ "\""
11400         | CallOptString None -> "null"
11401         | CallOptString (Some s) -> sprintf "\"%s\"" s
11402         | CallStringList xs ->
11403             "new String[]{" ^
11404               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
11405         | CallInt i -> string_of_int i
11406         | CallInt64 i -> Int64.to_string i
11407         | CallBool b -> string_of_bool b
11408         | CallBuffer s ->
11409             "new byte[] { " ^ String.concat "," (
11410               map_chars (fun c -> string_of_int (Char.code c)) s
11411             ) ^ " }"
11412       ) args
11413     )
11414   in
11415
11416   generate_lang_bindtests (
11417     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
11418   );
11419
11420   pr "
11421             System.out.println (\"EOF\");
11422         }
11423         catch (Exception exn) {
11424             System.err.println (exn);
11425             System.exit (1);
11426         }
11427     }
11428 }
11429 "
11430
11431 and generate_haskell_bindtests () =
11432   generate_header HaskellStyle GPLv2plus;
11433
11434   pr "\
11435 module Bindtests where
11436 import qualified Guestfs
11437
11438 main = do
11439   g <- Guestfs.create
11440 ";
11441
11442   let mkargs args =
11443     String.concat " " (
11444       List.map (
11445         function
11446         | CallString s -> "\"" ^ s ^ "\""
11447         | CallOptString None -> "Nothing"
11448         | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
11449         | CallStringList xs ->
11450             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
11451         | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
11452         | CallInt i -> string_of_int i
11453         | CallInt64 i when i < 0L -> "(" ^ Int64.to_string i ^ ")"
11454         | CallInt64 i -> Int64.to_string i
11455         | CallBool true -> "True"
11456         | CallBool false -> "False"
11457         | CallBuffer s -> "\"" ^ c_quote s ^ "\""
11458       ) args
11459     )
11460   in
11461
11462   generate_lang_bindtests (
11463     fun f args -> pr "  Guestfs.%s g %s\n" f (mkargs args)
11464   );
11465
11466   pr "  putStrLn \"EOF\"\n"
11467
11468 (* Language-independent bindings tests - we do it this way to
11469  * ensure there is parity in testing bindings across all languages.
11470  *)
11471 and generate_lang_bindtests call =
11472   call "test0" [CallString "abc"; CallOptString (Some "def");
11473                 CallStringList []; CallBool false;
11474                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456";
11475                 CallBuffer "abc\000abc"];
11476   call "test0" [CallString "abc"; CallOptString None;
11477                 CallStringList []; CallBool false;
11478                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456";
11479                 CallBuffer "abc\000abc"];
11480   call "test0" [CallString ""; CallOptString (Some "def");
11481                 CallStringList []; CallBool false;
11482                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456";
11483                 CallBuffer "abc\000abc"];
11484   call "test0" [CallString ""; CallOptString (Some "");
11485                 CallStringList []; CallBool false;
11486                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456";
11487                 CallBuffer "abc\000abc"];
11488   call "test0" [CallString "abc"; CallOptString (Some "def");
11489                 CallStringList ["1"]; CallBool false;
11490                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456";
11491                 CallBuffer "abc\000abc"];
11492   call "test0" [CallString "abc"; CallOptString (Some "def");
11493                 CallStringList ["1"; "2"]; CallBool false;
11494                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456";
11495                 CallBuffer "abc\000abc"];
11496   call "test0" [CallString "abc"; CallOptString (Some "def");
11497                 CallStringList ["1"]; CallBool true;
11498                 CallInt 0; CallInt64 0L; CallString "123"; CallString "456";
11499                 CallBuffer "abc\000abc"];
11500   call "test0" [CallString "abc"; CallOptString (Some "def");
11501                 CallStringList ["1"]; CallBool false;
11502                 CallInt (-1); CallInt64 (-1L); CallString "123"; CallString "456";
11503                 CallBuffer "abc\000abc"];
11504   call "test0" [CallString "abc"; CallOptString (Some "def");
11505                 CallStringList ["1"]; CallBool false;
11506                 CallInt (-2); CallInt64 (-2L); CallString "123"; CallString "456";
11507                 CallBuffer "abc\000abc"];
11508   call "test0" [CallString "abc"; CallOptString (Some "def");
11509                 CallStringList ["1"]; CallBool false;
11510                 CallInt 1; CallInt64 1L; CallString "123"; CallString "456";
11511                 CallBuffer "abc\000abc"];
11512   call "test0" [CallString "abc"; CallOptString (Some "def");
11513                 CallStringList ["1"]; CallBool false;
11514                 CallInt 2; CallInt64 2L; CallString "123"; CallString "456";
11515                 CallBuffer "abc\000abc"];
11516   call "test0" [CallString "abc"; CallOptString (Some "def");
11517                 CallStringList ["1"]; CallBool false;
11518                 CallInt 4095; CallInt64 4095L; CallString "123"; CallString "456";
11519                 CallBuffer "abc\000abc"];
11520   call "test0" [CallString "abc"; CallOptString (Some "def");
11521                 CallStringList ["1"]; CallBool false;
11522                 CallInt 0; CallInt64 0L; CallString ""; CallString "";
11523                 CallBuffer "abc\000abc"]
11524
11525 (* XXX Add here tests of the return and error functions. *)
11526
11527 (* Code to generator bindings for virt-inspector.  Currently only
11528  * implemented for OCaml code (for virt-p2v 2.0).
11529  *)
11530 let rng_input = "inspector/virt-inspector.rng"
11531
11532 (* Read the input file and parse it into internal structures.  This is
11533  * by no means a complete RELAX NG parser, but is just enough to be
11534  * able to parse the specific input file.
11535  *)
11536 type rng =
11537   | Element of string * rng list        (* <element name=name/> *)
11538   | Attribute of string * rng list        (* <attribute name=name/> *)
11539   | Interleave of rng list                (* <interleave/> *)
11540   | ZeroOrMore of rng                        (* <zeroOrMore/> *)
11541   | OneOrMore of rng                        (* <oneOrMore/> *)
11542   | Optional of rng                        (* <optional/> *)
11543   | Choice of string list                (* <choice><value/>*</choice> *)
11544   | Value of string                        (* <value>str</value> *)
11545   | Text                                (* <text/> *)
11546
11547 let rec string_of_rng = function
11548   | Element (name, xs) ->
11549       "Element (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
11550   | Attribute (name, xs) ->
11551       "Attribute (\"" ^ name ^ "\", (" ^ string_of_rng_list xs ^ "))"
11552   | Interleave xs -> "Interleave (" ^ string_of_rng_list xs ^ ")"
11553   | ZeroOrMore rng -> "ZeroOrMore (" ^ string_of_rng rng ^ ")"
11554   | OneOrMore rng -> "OneOrMore (" ^ string_of_rng rng ^ ")"
11555   | Optional rng -> "Optional (" ^ string_of_rng rng ^ ")"
11556   | Choice values -> "Choice [" ^ String.concat ", " values ^ "]"
11557   | Value value -> "Value \"" ^ value ^ "\""
11558   | Text -> "Text"
11559
11560 and string_of_rng_list xs =
11561   String.concat ", " (List.map string_of_rng xs)
11562
11563 let rec parse_rng ?defines context = function
11564   | [] -> []
11565   | Xml.Element ("element", ["name", name], children) :: rest ->
11566       Element (name, parse_rng ?defines context children)
11567       :: parse_rng ?defines context rest
11568   | Xml.Element ("attribute", ["name", name], children) :: rest ->
11569       Attribute (name, parse_rng ?defines context children)
11570       :: parse_rng ?defines context rest
11571   | Xml.Element ("interleave", [], children) :: rest ->
11572       Interleave (parse_rng ?defines context children)
11573       :: parse_rng ?defines context rest
11574   | Xml.Element ("zeroOrMore", [], [child]) :: rest ->
11575       let rng = parse_rng ?defines context [child] in
11576       (match rng with
11577        | [child] -> ZeroOrMore child :: parse_rng ?defines context rest
11578        | _ ->
11579            failwithf "%s: <zeroOrMore> contains more than one child element"
11580              context
11581       )
11582   | Xml.Element ("oneOrMore", [], [child]) :: rest ->
11583       let rng = parse_rng ?defines context [child] in
11584       (match rng with
11585        | [child] -> OneOrMore child :: parse_rng ?defines context rest
11586        | _ ->
11587            failwithf "%s: <oneOrMore> contains more than one child element"
11588              context
11589       )
11590   | Xml.Element ("optional", [], [child]) :: rest ->
11591       let rng = parse_rng ?defines context [child] in
11592       (match rng with
11593        | [child] -> Optional child :: parse_rng ?defines context rest
11594        | _ ->
11595            failwithf "%s: <optional> contains more than one child element"
11596              context
11597       )
11598   | Xml.Element ("choice", [], children) :: rest ->
11599       let values = List.map (
11600         function Xml.Element ("value", [], [Xml.PCData value]) -> value
11601         | _ ->
11602             failwithf "%s: can't handle anything except <value> in <choice>"
11603               context
11604       ) children in
11605       Choice values
11606       :: parse_rng ?defines context rest
11607   | Xml.Element ("value", [], [Xml.PCData value]) :: rest ->
11608       Value value :: parse_rng ?defines context rest
11609   | Xml.Element ("text", [], []) :: rest ->
11610       Text :: parse_rng ?defines context rest
11611   | Xml.Element ("ref", ["name", name], []) :: rest ->
11612       (* Look up the reference.  Because of limitations in this parser,
11613        * we can't handle arbitrarily nested <ref> yet.  You can only
11614        * use <ref> from inside <start>.
11615        *)
11616       (match defines with
11617        | None ->
11618            failwithf "%s: contains <ref>, but no refs are defined yet" context
11619        | Some map ->
11620            let rng = StringMap.find name map in
11621            rng @ parse_rng ?defines context rest
11622       )
11623   | x :: _ ->
11624       failwithf "%s: can't handle '%s' in schema" context (Xml.to_string x)
11625
11626 let grammar =
11627   let xml = Xml.parse_file rng_input in
11628   match xml with
11629   | Xml.Element ("grammar", _,
11630                  Xml.Element ("start", _, gram) :: defines) ->
11631       (* The <define/> elements are referenced in the <start> section,
11632        * so build a map of those first.
11633        *)
11634       let defines = List.fold_left (
11635         fun map ->
11636           function Xml.Element ("define", ["name", name], defn) ->
11637             StringMap.add name defn map
11638           | _ ->
11639               failwithf "%s: expected <define name=name/>" rng_input
11640       ) StringMap.empty defines in
11641       let defines = StringMap.mapi parse_rng defines in
11642
11643       (* Parse the <start> clause, passing the defines. *)
11644       parse_rng ~defines "<start>" gram
11645   | _ ->
11646       failwithf "%s: input is not <grammar><start/><define>*</grammar>"
11647         rng_input
11648
11649 let name_of_field = function
11650   | Element (name, _) | Attribute (name, _)
11651   | ZeroOrMore (Element (name, _))
11652   | OneOrMore (Element (name, _))
11653   | Optional (Element (name, _)) -> name
11654   | Optional (Attribute (name, _)) -> name
11655   | Text -> (* an unnamed field in an element *)
11656       "data"
11657   | rng ->
11658       failwithf "name_of_field failed at: %s" (string_of_rng rng)
11659
11660 (* At the moment this function only generates OCaml types.  However we
11661  * should parameterize it later so it can generate types/structs in a
11662  * variety of languages.
11663  *)
11664 let generate_types xs =
11665   (* A simple type is one that can be printed out directly, eg.
11666    * "string option".  A complex type is one which has a name and has
11667    * to be defined via another toplevel definition, eg. a struct.
11668    *
11669    * generate_type generates code for either simple or complex types.
11670    * In the simple case, it returns the string ("string option").  In
11671    * the complex case, it returns the name ("mountpoint").  In the
11672    * complex case it has to print out the definition before returning,
11673    * so it should only be called when we are at the beginning of a
11674    * new line (BOL context).
11675    *)
11676   let rec generate_type = function
11677     | Text ->                                (* string *)
11678         "string", true
11679     | Choice values ->                        (* [`val1|`val2|...] *)
11680         "[" ^ String.concat "|" (List.map ((^)"`") values) ^ "]", true
11681     | ZeroOrMore rng ->                        (* <rng> list *)
11682         let t, is_simple = generate_type rng in
11683         t ^ " list (* 0 or more *)", is_simple
11684     | OneOrMore rng ->                        (* <rng> list *)
11685         let t, is_simple = generate_type rng in
11686         t ^ " list (* 1 or more *)", is_simple
11687                                         (* virt-inspector hack: bool *)
11688     | Optional (Attribute (name, [Value "1"])) ->
11689         "bool", true
11690     | Optional rng ->                        (* <rng> list *)
11691         let t, is_simple = generate_type rng in
11692         t ^ " option", is_simple
11693                                         (* type name = { fields ... } *)
11694     | Element (name, fields) when is_attrs_interleave fields ->
11695         generate_type_struct name (get_attrs_interleave fields)
11696     | Element (name, [field])                (* type name = field *)
11697     | Attribute (name, [field]) ->
11698         let t, is_simple = generate_type field in
11699         if is_simple then (t, true)
11700         else (
11701           pr "type %s = %s\n" name t;
11702           name, false
11703         )
11704     | Element (name, fields) ->              (* type name = { fields ... } *)
11705         generate_type_struct name fields
11706     | rng ->
11707         failwithf "generate_type failed at: %s" (string_of_rng rng)
11708
11709   and is_attrs_interleave = function
11710     | [Interleave _] -> true
11711     | Attribute _ :: fields -> is_attrs_interleave fields
11712     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
11713     | _ -> false
11714
11715   and get_attrs_interleave = function
11716     | [Interleave fields] -> fields
11717     | ((Attribute _) as field) :: fields
11718     | ((Optional (Attribute _)) as field) :: fields ->
11719         field :: get_attrs_interleave fields
11720     | _ -> assert false
11721
11722   and generate_types xs =
11723     List.iter (fun x -> ignore (generate_type x)) xs
11724
11725   and generate_type_struct name fields =
11726     (* Calculate the types of the fields first.  We have to do this
11727      * before printing anything so we are still in BOL context.
11728      *)
11729     let types = List.map fst (List.map generate_type fields) in
11730
11731     (* Special case of a struct containing just a string and another
11732      * field.  Turn it into an assoc list.
11733      *)
11734     match types with
11735     | ["string"; other] ->
11736         let fname1, fname2 =
11737           match fields with
11738           | [f1; f2] -> name_of_field f1, name_of_field f2
11739           | _ -> assert false in
11740         pr "type %s = string * %s (* %s -> %s *)\n" name other fname1 fname2;
11741         name, false
11742
11743     | types ->
11744         pr "type %s = {\n" name;
11745         List.iter (
11746           fun (field, ftype) ->
11747             let fname = name_of_field field in
11748             pr "  %s_%s : %s;\n" name fname ftype
11749         ) (List.combine fields types);
11750         pr "}\n";
11751         (* Return the name of this type, and
11752          * false because it's not a simple type.
11753          *)
11754         name, false
11755   in
11756
11757   generate_types xs
11758
11759 let generate_parsers xs =
11760   (* As for generate_type above, generate_parser makes a parser for
11761    * some type, and returns the name of the parser it has generated.
11762    * Because it (may) need to print something, it should always be
11763    * called in BOL context.
11764    *)
11765   let rec generate_parser = function
11766     | Text ->                                (* string *)
11767         "string_child_or_empty"
11768     | Choice values ->                        (* [`val1|`val2|...] *)
11769         sprintf "(fun x -> match Xml.pcdata (first_child x) with %s | str -> failwith (\"unexpected field value: \" ^ str))"
11770           (String.concat "|"
11771              (List.map (fun v -> sprintf "%S -> `%s" v v) values))
11772     | ZeroOrMore rng ->                        (* <rng> list *)
11773         let pa = generate_parser rng in
11774         sprintf "(fun x -> List.map %s (Xml.children x))" pa
11775     | OneOrMore rng ->                        (* <rng> list *)
11776         let pa = generate_parser rng in
11777         sprintf "(fun x -> List.map %s (Xml.children x))" pa
11778                                         (* virt-inspector hack: bool *)
11779     | Optional (Attribute (name, [Value "1"])) ->
11780         sprintf "(fun x -> try ignore (Xml.attrib x %S); true with Xml.No_attribute _ -> false)" name
11781     | Optional rng ->                        (* <rng> list *)
11782         let pa = generate_parser rng in
11783         sprintf "(function None -> None | Some x -> Some (%s x))" pa
11784                                         (* type name = { fields ... } *)
11785     | Element (name, fields) when is_attrs_interleave fields ->
11786         generate_parser_struct name (get_attrs_interleave fields)
11787     | Element (name, [field]) ->        (* type name = field *)
11788         let pa = generate_parser field in
11789         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
11790         pr "let %s =\n" parser_name;
11791         pr "  %s\n" pa;
11792         pr "let parse_%s = %s\n" name parser_name;
11793         parser_name
11794     | Attribute (name, [field]) ->
11795         let pa = generate_parser field in
11796         let parser_name = sprintf "parse_%s_%d" name (unique ()) in
11797         pr "let %s =\n" parser_name;
11798         pr "  %s\n" pa;
11799         pr "let parse_%s = %s\n" name parser_name;
11800         parser_name
11801     | Element (name, fields) ->              (* type name = { fields ... } *)
11802         generate_parser_struct name ([], fields)
11803     | rng ->
11804         failwithf "generate_parser failed at: %s" (string_of_rng rng)
11805
11806   and is_attrs_interleave = function
11807     | [Interleave _] -> true
11808     | Attribute _ :: fields -> is_attrs_interleave fields
11809     | Optional (Attribute _) :: fields -> is_attrs_interleave fields
11810     | _ -> false
11811
11812   and get_attrs_interleave = function
11813     | [Interleave fields] -> [], fields
11814     | ((Attribute _) as field) :: fields
11815     | ((Optional (Attribute _)) as field) :: fields ->
11816         let attrs, interleaves = get_attrs_interleave fields in
11817         (field :: attrs), interleaves
11818     | _ -> assert false
11819
11820   and generate_parsers xs =
11821     List.iter (fun x -> ignore (generate_parser x)) xs
11822
11823   and generate_parser_struct name (attrs, interleaves) =
11824     (* Generate parsers for the fields first.  We have to do this
11825      * before printing anything so we are still in BOL context.
11826      *)
11827     let fields = attrs @ interleaves in
11828     let pas = List.map generate_parser fields in
11829
11830     (* Generate an intermediate tuple from all the fields first.
11831      * If the type is just a string + another field, then we will
11832      * return this directly, otherwise it is turned into a record.
11833      *
11834      * RELAX NG note: This code treats <interleave> and plain lists of
11835      * fields the same.  In other words, it doesn't bother enforcing
11836      * any ordering of fields in the XML.
11837      *)
11838     pr "let parse_%s x =\n" name;
11839     pr "  let t = (\n    ";
11840     let comma = ref false in
11841     List.iter (
11842       fun x ->
11843         if !comma then pr ",\n    ";
11844         comma := true;
11845         match x with
11846         | Optional (Attribute (fname, [field])), pa ->
11847             pr "%s x" pa
11848         | Optional (Element (fname, [field])), pa ->
11849             pr "%s (optional_child %S x)" pa fname
11850         | Attribute (fname, [Text]), _ ->
11851             pr "attribute %S x" fname
11852         | (ZeroOrMore _ | OneOrMore _), pa ->
11853             pr "%s x" pa
11854         | Text, pa ->
11855             pr "%s x" pa
11856         | (field, pa) ->
11857             let fname = name_of_field field in
11858             pr "%s (child %S x)" pa fname
11859     ) (List.combine fields pas);
11860     pr "\n  ) in\n";
11861
11862     (match fields with
11863      | [Element (_, [Text]) | Attribute (_, [Text]); _] ->
11864          pr "  t\n"
11865
11866      | _ ->
11867          pr "  (Obj.magic t : %s)\n" name
11868 (*
11869          List.iter (
11870            function
11871            | (Optional (Attribute (fname, [field])), pa) ->
11872                pr "  %s_%s =\n" name fname;
11873                pr "    %s x;\n" pa
11874            | (Optional (Element (fname, [field])), pa) ->
11875                pr "  %s_%s =\n" name fname;
11876                pr "    (let x = optional_child %S x in\n" fname;
11877                pr "     %s x);\n" pa
11878            | (field, pa) ->
11879                let fname = name_of_field field in
11880                pr "  %s_%s =\n" name fname;
11881                pr "    (let x = child %S x in\n" fname;
11882                pr "     %s x);\n" pa
11883          ) (List.combine fields pas);
11884          pr "}\n"
11885 *)
11886     );
11887     sprintf "parse_%s" name
11888   in
11889
11890   generate_parsers xs
11891
11892 (* Generate ocaml/guestfs_inspector.mli. *)
11893 let generate_ocaml_inspector_mli () =
11894   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11895
11896   pr "\
11897 (** This is an OCaml language binding to the external [virt-inspector]
11898     program.
11899
11900     For more information, please read the man page [virt-inspector(1)].
11901 *)
11902
11903 ";
11904
11905   generate_types grammar;
11906   pr "(** The nested information returned from the {!inspect} function. *)\n";
11907   pr "\n";
11908
11909   pr "\
11910 val inspect : ?connect:string -> ?xml:string -> string list -> operatingsystems
11911 (** To inspect a libvirt domain called [name], pass a singleton
11912     list: [inspect [name]].  When using libvirt only, you may
11913     optionally pass a libvirt URI using [inspect ~connect:uri ...].
11914
11915     To inspect a disk image or images, pass a list of the filenames
11916     of the disk images: [inspect filenames]
11917
11918     This function inspects the given guest or disk images and
11919     returns a list of operating system(s) found and a large amount
11920     of information about them.  In the vast majority of cases,
11921     a virtual machine only contains a single operating system.
11922
11923     If the optional [~xml] parameter is given, then this function
11924     skips running the external virt-inspector program and just
11925     parses the given XML directly (which is expected to be XML
11926     produced from a previous run of virt-inspector).  The list of
11927     names and connect URI are ignored in this case.
11928
11929     This function can throw a wide variety of exceptions, for example
11930     if the external virt-inspector program cannot be found, or if
11931     it doesn't generate valid XML.
11932 *)
11933 "
11934
11935 (* Generate ocaml/guestfs_inspector.ml. *)
11936 let generate_ocaml_inspector_ml () =
11937   generate_header ~extra_inputs:[rng_input] OCamlStyle LGPLv2plus;
11938
11939   pr "open Unix\n";
11940   pr "\n";
11941
11942   generate_types grammar;
11943   pr "\n";
11944
11945   pr "\
11946 (* Misc functions which are used by the parser code below. *)
11947 let first_child = function
11948   | Xml.Element (_, _, c::_) -> c
11949   | Xml.Element (name, _, []) ->
11950       failwith (\"expected <\" ^ name ^ \"/> to have a child node\")
11951   | Xml.PCData str ->
11952       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11953
11954 let string_child_or_empty = function
11955   | Xml.Element (_, _, [Xml.PCData s]) -> s
11956   | Xml.Element (_, _, []) -> \"\"
11957   | Xml.Element (x, _, _) ->
11958       failwith (\"expected XML tag with a single PCDATA child, but got \" ^
11959                 x ^ \" instead\")
11960   | Xml.PCData str ->
11961       failwith (\"expected XML tag, but read PCDATA '\" ^ str ^ \"' instead\")
11962
11963 let optional_child name xml =
11964   let children = Xml.children xml in
11965   try
11966     Some (List.find (function
11967                      | Xml.Element (n, _, _) when n = name -> true
11968                      | _ -> false) children)
11969   with
11970     Not_found -> None
11971
11972 let child name xml =
11973   match optional_child name xml with
11974   | Some c -> c
11975   | None ->
11976       failwith (\"mandatory field <\" ^ name ^ \"/> missing in XML output\")
11977
11978 let attribute name xml =
11979   try Xml.attrib xml name
11980   with Xml.No_attribute _ ->
11981     failwith (\"mandatory attribute \" ^ name ^ \" missing in XML output\")
11982
11983 ";
11984
11985   generate_parsers grammar;
11986   pr "\n";
11987
11988   pr "\
11989 (* Run external virt-inspector, then use parser to parse the XML. *)
11990 let inspect ?connect ?xml names =
11991   let xml =
11992     match xml with
11993     | None ->
11994         if names = [] then invalid_arg \"inspect: no names given\";
11995         let cmd = [ \"virt-inspector\"; \"--xml\" ] @
11996           (match connect with None -> [] | Some uri -> [ \"--connect\"; uri ]) @
11997           names in
11998         let cmd = List.map Filename.quote cmd in
11999         let cmd = String.concat \" \" cmd in
12000         let chan = open_process_in cmd in
12001         let xml = Xml.parse_in chan in
12002         (match close_process_in chan with
12003          | WEXITED 0 -> ()
12004          | WEXITED _ -> failwith \"external virt-inspector command failed\"
12005          | WSIGNALED i | WSTOPPED i ->
12006              failwith (\"external virt-inspector command died or stopped on sig \" ^
12007                        string_of_int i)
12008         );
12009         xml
12010     | Some doc ->
12011         Xml.parse_string doc in
12012   parse_operatingsystems xml
12013 "
12014
12015 and generate_max_proc_nr () =
12016   pr "%d\n" max_proc_nr
12017
12018 let output_to filename k =
12019   let filename_new = filename ^ ".new" in
12020   chan := open_out filename_new;
12021   k ();
12022   close_out !chan;
12023   chan := Pervasives.stdout;
12024
12025   (* Is the new file different from the current file? *)
12026   if Sys.file_exists filename && files_equal filename filename_new then
12027     unlink filename_new                 (* same, so skip it *)
12028   else (
12029     (* different, overwrite old one *)
12030     (try chmod filename 0o644 with Unix_error _ -> ());
12031     rename filename_new filename;
12032     chmod filename 0o444;
12033     printf "written %s\n%!" filename;
12034   )
12035
12036 let perror msg = function
12037   | Unix_error (err, _, _) ->
12038       eprintf "%s: %s\n" msg (error_message err)
12039   | exn ->
12040       eprintf "%s: %s\n" msg (Printexc.to_string exn)
12041
12042 (* Main program. *)
12043 let () =
12044   let lock_fd =
12045     try openfile "HACKING" [O_RDWR] 0
12046     with
12047     | Unix_error (ENOENT, _, _) ->
12048         eprintf "\
12049 You are probably running this from the wrong directory.
12050 Run it from the top source directory using the command
12051   src/generator.ml
12052 ";
12053         exit 1
12054     | exn ->
12055         perror "open: HACKING" exn;
12056         exit 1 in
12057
12058   (* Acquire a lock so parallel builds won't try to run the generator
12059    * twice at the same time.  Subsequent builds will wait for the first
12060    * one to finish.  Note the lock is released implicitly when the
12061    * program exits.
12062    *)
12063   (try lockf lock_fd F_LOCK 1
12064    with exn ->
12065      perror "lock: HACKING" exn;
12066      exit 1);
12067
12068   check_functions ();
12069
12070   output_to "src/guestfs_protocol.x" generate_xdr;
12071   output_to "src/guestfs-structs.h" generate_structs_h;
12072   output_to "src/guestfs-actions.h" generate_actions_h;
12073   output_to "src/guestfs-internal-actions.h" generate_internal_actions_h;
12074   output_to "src/guestfs-actions.c" generate_client_actions;
12075   output_to "src/guestfs-bindtests.c" generate_bindtests;
12076   output_to "src/guestfs-structs.pod" generate_structs_pod;
12077   output_to "src/guestfs-actions.pod" generate_actions_pod;
12078   output_to "src/guestfs-availability.pod" generate_availability_pod;
12079   output_to "src/MAX_PROC_NR" generate_max_proc_nr;
12080   output_to "src/libguestfs.syms" generate_linker_script;
12081   output_to "daemon/actions.h" generate_daemon_actions_h;
12082   output_to "daemon/stubs.c" generate_daemon_actions;
12083   output_to "daemon/names.c" generate_daemon_names;
12084   output_to "daemon/optgroups.c" generate_daemon_optgroups_c;
12085   output_to "daemon/optgroups.h" generate_daemon_optgroups_h;
12086   output_to "capitests/tests.c" generate_tests;
12087   output_to "fish/cmds.c" generate_fish_cmds;
12088   output_to "fish/completion.c" generate_fish_completion;
12089   output_to "fish/guestfish-actions.pod" generate_fish_actions_pod;
12090   output_to "ocaml/guestfs.mli" generate_ocaml_mli;
12091   output_to "ocaml/guestfs.ml" generate_ocaml_ml;
12092   output_to "ocaml/guestfs_c_actions.c" generate_ocaml_c;
12093   output_to "ocaml/bindtests.ml" generate_ocaml_bindtests;
12094   output_to "ocaml/guestfs_inspector.mli" generate_ocaml_inspector_mli;
12095   output_to "ocaml/guestfs_inspector.ml" generate_ocaml_inspector_ml;
12096   output_to "perl/Guestfs.xs" generate_perl_xs;
12097   output_to "perl/lib/Sys/Guestfs.pm" generate_perl_pm;
12098   output_to "perl/bindtests.pl" generate_perl_bindtests;
12099   output_to "python/guestfs-py.c" generate_python_c;
12100   output_to "python/guestfs.py" generate_python_py;
12101   output_to "python/bindtests.py" generate_python_bindtests;
12102   output_to "ruby/ext/guestfs/_guestfs.c" generate_ruby_c;
12103   output_to "ruby/bindtests.rb" generate_ruby_bindtests;
12104   output_to "java/com/redhat/et/libguestfs/GuestFS.java" generate_java_java;
12105
12106   List.iter (
12107     fun (typ, jtyp) ->
12108       let cols = cols_of_struct typ in
12109       let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
12110       output_to filename (generate_java_struct jtyp cols);
12111   ) java_structs;
12112
12113   output_to "java/Makefile.inc" generate_java_makefile_inc;
12114   output_to "java/com_redhat_et_libguestfs_GuestFS.c" generate_java_c;
12115   output_to "java/Bindtests.java" generate_java_bindtests;
12116   output_to "haskell/Guestfs.hs" generate_haskell_hs;
12117   output_to "haskell/Bindtests.hs" generate_haskell_bindtests;
12118   output_to "csharp/Libguestfs.cs" generate_csharp;
12119
12120   (* Always generate this file last, and unconditionally.  It's used
12121    * by the Makefile to know when we must re-run the generator.
12122    *)
12123   let chan = open_out "src/stamp-generator" in
12124   fprintf chan "1\n";
12125   close_out chan;
12126
12127   printf "generated %d lines of code\n" !lines