Tidy up appliance rescue code.
[libguestfs.git] / src / generator.ml
1 #!/usr/bin/env ocaml
2 (* libguestfs
3  * Copyright (C) 2009 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 below), and
25  * daemon/<somefile>.c to write the implementation.
26  *
27  * After editing this file, run it (./src/generator.ml) to regenerate all the
28  * output files.  Note that if you are using a separate build directory you
29  * must run generator.ml from the _source_ directory.
30  *
31  * IMPORTANT: This script should NOT print any warnings.  If it prints
32  * warnings, you should treat them as errors.
33  *)
34
35 #load "unix.cma";;
36 #load "str.cma";;
37
38 open Printf
39
40 type style = ret * args
41 and ret =
42     (* "RErr" as a return value means an int used as a simple error
43      * indication, ie. 0 or -1.
44      *)
45   | RErr
46
47     (* "RInt" as a return value means an int which is -1 for error
48      * or any value >= 0 on success.  Only use this for smallish
49      * positive ints (0 <= i < 2^30).
50      *)
51   | RInt of string
52
53     (* "RInt64" is the same as RInt, but is guaranteed to be able
54      * to return a full 64 bit value, _except_ that -1 means error
55      * (so -1 cannot be a valid, non-error return value).
56      *)
57   | RInt64 of string
58
59     (* "RBool" is a bool return value which can be true/false or
60      * -1 for error.
61      *)
62   | RBool of string
63
64     (* "RConstString" is a string that refers to a constant value.
65      * The return value must NOT be NULL (since NULL indicates
66      * an error).
67      *
68      * Try to avoid using this.  In particular you cannot use this
69      * for values returned from the daemon, because there is no
70      * thread-safe way to return them in the C API.
71      *)
72   | RConstString of string
73
74     (* "RConstOptString" is an even more broken version of
75      * "RConstString".  The returned string may be NULL and there
76      * is no way to return an error indication.  Avoid using this!
77      *)
78   | RConstOptString of string
79
80     (* "RString" is a returned string.  It must NOT be NULL, since
81      * a NULL return indicates an error.  The caller frees this.
82      *)
83   | RString of string
84
85     (* "RStringList" is a list of strings.  No string in the list
86      * can be NULL.  The caller frees the strings and the array.
87      *)
88   | RStringList of string
89
90     (* "RStruct" is a function which returns a single named structure
91      * or an error indication (in C, a struct, and in other languages
92      * with varying representations, but usually very efficient).  See
93      * after the function list below for the structures.
94      *)
95   | RStruct of string * string          (* name of retval, name of struct *)
96
97     (* "RStructList" is a function which returns either a list/array
98      * of structures (could be zero-length), or an error indication.
99      *)
100   | RStructList of string * string      (* name of retval, name of struct *)
101
102     (* Key-value pairs of untyped strings.  Turns into a hashtable or
103      * dictionary in languages which support it.  DON'T use this as a
104      * general "bucket" for results.  Prefer a stronger typed return
105      * value if one is available, or write a custom struct.  Don't use
106      * this if the list could potentially be very long, since it is
107      * inefficient.  Keys should be unique.  NULLs are not permitted.
108      *)
109   | RHashtable of string
110
111     (* "RBufferOut" is handled almost exactly like RString, but
112      * it allows the string to contain arbitrary 8 bit data including
113      * ASCII NUL.  In the C API this causes an implicit extra parameter
114      * to be added of type <size_t *size_r>.  The extra parameter
115      * returns the actual size of the return buffer in bytes.
116      *
117      * Other programming languages support strings with arbitrary 8 bit
118      * data.
119      *
120      * At the RPC layer we have to use the opaque<> type instead of
121      * string<>.  Returned data is still limited to the max message
122      * size (ie. ~ 2 MB).
123      *)
124   | RBufferOut of string
125
126 and args = argt list    (* Function parameters, guestfs handle is implicit. *)
127
128     (* Note in future we should allow a "variable args" parameter as
129      * the final parameter, to allow commands like
130      *   chmod mode file [file(s)...]
131      * This is not implemented yet, but many commands (such as chmod)
132      * are currently defined with the argument order keeping this future
133      * possibility in mind.
134      *)
135 and argt =
136   | String of string    (* const char *name, cannot be NULL *)
137   | Device of string    (* /dev device name, cannot be NULL *)
138   | Pathname of string  (* file name, cannot be NULL *)
139   | Dev_or_Path of string (* /dev device name or Pathname, cannot be NULL *)
140   | OptString of string (* const char *name, may be NULL *)
141   | StringList of string(* list of strings (each string cannot be NULL) *)
142   | DeviceList of string(* list of Device names (each cannot be NULL) *)
143   | Bool of string      (* boolean *)
144   | Int of string       (* int (smallish ints, signed, <= 31 bits) *)
145     (* These are treated as filenames (simple string parameters) in
146      * the C API and bindings.  But in the RPC protocol, we transfer
147      * the actual file content up to or down from the daemon.
148      * FileIn: local machine -> daemon (in request)
149      * FileOut: daemon -> local machine (in reply)
150      * In guestfish (only), the special name "-" means read from
151      * stdin or write to stdout.
152      *)
153   | FileIn of string
154   | FileOut of string
155 (* Not implemented:
156     (* Opaque buffer which can contain arbitrary 8 bit data.
157      * In the C API, this is expressed as <char *, int> pair.
158      * Most other languages have a string type which can contain
159      * ASCII NUL.  We use whatever type is appropriate for each
160      * language.
161      * Buffers are limited by the total message size.  To transfer
162      * large blocks of data, use FileIn/FileOut parameters instead.
163      * To return an arbitrary buffer, use RBufferOut.
164      *)
165   | BufferIn of string
166 *)
167
168 type flags =
169   | ProtocolLimitWarning  (* display warning about protocol size limits *)
170   | DangerWillRobinson    (* flags particularly dangerous commands *)
171   | FishAlias of string   (* provide an alias for this cmd in guestfish *)
172   | FishAction of string  (* call this function in guestfish *)
173   | NotInFish             (* do not export via guestfish *)
174   | NotInDocs             (* do not add this function to documentation *)
175   | DeprecatedBy of string (* function is deprecated, use .. instead *)
176
177 (* You can supply zero or as many tests as you want per API call.
178  *
179  * Note that the test environment has 3 block devices, of size 500MB,
180  * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
181  * a fourth ISO block device with some known files on it (/dev/sdd).
182  *
183  * Note for partitioning purposes, the 500MB device has 1015 cylinders.
184  * Number of cylinders was 63 for IDE emulated disks with precisely
185  * the same size.  How exactly this is calculated is a mystery.
186  *
187  * The ISO block device (/dev/sdd) comes from images/test.iso.
188  *
189  * To be able to run the tests in a reasonable amount of time,
190  * the virtual machine and block devices are reused between tests.
191  * So don't try testing kill_subprocess :-x
192  *
193  * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
194  *
195  * Don't assume anything about the previous contents of the block
196  * devices.  Use 'Init*' to create some initial scenarios.
197  *
198  * You can add a prerequisite clause to any individual test.  This
199  * is a run-time check, which, if it fails, causes the test to be
200  * skipped.  Useful if testing a command which might not work on
201  * all variations of libguestfs builds.  A test that has prerequisite
202  * of 'Always' is run unconditionally.
203  *
204  * In addition, packagers can skip individual tests by setting the
205  * environment variables:     eg:
206  *   SKIP_TEST_<CMD>_<NUM>=1  SKIP_TEST_COMMAND_3=1  (skips test #3 of command)
207  *   SKIP_TEST_<CMD>=1        SKIP_TEST_ZEROFREE=1   (skips all zerofree tests)
208  *)
209 type tests = (test_init * test_prereq * test) list
210 and test =
211     (* Run the command sequence and just expect nothing to fail. *)
212   | TestRun of seq
213
214     (* Run the command sequence and expect the output of the final
215      * command to be the string.
216      *)
217   | TestOutput of seq * string
218
219     (* Run the command sequence and expect the output of the final
220      * command to be the list of strings.
221      *)
222   | TestOutputList of seq * string list
223
224     (* Run the command sequence and expect the output of the final
225      * command to be the list of block devices (could be either
226      * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
227      * character of each string).
228      *)
229   | TestOutputListOfDevices of seq * string list
230
231     (* Run the command sequence and expect the output of the final
232      * command to be the integer.
233      *)
234   | TestOutputInt of seq * int
235
236     (* Run the command sequence and expect the output of the final
237      * command to be <op> <int>, eg. ">=", "1".
238      *)
239   | TestOutputIntOp of seq * string * int
240
241     (* Run the command sequence and expect the output of the final
242      * command to be a true value (!= 0 or != NULL).
243      *)
244   | TestOutputTrue of seq
245
246     (* Run the command sequence and expect the output of the final
247      * command to be a false value (== 0 or == NULL, but not an error).
248      *)
249   | TestOutputFalse of seq
250
251     (* Run the command sequence and expect the output of the final
252      * command to be a list of the given length (but don't care about
253      * content).
254      *)
255   | TestOutputLength of seq * int
256
257     (* Run the command sequence and expect the output of the final
258      * command to be a buffer (RBufferOut), ie. string + size.
259      *)
260   | TestOutputBuffer of seq * string
261
262     (* Run the command sequence and expect the output of the final
263      * command to be a structure.
264      *)
265   | TestOutputStruct of seq * test_field_compare list
266
267     (* Run the command sequence and expect the final command (only)
268      * to fail.
269      *)
270   | TestLastFail of seq
271
272 and test_field_compare =
273   | CompareWithInt of string * int
274   | CompareWithIntOp of string * string * int
275   | CompareWithString of string * string
276   | CompareFieldsIntEq of string * string
277   | CompareFieldsStrEq of string * string
278
279 (* Test prerequisites. *)
280 and test_prereq =
281     (* Test always runs. *)
282   | Always
283
284     (* Test is currently disabled - eg. it fails, or it tests some
285      * unimplemented feature.
286      *)
287   | Disabled
288
289     (* 'string' is some C code (a function body) that should return
290      * true or false.  The test will run if the code returns true.
291      *)
292   | If of string
293
294     (* As for 'If' but the test runs _unless_ the code returns true. *)
295   | Unless of string
296
297 (* Some initial scenarios for testing. *)
298 and test_init =
299     (* Do nothing, block devices could contain random stuff including
300      * LVM PVs, and some filesystems might be mounted.  This is usually
301      * a bad idea.
302      *)
303   | InitNone
304
305     (* Block devices are empty and no filesystems are mounted. *)
306   | InitEmpty
307
308     (* /dev/sda contains a single partition /dev/sda1, with random
309      * content.  /dev/sdb and /dev/sdc may have random content.
310      * No LVM.
311      *)
312   | InitPartition
313
314     (* /dev/sda contains a single partition /dev/sda1, which is formatted
315      * as ext2, empty [except for lost+found] and mounted on /.
316      * /dev/sdb and /dev/sdc may have random content.
317      * No LVM.
318      *)
319   | InitBasicFS
320
321     (* /dev/sda:
322      *   /dev/sda1 (is a PV):
323      *     /dev/VG/LV (size 8MB):
324      *       formatted as ext2, empty [except for lost+found], mounted on /
325      * /dev/sdb and /dev/sdc may have random content.
326      *)
327   | InitBasicFSonLVM
328
329     (* /dev/sdd (the ISO, see images/ directory in source)
330      * is mounted on /
331      *)
332   | InitISOFS
333
334 (* Sequence of commands for testing. *)
335 and seq = cmd list
336 and cmd = string list
337
338 (* Note about long descriptions: When referring to another
339  * action, use the format C<guestfs_other> (ie. the full name of
340  * the C function).  This will be replaced as appropriate in other
341  * language bindings.
342  *
343  * Apart from that, long descriptions are just perldoc paragraphs.
344  *)
345
346 (* Generate a random UUID (used in tests). *)
347 let uuidgen () =
348   let chan = Unix.open_process_in "uuidgen" in
349   let uuid = input_line chan in
350   (match Unix.close_process_in chan with
351    | Unix.WEXITED 0 -> ()
352    | Unix.WEXITED _ ->
353        failwith "uuidgen: process exited with non-zero status"
354    | Unix.WSIGNALED _ | Unix.WSTOPPED _ ->
355        failwith "uuidgen: process signalled or stopped by signal"
356   );
357   uuid
358
359 (* These test functions are used in the language binding tests. *)
360
361 let test_all_args = [
362   String "str";
363   OptString "optstr";
364   StringList "strlist";
365   Bool "b";
366   Int "integer";
367   FileIn "filein";
368   FileOut "fileout";
369 ]
370
371 let test_all_rets = [
372   (* except for RErr, which is tested thoroughly elsewhere *)
373   "test0rint",         RInt "valout";
374   "test0rint64",       RInt64 "valout";
375   "test0rbool",        RBool "valout";
376   "test0rconststring", RConstString "valout";
377   "test0rconstoptstring", RConstOptString "valout";
378   "test0rstring",      RString "valout";
379   "test0rstringlist",  RStringList "valout";
380   "test0rstruct",      RStruct ("valout", "lvm_pv");
381   "test0rstructlist",  RStructList ("valout", "lvm_pv");
382   "test0rhashtable",   RHashtable "valout";
383 ]
384
385 let test_functions = [
386   ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
387    [],
388    "internal test function - do not use",
389    "\
390 This is an internal test function which is used to test whether
391 the automatically generated bindings can handle every possible
392 parameter type correctly.
393
394 It echos the contents of each parameter to stdout.
395
396 You probably don't want to call this function.");
397 ] @ List.flatten (
398   List.map (
399     fun (name, ret) ->
400       [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
401         [],
402         "internal test function - do not use",
403         "\
404 This is an internal test function which is used to test whether
405 the automatically generated bindings can handle every possible
406 return type correctly.
407
408 It converts string C<val> to the return type.
409
410 You probably don't want to call this function.");
411        (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
412         [],
413         "internal test function - do not use",
414         "\
415 This is an internal test function which is used to test whether
416 the automatically generated bindings can handle every possible
417 return type correctly.
418
419 This function always returns an error.
420
421 You probably don't want to call this function.")]
422   ) test_all_rets
423 )
424
425 (* non_daemon_functions are any functions which don't get processed
426  * in the daemon, eg. functions for setting and getting local
427  * configuration values.
428  *)
429
430 let non_daemon_functions = test_functions @ [
431   ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
432    [],
433    "launch the qemu subprocess",
434    "\
435 Internally libguestfs is implemented by running a virtual machine
436 using L<qemu(1)>.
437
438 You should call this after configuring the handle
439 (eg. adding drives) but before performing any actions.");
440
441   ("wait_ready", (RErr, []), -1, [NotInFish],
442    [],
443    "wait until the qemu subprocess launches (no op)",
444    "\
445 This function is a no op.
446
447 In versions of the API E<lt> 1.0.71 you had to call this function
448 just after calling C<guestfs_launch> to wait for the launch
449 to complete.  However this is no longer necessary because
450 C<guestfs_launch> now does the waiting.
451
452 If you see any calls to this function in code then you can just
453 remove them, unless you want to retain compatibility with older
454 versions of the API.");
455
456   ("kill_subprocess", (RErr, []), -1, [],
457    [],
458    "kill the qemu subprocess",
459    "\
460 This kills the qemu subprocess.  You should never need to call this.");
461
462   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
463    [],
464    "add an image to examine or modify",
465    "\
466 This function adds a virtual machine disk image C<filename> to the
467 guest.  The first time you call this function, the disk appears as IDE
468 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
469 so on.
470
471 You don't necessarily need to be root when using libguestfs.  However
472 you obviously do need sufficient permissions to access the filename
473 for whatever operations you want to perform (ie. read access if you
474 just want to read the image or write access if you want to modify the
475 image).
476
477 This is equivalent to the qemu parameter
478 C<-drive file=filename,cache=off,if=...>.
479 C<cache=off> is omitted in cases where it is not supported by
480 the underlying filesystem.
481
482 Note that this call checks for the existence of C<filename>.  This
483 stops you from specifying other types of drive which are supported
484 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
485 the general C<guestfs_config> call instead.");
486
487   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
488    [],
489    "add a CD-ROM disk image to examine",
490    "\
491 This function adds a virtual CD-ROM disk image to the guest.
492
493 This is equivalent to the qemu parameter C<-cdrom filename>.
494
495 Note that this call checks for the existence of C<filename>.  This
496 stops you from specifying other types of drive which are supported
497 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
498 the general C<guestfs_config> call instead.");
499
500   ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
501    [],
502    "add a drive in snapshot mode (read-only)",
503    "\
504 This adds a drive in snapshot mode, making it effectively
505 read-only.
506
507 Note that writes to the device are allowed, and will be seen for
508 the duration of the guestfs handle, but they are written
509 to a temporary file which is discarded as soon as the guestfs
510 handle is closed.  We don't currently have any method to enable
511 changes to be committed, although qemu can support this.
512
513 This is equivalent to the qemu parameter
514 C<-drive file=filename,snapshot=on,if=...>.
515
516 Note that this call checks for the existence of C<filename>.  This
517 stops you from specifying other types of drive which are supported
518 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
519 the general C<guestfs_config> call instead.");
520
521   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
522    [],
523    "add qemu parameters",
524    "\
525 This can be used to add arbitrary qemu command line parameters
526 of the form C<-param value>.  Actually it's not quite arbitrary - we
527 prevent you from setting some parameters which would interfere with
528 parameters that we use.
529
530 The first character of C<param> string must be a C<-> (dash).
531
532 C<value> can be NULL.");
533
534   ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
535    [],
536    "set the qemu binary",
537    "\
538 Set the qemu binary that we will use.
539
540 The default is chosen when the library was compiled by the
541 configure script.
542
543 You can also override this by setting the C<LIBGUESTFS_QEMU>
544 environment variable.
545
546 Setting C<qemu> to C<NULL> restores the default qemu binary.");
547
548   ("get_qemu", (RConstString "qemu", []), -1, [],
549    [InitNone, Always, TestRun (
550       [["get_qemu"]])],
551    "get the qemu binary",
552    "\
553 Return the current qemu binary.
554
555 This is always non-NULL.  If it wasn't set already, then this will
556 return the default qemu binary name.");
557
558   ("set_path", (RErr, [String "searchpath"]), -1, [FishAlias "path"],
559    [],
560    "set the search path",
561    "\
562 Set the path that libguestfs searches for kernel and initrd.img.
563
564 The default is C<$libdir/guestfs> unless overridden by setting
565 C<LIBGUESTFS_PATH> environment variable.
566
567 Setting C<path> to C<NULL> restores the default path.");
568
569   ("get_path", (RConstString "path", []), -1, [],
570    [InitNone, Always, TestRun (
571       [["get_path"]])],
572    "get the search path",
573    "\
574 Return the current search path.
575
576 This is always non-NULL.  If it wasn't set already, then this will
577 return the default path.");
578
579   ("set_append", (RErr, [OptString "append"]), -1, [FishAlias "append"],
580    [],
581    "add options to kernel command line",
582    "\
583 This function is used to add additional options to the
584 guest kernel command line.
585
586 The default is C<NULL> unless overridden by setting
587 C<LIBGUESTFS_APPEND> environment variable.
588
589 Setting C<append> to C<NULL> means I<no> additional options
590 are passed (libguestfs always adds a few of its own).");
591
592   ("get_append", (RConstOptString "append", []), -1, [],
593    (* This cannot be tested with the current framework.  The
594     * function can return NULL in normal operations, which the
595     * test framework interprets as an error.
596     *)
597    [],
598    "get the additional kernel options",
599    "\
600 Return the additional kernel options which are added to the
601 guest kernel command line.
602
603 If C<NULL> then no options are added.");
604
605   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
606    [],
607    "set autosync mode",
608    "\
609 If C<autosync> is true, this enables autosync.  Libguestfs will make a
610 best effort attempt to run C<guestfs_umount_all> followed by
611 C<guestfs_sync> when the handle is closed
612 (also if the program exits without closing handles).
613
614 This is disabled by default (except in guestfish where it is
615 enabled by default).");
616
617   ("get_autosync", (RBool "autosync", []), -1, [],
618    [InitNone, Always, TestRun (
619       [["get_autosync"]])],
620    "get autosync mode",
621    "\
622 Get the autosync flag.");
623
624   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
625    [],
626    "set verbose mode",
627    "\
628 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
629
630 Verbose messages are disabled unless the environment variable
631 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
632
633   ("get_verbose", (RBool "verbose", []), -1, [],
634    [],
635    "get verbose mode",
636    "\
637 This returns the verbose messages flag.");
638
639   ("is_ready", (RBool "ready", []), -1, [],
640    [InitNone, Always, TestOutputTrue (
641       [["is_ready"]])],
642    "is ready to accept commands",
643    "\
644 This returns true iff this handle is ready to accept commands
645 (in the C<READY> state).
646
647 For more information on states, see L<guestfs(3)>.");
648
649   ("is_config", (RBool "config", []), -1, [],
650    [InitNone, Always, TestOutputFalse (
651       [["is_config"]])],
652    "is in configuration state",
653    "\
654 This returns true iff this handle is being configured
655 (in the C<CONFIG> state).
656
657 For more information on states, see L<guestfs(3)>.");
658
659   ("is_launching", (RBool "launching", []), -1, [],
660    [InitNone, Always, TestOutputFalse (
661       [["is_launching"]])],
662    "is launching subprocess",
663    "\
664 This returns true iff this handle is launching the subprocess
665 (in the C<LAUNCHING> state).
666
667 For more information on states, see L<guestfs(3)>.");
668
669   ("is_busy", (RBool "busy", []), -1, [],
670    [InitNone, Always, TestOutputFalse (
671       [["is_busy"]])],
672    "is busy processing a command",
673    "\
674 This returns true iff this handle is busy processing a command
675 (in the C<BUSY> state).
676
677 For more information on states, see L<guestfs(3)>.");
678
679   ("get_state", (RInt "state", []), -1, [],
680    [],
681    "get the current state",
682    "\
683 This returns the current state as an opaque integer.  This is
684 only useful for printing debug and internal error messages.
685
686 For more information on states, see L<guestfs(3)>.");
687
688   ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
689    [InitNone, Always, TestOutputInt (
690       [["set_memsize"; "500"];
691        ["get_memsize"]], 500)],
692    "set memory allocated to the qemu subprocess",
693    "\
694 This sets the memory size in megabytes allocated to the
695 qemu subprocess.  This only has any effect if called before
696 C<guestfs_launch>.
697
698 You can also change this by setting the environment
699 variable C<LIBGUESTFS_MEMSIZE> before the handle is
700 created.
701
702 For more information on the architecture of libguestfs,
703 see L<guestfs(3)>.");
704
705   ("get_memsize", (RInt "memsize", []), -1, [],
706    [InitNone, Always, TestOutputIntOp (
707       [["get_memsize"]], ">=", 256)],
708    "get memory allocated to the qemu subprocess",
709    "\
710 This gets the memory size in megabytes allocated to the
711 qemu subprocess.
712
713 If C<guestfs_set_memsize> was not called
714 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
715 then this returns the compiled-in default value for memsize.
716
717 For more information on the architecture of libguestfs,
718 see L<guestfs(3)>.");
719
720   ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"],
721    [InitNone, Always, TestOutputIntOp (
722       [["get_pid"]], ">=", 1)],
723    "get PID of qemu subprocess",
724    "\
725 Return the process ID of the qemu subprocess.  If there is no
726 qemu subprocess, then this will return an error.
727
728 This is an internal call used for debugging and testing.");
729
730   ("version", (RStruct ("version", "version"), []), -1, [],
731    [InitNone, Always, TestOutputStruct (
732       [["version"]], [CompareWithInt ("major", 1)])],
733    "get the library version number",
734    "\
735 Return the libguestfs version number that the program is linked
736 against.
737
738 Note that because of dynamic linking this is not necessarily
739 the version of libguestfs that you compiled against.  You can
740 compile the program, and then at runtime dynamically link
741 against a completely different C<libguestfs.so> library.
742
743 This call was added in version C<1.0.58>.  In previous
744 versions of libguestfs there was no way to get the version
745 number.  From C code you can use ELF weak linking tricks to find out if
746 this symbol exists (if it doesn't, then it's an earlier version).
747
748 The call returns a structure with four elements.  The first
749 three (C<major>, C<minor> and C<release>) are numbers and
750 correspond to the usual version triplet.  The fourth element
751 (C<extra>) is a string and is normally empty, but may be
752 used for distro-specific information.
753
754 To construct the original version string:
755 C<$major.$minor.$release$extra>
756
757 I<Note:> Don't use this call to test for availability
758 of features.  Distro backports makes this unreliable.");
759
760   ("set_selinux", (RErr, [Bool "selinux"]), -1, [FishAlias "selinux"],
761    [InitNone, Always, TestOutputTrue (
762       [["set_selinux"; "true"];
763        ["get_selinux"]])],
764    "set SELinux enabled or disabled at appliance boot",
765    "\
766 This sets the selinux flag that is passed to the appliance
767 at boot time.  The default is C<selinux=0> (disabled).
768
769 Note that if SELinux is enabled, it is always in
770 Permissive mode (C<enforcing=0>).
771
772 For more information on the architecture of libguestfs,
773 see L<guestfs(3)>.");
774
775   ("get_selinux", (RBool "selinux", []), -1, [],
776    [],
777    "get SELinux enabled flag",
778    "\
779 This returns the current setting of the selinux flag which
780 is passed to the appliance at boot time.  See C<guestfs_set_selinux>.
781
782 For more information on the architecture of libguestfs,
783 see L<guestfs(3)>.");
784
785   ("set_trace", (RErr, [Bool "trace"]), -1, [FishAlias "trace"],
786    [InitNone, Always, TestOutputFalse (
787       [["set_trace"; "false"];
788        ["get_trace"]])],
789    "enable or disable command traces",
790    "\
791 If the command trace flag is set to 1, then commands are
792 printed on stdout before they are executed in a format
793 which is very similar to the one used by guestfish.  In
794 other words, you can run a program with this enabled, and
795 you will get out a script which you can feed to guestfish
796 to perform the same set of actions.
797
798 If you want to trace C API calls into libguestfs (and
799 other libraries) then possibly a better way is to use
800 the external ltrace(1) command.
801
802 Command traces are disabled unless the environment variable
803 C<LIBGUESTFS_TRACE> is defined and set to C<1>.");
804
805   ("get_trace", (RBool "trace", []), -1, [],
806    [],
807    "get command trace enabled flag",
808    "\
809 Return the command trace flag.");
810
811 ]
812
813 (* daemon_functions are any functions which cause some action
814  * to take place in the daemon.
815  *)
816
817 let daemon_functions = [
818   ("mount", (RErr, [Device "device"; String "mountpoint"]), 1, [],
819    [InitEmpty, Always, TestOutput (
820       [["sfdiskM"; "/dev/sda"; ","];
821        ["mkfs"; "ext2"; "/dev/sda1"];
822        ["mount"; "/dev/sda1"; "/"];
823        ["write_file"; "/new"; "new file contents"; "0"];
824        ["cat"; "/new"]], "new file contents")],
825    "mount a guest disk at a position in the filesystem",
826    "\
827 Mount a guest disk at a position in the filesystem.  Block devices
828 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
829 the guest.  If those block devices contain partitions, they will have
830 the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
831 names can be used.
832
833 The rules are the same as for L<mount(2)>:  A filesystem must
834 first be mounted on C</> before others can be mounted.  Other
835 filesystems can only be mounted on directories which already
836 exist.
837
838 The mounted filesystem is writable, if we have sufficient permissions
839 on the underlying device.
840
841 The filesystem options C<sync> and C<noatime> are set with this
842 call, in order to improve reliability.");
843
844   ("sync", (RErr, []), 2, [],
845    [ InitEmpty, Always, TestRun [["sync"]]],
846    "sync disks, writes are flushed through to the disk image",
847    "\
848 This syncs the disk, so that any writes are flushed through to the
849 underlying disk image.
850
851 You should always call this if you have modified a disk image, before
852 closing the handle.");
853
854   ("touch", (RErr, [Pathname "path"]), 3, [],
855    [InitBasicFS, Always, TestOutputTrue (
856       [["touch"; "/new"];
857        ["exists"; "/new"]])],
858    "update file timestamps or create a new file",
859    "\
860 Touch acts like the L<touch(1)> command.  It can be used to
861 update the timestamps on a file, or, if the file does not exist,
862 to create a new zero-length file.");
863
864   ("cat", (RString "content", [Pathname "path"]), 4, [ProtocolLimitWarning],
865    [InitISOFS, Always, TestOutput (
866       [["cat"; "/known-2"]], "abcdef\n")],
867    "list the contents of a file",
868    "\
869 Return the contents of the file named C<path>.
870
871 Note that this function cannot correctly handle binary files
872 (specifically, files containing C<\\0> character which is treated
873 as end of string).  For those you need to use the C<guestfs_read_file>
874 or C<guestfs_download> functions which have a more complex interface.");
875
876   ("ll", (RString "listing", [Pathname "directory"]), 5, [],
877    [], (* XXX Tricky to test because it depends on the exact format
878         * of the 'ls -l' command, which changes between F10 and F11.
879         *)
880    "list the files in a directory (long format)",
881    "\
882 List the files in C<directory> (relative to the root directory,
883 there is no cwd) in the format of 'ls -la'.
884
885 This command is mostly useful for interactive sessions.  It
886 is I<not> intended that you try to parse the output string.");
887
888   ("ls", (RStringList "listing", [Pathname "directory"]), 6, [],
889    [InitBasicFS, Always, TestOutputList (
890       [["touch"; "/new"];
891        ["touch"; "/newer"];
892        ["touch"; "/newest"];
893        ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
894    "list the files in a directory",
895    "\
896 List the files in C<directory> (relative to the root directory,
897 there is no cwd).  The '.' and '..' entries are not returned, but
898 hidden files are shown.
899
900 This command is mostly useful for interactive sessions.  Programs
901 should probably use C<guestfs_readdir> instead.");
902
903   ("list_devices", (RStringList "devices", []), 7, [],
904    [InitEmpty, Always, TestOutputListOfDevices (
905       [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
906    "list the block devices",
907    "\
908 List all the block devices.
909
910 The full block device names are returned, eg. C</dev/sda>");
911
912   ("list_partitions", (RStringList "partitions", []), 8, [],
913    [InitBasicFS, Always, TestOutputListOfDevices (
914       [["list_partitions"]], ["/dev/sda1"]);
915     InitEmpty, Always, TestOutputListOfDevices (
916       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
917        ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
918    "list the partitions",
919    "\
920 List all the partitions detected on all block devices.
921
922 The full partition device names are returned, eg. C</dev/sda1>
923
924 This does not return logical volumes.  For that you will need to
925 call C<guestfs_lvs>.");
926
927   ("pvs", (RStringList "physvols", []), 9, [],
928    [InitBasicFSonLVM, Always, TestOutputListOfDevices (
929       [["pvs"]], ["/dev/sda1"]);
930     InitEmpty, Always, TestOutputListOfDevices (
931       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
932        ["pvcreate"; "/dev/sda1"];
933        ["pvcreate"; "/dev/sda2"];
934        ["pvcreate"; "/dev/sda3"];
935        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
936    "list the LVM physical volumes (PVs)",
937    "\
938 List all the physical volumes detected.  This is the equivalent
939 of the L<pvs(8)> command.
940
941 This returns a list of just the device names that contain
942 PVs (eg. C</dev/sda2>).
943
944 See also C<guestfs_pvs_full>.");
945
946   ("vgs", (RStringList "volgroups", []), 10, [],
947    [InitBasicFSonLVM, Always, TestOutputList (
948       [["vgs"]], ["VG"]);
949     InitEmpty, Always, TestOutputList (
950       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
951        ["pvcreate"; "/dev/sda1"];
952        ["pvcreate"; "/dev/sda2"];
953        ["pvcreate"; "/dev/sda3"];
954        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
955        ["vgcreate"; "VG2"; "/dev/sda3"];
956        ["vgs"]], ["VG1"; "VG2"])],
957    "list the LVM volume groups (VGs)",
958    "\
959 List all the volumes groups detected.  This is the equivalent
960 of the L<vgs(8)> command.
961
962 This returns a list of just the volume group names that were
963 detected (eg. C<VolGroup00>).
964
965 See also C<guestfs_vgs_full>.");
966
967   ("lvs", (RStringList "logvols", []), 11, [],
968    [InitBasicFSonLVM, Always, TestOutputList (
969       [["lvs"]], ["/dev/VG/LV"]);
970     InitEmpty, Always, TestOutputList (
971       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
972        ["pvcreate"; "/dev/sda1"];
973        ["pvcreate"; "/dev/sda2"];
974        ["pvcreate"; "/dev/sda3"];
975        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
976        ["vgcreate"; "VG2"; "/dev/sda3"];
977        ["lvcreate"; "LV1"; "VG1"; "50"];
978        ["lvcreate"; "LV2"; "VG1"; "50"];
979        ["lvcreate"; "LV3"; "VG2"; "50"];
980        ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
981    "list the LVM logical volumes (LVs)",
982    "\
983 List all the logical volumes detected.  This is the equivalent
984 of the L<lvs(8)> command.
985
986 This returns a list of the logical volume device names
987 (eg. C</dev/VolGroup00/LogVol00>).
988
989 See also C<guestfs_lvs_full>.");
990
991   ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [],
992    [], (* XXX how to test? *)
993    "list the LVM physical volumes (PVs)",
994    "\
995 List all the physical volumes detected.  This is the equivalent
996 of the L<pvs(8)> command.  The \"full\" version includes all fields.");
997
998   ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [],
999    [], (* XXX how to test? *)
1000    "list the LVM volume groups (VGs)",
1001    "\
1002 List all the volumes groups detected.  This is the equivalent
1003 of the L<vgs(8)> command.  The \"full\" version includes all fields.");
1004
1005   ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [],
1006    [], (* XXX how to test? *)
1007    "list the LVM logical volumes (LVs)",
1008    "\
1009 List all the logical volumes detected.  This is the equivalent
1010 of the L<lvs(8)> command.  The \"full\" version includes all fields.");
1011
1012   ("read_lines", (RStringList "lines", [Pathname "path"]), 15, [],
1013    [InitISOFS, Always, TestOutputList (
1014       [["read_lines"; "/known-4"]], ["abc"; "def"; "ghi"]);
1015     InitISOFS, Always, TestOutputList (
1016       [["read_lines"; "/empty"]], [])],
1017    "read file as lines",
1018    "\
1019 Return the contents of the file named C<path>.
1020
1021 The file contents are returned as a list of lines.  Trailing
1022 C<LF> and C<CRLF> character sequences are I<not> returned.
1023
1024 Note that this function cannot correctly handle binary files
1025 (specifically, files containing C<\\0> character which is treated
1026 as end of line).  For those you need to use the C<guestfs_read_file>
1027 function which has a more complex interface.");
1028
1029   ("aug_init", (RErr, [Pathname "root"; Int "flags"]), 16, [],
1030    [], (* XXX Augeas code needs tests. *)
1031    "create a new Augeas handle",
1032    "\
1033 Create a new Augeas handle for editing configuration files.
1034 If there was any previous Augeas handle associated with this
1035 guestfs session, then it is closed.
1036
1037 You must call this before using any other C<guestfs_aug_*>
1038 commands.
1039
1040 C<root> is the filesystem root.  C<root> must not be NULL,
1041 use C</> instead.
1042
1043 The flags are the same as the flags defined in
1044 E<lt>augeas.hE<gt>, the logical I<or> of the following
1045 integers:
1046
1047 =over 4
1048
1049 =item C<AUG_SAVE_BACKUP> = 1
1050
1051 Keep the original file with a C<.augsave> extension.
1052
1053 =item C<AUG_SAVE_NEWFILE> = 2
1054
1055 Save changes into a file with extension C<.augnew>, and
1056 do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
1057
1058 =item C<AUG_TYPE_CHECK> = 4
1059
1060 Typecheck lenses (can be expensive).
1061
1062 =item C<AUG_NO_STDINC> = 8
1063
1064 Do not use standard load path for modules.
1065
1066 =item C<AUG_SAVE_NOOP> = 16
1067
1068 Make save a no-op, just record what would have been changed.
1069
1070 =item C<AUG_NO_LOAD> = 32
1071
1072 Do not load the tree in C<guestfs_aug_init>.
1073
1074 =back
1075
1076 To close the handle, you can call C<guestfs_aug_close>.
1077
1078 To find out more about Augeas, see L<http://augeas.net/>.");
1079
1080   ("aug_close", (RErr, []), 26, [],
1081    [], (* XXX Augeas code needs tests. *)
1082    "close the current Augeas handle",
1083    "\
1084 Close the current Augeas handle and free up any resources
1085 used by it.  After calling this, you have to call
1086 C<guestfs_aug_init> again before you can use any other
1087 Augeas functions.");
1088
1089   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
1090    [], (* XXX Augeas code needs tests. *)
1091    "define an Augeas variable",
1092    "\
1093 Defines an Augeas variable C<name> whose value is the result
1094 of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
1095 undefined.
1096
1097 On success this returns the number of nodes in C<expr>, or
1098 C<0> if C<expr> evaluates to something which is not a nodeset.");
1099
1100   ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [],
1101    [], (* XXX Augeas code needs tests. *)
1102    "define an Augeas node",
1103    "\
1104 Defines a variable C<name> whose value is the result of
1105 evaluating C<expr>.
1106
1107 If C<expr> evaluates to an empty nodeset, a node is created,
1108 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
1109 C<name> will be the nodeset containing that single node.
1110
1111 On success this returns a pair containing the
1112 number of nodes in the nodeset, and a boolean flag
1113 if a node was created.");
1114
1115   ("aug_get", (RString "val", [String "augpath"]), 19, [],
1116    [], (* XXX Augeas code needs tests. *)
1117    "look up the value of an Augeas path",
1118    "\
1119 Look up the value associated with C<path>.  If C<path>
1120 matches exactly one node, the C<value> is returned.");
1121
1122   ("aug_set", (RErr, [String "augpath"; String "val"]), 20, [],
1123    [], (* XXX Augeas code needs tests. *)
1124    "set Augeas path to value",
1125    "\
1126 Set the value associated with C<path> to C<value>.");
1127
1128   ("aug_insert", (RErr, [String "augpath"; String "label"; Bool "before"]), 21, [],
1129    [], (* XXX Augeas code needs tests. *)
1130    "insert a sibling Augeas node",
1131    "\
1132 Create a new sibling C<label> for C<path>, inserting it into
1133 the tree before or after C<path> (depending on the boolean
1134 flag C<before>).
1135
1136 C<path> must match exactly one existing node in the tree, and
1137 C<label> must be a label, ie. not contain C</>, C<*> or end
1138 with a bracketed index C<[N]>.");
1139
1140   ("aug_rm", (RInt "nrnodes", [String "augpath"]), 22, [],
1141    [], (* XXX Augeas code needs tests. *)
1142    "remove an Augeas path",
1143    "\
1144 Remove C<path> and all of its children.
1145
1146 On success this returns the number of entries which were removed.");
1147
1148   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
1149    [], (* XXX Augeas code needs tests. *)
1150    "move Augeas node",
1151    "\
1152 Move the node C<src> to C<dest>.  C<src> must match exactly
1153 one node.  C<dest> is overwritten if it exists.");
1154
1155   ("aug_match", (RStringList "matches", [String "augpath"]), 24, [],
1156    [], (* XXX Augeas code needs tests. *)
1157    "return Augeas nodes which match augpath",
1158    "\
1159 Returns a list of paths which match the path expression C<path>.
1160 The returned paths are sufficiently qualified so that they match
1161 exactly one node in the current tree.");
1162
1163   ("aug_save", (RErr, []), 25, [],
1164    [], (* XXX Augeas code needs tests. *)
1165    "write all pending Augeas changes to disk",
1166    "\
1167 This writes all pending changes to disk.
1168
1169 The flags which were passed to C<guestfs_aug_init> affect exactly
1170 how files are saved.");
1171
1172   ("aug_load", (RErr, []), 27, [],
1173    [], (* XXX Augeas code needs tests. *)
1174    "load files into the tree",
1175    "\
1176 Load files into the tree.
1177
1178 See C<aug_load> in the Augeas documentation for the full gory
1179 details.");
1180
1181   ("aug_ls", (RStringList "matches", [String "augpath"]), 28, [],
1182    [], (* XXX Augeas code needs tests. *)
1183    "list Augeas nodes under augpath",
1184    "\
1185 This is just a shortcut for listing C<guestfs_aug_match>
1186 C<path/*> and sorting the resulting nodes into alphabetical order.");
1187
1188   ("rm", (RErr, [Pathname "path"]), 29, [],
1189    [InitBasicFS, Always, TestRun
1190       [["touch"; "/new"];
1191        ["rm"; "/new"]];
1192     InitBasicFS, Always, TestLastFail
1193       [["rm"; "/new"]];
1194     InitBasicFS, Always, TestLastFail
1195       [["mkdir"; "/new"];
1196        ["rm"; "/new"]]],
1197    "remove a file",
1198    "\
1199 Remove the single file C<path>.");
1200
1201   ("rmdir", (RErr, [Pathname "path"]), 30, [],
1202    [InitBasicFS, Always, TestRun
1203       [["mkdir"; "/new"];
1204        ["rmdir"; "/new"]];
1205     InitBasicFS, Always, TestLastFail
1206       [["rmdir"; "/new"]];
1207     InitBasicFS, Always, TestLastFail
1208       [["touch"; "/new"];
1209        ["rmdir"; "/new"]]],
1210    "remove a directory",
1211    "\
1212 Remove the single directory C<path>.");
1213
1214   ("rm_rf", (RErr, [Pathname "path"]), 31, [],
1215    [InitBasicFS, Always, TestOutputFalse
1216       [["mkdir"; "/new"];
1217        ["mkdir"; "/new/foo"];
1218        ["touch"; "/new/foo/bar"];
1219        ["rm_rf"; "/new"];
1220        ["exists"; "/new"]]],
1221    "remove a file or directory recursively",
1222    "\
1223 Remove the file or directory C<path>, recursively removing the
1224 contents if its a directory.  This is like the C<rm -rf> shell
1225 command.");
1226
1227   ("mkdir", (RErr, [Pathname "path"]), 32, [],
1228    [InitBasicFS, Always, TestOutputTrue
1229       [["mkdir"; "/new"];
1230        ["is_dir"; "/new"]];
1231     InitBasicFS, Always, TestLastFail
1232       [["mkdir"; "/new/foo/bar"]]],
1233    "create a directory",
1234    "\
1235 Create a directory named C<path>.");
1236
1237   ("mkdir_p", (RErr, [Pathname "path"]), 33, [],
1238    [InitBasicFS, Always, TestOutputTrue
1239       [["mkdir_p"; "/new/foo/bar"];
1240        ["is_dir"; "/new/foo/bar"]];
1241     InitBasicFS, Always, TestOutputTrue
1242       [["mkdir_p"; "/new/foo/bar"];
1243        ["is_dir"; "/new/foo"]];
1244     InitBasicFS, Always, TestOutputTrue
1245       [["mkdir_p"; "/new/foo/bar"];
1246        ["is_dir"; "/new"]];
1247     (* Regression tests for RHBZ#503133: *)
1248     InitBasicFS, Always, TestRun
1249       [["mkdir"; "/new"];
1250        ["mkdir_p"; "/new"]];
1251     InitBasicFS, Always, TestLastFail
1252       [["touch"; "/new"];
1253        ["mkdir_p"; "/new"]]],
1254    "create a directory and parents",
1255    "\
1256 Create a directory named C<path>, creating any parent directories
1257 as necessary.  This is like the C<mkdir -p> shell command.");
1258
1259   ("chmod", (RErr, [Int "mode"; Pathname "path"]), 34, [],
1260    [], (* XXX Need stat command to test *)
1261    "change file mode",
1262    "\
1263 Change the mode (permissions) of C<path> to C<mode>.  Only
1264 numeric modes are supported.");
1265
1266   ("chown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 35, [],
1267    [], (* XXX Need stat command to test *)
1268    "change file owner and group",
1269    "\
1270 Change the file owner to C<owner> and group to C<group>.
1271
1272 Only numeric uid and gid are supported.  If you want to use
1273 names, you will need to locate and parse the password file
1274 yourself (Augeas support makes this relatively easy).");
1275
1276   ("exists", (RBool "existsflag", [Pathname "path"]), 36, [],
1277    [InitISOFS, Always, TestOutputTrue (
1278       [["exists"; "/empty"]]);
1279     InitISOFS, Always, TestOutputTrue (
1280       [["exists"; "/directory"]])],
1281    "test if file or directory exists",
1282    "\
1283 This returns C<true> if and only if there is a file, directory
1284 (or anything) with the given C<path> name.
1285
1286 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1287
1288   ("is_file", (RBool "fileflag", [Pathname "path"]), 37, [],
1289    [InitISOFS, Always, TestOutputTrue (
1290       [["is_file"; "/known-1"]]);
1291     InitISOFS, Always, TestOutputFalse (
1292       [["is_file"; "/directory"]])],
1293    "test if file exists",
1294    "\
1295 This returns C<true> if and only if there is a file
1296 with the given C<path> name.  Note that it returns false for
1297 other objects like directories.
1298
1299 See also C<guestfs_stat>.");
1300
1301   ("is_dir", (RBool "dirflag", [Pathname "path"]), 38, [],
1302    [InitISOFS, Always, TestOutputFalse (
1303       [["is_dir"; "/known-3"]]);
1304     InitISOFS, Always, TestOutputTrue (
1305       [["is_dir"; "/directory"]])],
1306    "test if file exists",
1307    "\
1308 This returns C<true> if and only if there is a directory
1309 with the given C<path> name.  Note that it returns false for
1310 other objects like files.
1311
1312 See also C<guestfs_stat>.");
1313
1314   ("pvcreate", (RErr, [Device "device"]), 39, [],
1315    [InitEmpty, Always, TestOutputListOfDevices (
1316       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1317        ["pvcreate"; "/dev/sda1"];
1318        ["pvcreate"; "/dev/sda2"];
1319        ["pvcreate"; "/dev/sda3"];
1320        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1321    "create an LVM physical volume",
1322    "\
1323 This creates an LVM physical volume on the named C<device>,
1324 where C<device> should usually be a partition name such
1325 as C</dev/sda1>.");
1326
1327   ("vgcreate", (RErr, [String "volgroup"; DeviceList "physvols"]), 40, [],
1328    [InitEmpty, Always, TestOutputList (
1329       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1330        ["pvcreate"; "/dev/sda1"];
1331        ["pvcreate"; "/dev/sda2"];
1332        ["pvcreate"; "/dev/sda3"];
1333        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1334        ["vgcreate"; "VG2"; "/dev/sda3"];
1335        ["vgs"]], ["VG1"; "VG2"])],
1336    "create an LVM volume group",
1337    "\
1338 This creates an LVM volume group called C<volgroup>
1339 from the non-empty list of physical volumes C<physvols>.");
1340
1341   ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
1342    [InitEmpty, Always, TestOutputList (
1343       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1344        ["pvcreate"; "/dev/sda1"];
1345        ["pvcreate"; "/dev/sda2"];
1346        ["pvcreate"; "/dev/sda3"];
1347        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1348        ["vgcreate"; "VG2"; "/dev/sda3"];
1349        ["lvcreate"; "LV1"; "VG1"; "50"];
1350        ["lvcreate"; "LV2"; "VG1"; "50"];
1351        ["lvcreate"; "LV3"; "VG2"; "50"];
1352        ["lvcreate"; "LV4"; "VG2"; "50"];
1353        ["lvcreate"; "LV5"; "VG2"; "50"];
1354        ["lvs"]],
1355       ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1356        "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1357    "create an LVM volume group",
1358    "\
1359 This creates an LVM volume group called C<logvol>
1360 on the volume group C<volgroup>, with C<size> megabytes.");
1361
1362   ("mkfs", (RErr, [String "fstype"; Device "device"]), 42, [],
1363    [InitEmpty, Always, TestOutput (
1364       [["sfdiskM"; "/dev/sda"; ","];
1365        ["mkfs"; "ext2"; "/dev/sda1"];
1366        ["mount"; "/dev/sda1"; "/"];
1367        ["write_file"; "/new"; "new file contents"; "0"];
1368        ["cat"; "/new"]], "new file contents")],
1369    "make a filesystem",
1370    "\
1371 This creates a filesystem on C<device> (usually a partition
1372 or LVM logical volume).  The filesystem type is C<fstype>, for
1373 example C<ext3>.");
1374
1375   ("sfdisk", (RErr, [Device "device";
1376                      Int "cyls"; Int "heads"; Int "sectors";
1377                      StringList "lines"]), 43, [DangerWillRobinson],
1378    [],
1379    "create partitions on a block device",
1380    "\
1381 This is a direct interface to the L<sfdisk(8)> program for creating
1382 partitions on block devices.
1383
1384 C<device> should be a block device, for example C</dev/sda>.
1385
1386 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1387 and sectors on the device, which are passed directly to sfdisk as
1388 the I<-C>, I<-H> and I<-S> parameters.  If you pass C<0> for any
1389 of these, then the corresponding parameter is omitted.  Usually for
1390 'large' disks, you can just pass C<0> for these, but for small
1391 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1392 out the right geometry and you will need to tell it.
1393
1394 C<lines> is a list of lines that we feed to C<sfdisk>.  For more
1395 information refer to the L<sfdisk(8)> manpage.
1396
1397 To create a single partition occupying the whole disk, you would
1398 pass C<lines> as a single element list, when the single element being
1399 the string C<,> (comma).
1400
1401 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>");
1402
1403   ("write_file", (RErr, [Pathname "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1404    [InitBasicFS, Always, TestOutput (
1405       [["write_file"; "/new"; "new file contents"; "0"];
1406        ["cat"; "/new"]], "new file contents");
1407     InitBasicFS, Always, TestOutput (
1408       [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1409        ["cat"; "/new"]], "\nnew file contents\n");
1410     InitBasicFS, Always, TestOutput (
1411       [["write_file"; "/new"; "\n\n"; "0"];
1412        ["cat"; "/new"]], "\n\n");
1413     InitBasicFS, Always, TestOutput (
1414       [["write_file"; "/new"; ""; "0"];
1415        ["cat"; "/new"]], "");
1416     InitBasicFS, Always, TestOutput (
1417       [["write_file"; "/new"; "\n\n\n"; "0"];
1418        ["cat"; "/new"]], "\n\n\n");
1419     InitBasicFS, Always, TestOutput (
1420       [["write_file"; "/new"; "\n"; "0"];
1421        ["cat"; "/new"]], "\n")],
1422    "create a file",
1423    "\
1424 This call creates a file called C<path>.  The contents of the
1425 file is the string C<content> (which can contain any 8 bit data),
1426 with length C<size>.
1427
1428 As a special case, if C<size> is C<0>
1429 then the length is calculated using C<strlen> (so in this case
1430 the content cannot contain embedded ASCII NULs).
1431
1432 I<NB.> Owing to a bug, writing content containing ASCII NUL
1433 characters does I<not> work, even if the length is specified.
1434 We hope to resolve this bug in a future version.  In the meantime
1435 use C<guestfs_upload>.");
1436
1437   ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1438    [InitEmpty, Always, TestOutputListOfDevices (
1439       [["sfdiskM"; "/dev/sda"; ","];
1440        ["mkfs"; "ext2"; "/dev/sda1"];
1441        ["mount"; "/dev/sda1"; "/"];
1442        ["mounts"]], ["/dev/sda1"]);
1443     InitEmpty, Always, TestOutputList (
1444       [["sfdiskM"; "/dev/sda"; ","];
1445        ["mkfs"; "ext2"; "/dev/sda1"];
1446        ["mount"; "/dev/sda1"; "/"];
1447        ["umount"; "/"];
1448        ["mounts"]], [])],
1449    "unmount a filesystem",
1450    "\
1451 This unmounts the given filesystem.  The filesystem may be
1452 specified either by its mountpoint (path) or the device which
1453 contains the filesystem.");
1454
1455   ("mounts", (RStringList "devices", []), 46, [],
1456    [InitBasicFS, Always, TestOutputListOfDevices (
1457       [["mounts"]], ["/dev/sda1"])],
1458    "show mounted filesystems",
1459    "\
1460 This returns the list of currently mounted filesystems.  It returns
1461 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1462
1463 Some internal mounts are not shown.
1464
1465 See also: C<guestfs_mountpoints>");
1466
1467   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1468    [InitBasicFS, Always, TestOutputList (
1469       [["umount_all"];
1470        ["mounts"]], []);
1471     (* check that umount_all can unmount nested mounts correctly: *)
1472     InitEmpty, Always, TestOutputList (
1473       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1474        ["mkfs"; "ext2"; "/dev/sda1"];
1475        ["mkfs"; "ext2"; "/dev/sda2"];
1476        ["mkfs"; "ext2"; "/dev/sda3"];
1477        ["mount"; "/dev/sda1"; "/"];
1478        ["mkdir"; "/mp1"];
1479        ["mount"; "/dev/sda2"; "/mp1"];
1480        ["mkdir"; "/mp1/mp2"];
1481        ["mount"; "/dev/sda3"; "/mp1/mp2"];
1482        ["mkdir"; "/mp1/mp2/mp3"];
1483        ["umount_all"];
1484        ["mounts"]], [])],
1485    "unmount all filesystems",
1486    "\
1487 This unmounts all mounted filesystems.
1488
1489 Some internal mounts are not unmounted by this call.");
1490
1491   ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
1492    [],
1493    "remove all LVM LVs, VGs and PVs",
1494    "\
1495 This command removes all LVM logical volumes, volume groups
1496 and physical volumes.");
1497
1498   ("file", (RString "description", [Dev_or_Path "path"]), 49, [],
1499    [InitISOFS, Always, TestOutput (
1500       [["file"; "/empty"]], "empty");
1501     InitISOFS, Always, TestOutput (
1502       [["file"; "/known-1"]], "ASCII text");
1503     InitISOFS, Always, TestLastFail (
1504       [["file"; "/notexists"]])],
1505    "determine file type",
1506    "\
1507 This call uses the standard L<file(1)> command to determine
1508 the type or contents of the file.  This also works on devices,
1509 for example to find out whether a partition contains a filesystem.
1510
1511 This call will also transparently look inside various types
1512 of compressed file.
1513
1514 The exact command which runs is C<file -zbsL path>.  Note in
1515 particular that the filename is not prepended to the output
1516 (the C<-b> option).");
1517
1518   ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1519    [InitBasicFS, Always, TestOutput (
1520       [["upload"; "test-command"; "/test-command"];
1521        ["chmod"; "0o755"; "/test-command"];
1522        ["command"; "/test-command 1"]], "Result1");
1523     InitBasicFS, Always, TestOutput (
1524       [["upload"; "test-command"; "/test-command"];
1525        ["chmod"; "0o755"; "/test-command"];
1526        ["command"; "/test-command 2"]], "Result2\n");
1527     InitBasicFS, Always, TestOutput (
1528       [["upload"; "test-command"; "/test-command"];
1529        ["chmod"; "0o755"; "/test-command"];
1530        ["command"; "/test-command 3"]], "\nResult3");
1531     InitBasicFS, Always, TestOutput (
1532       [["upload"; "test-command"; "/test-command"];
1533        ["chmod"; "0o755"; "/test-command"];
1534        ["command"; "/test-command 4"]], "\nResult4\n");
1535     InitBasicFS, Always, TestOutput (
1536       [["upload"; "test-command"; "/test-command"];
1537        ["chmod"; "0o755"; "/test-command"];
1538        ["command"; "/test-command 5"]], "\nResult5\n\n");
1539     InitBasicFS, Always, TestOutput (
1540       [["upload"; "test-command"; "/test-command"];
1541        ["chmod"; "0o755"; "/test-command"];
1542        ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1543     InitBasicFS, Always, TestOutput (
1544       [["upload"; "test-command"; "/test-command"];
1545        ["chmod"; "0o755"; "/test-command"];
1546        ["command"; "/test-command 7"]], "");
1547     InitBasicFS, Always, TestOutput (
1548       [["upload"; "test-command"; "/test-command"];
1549        ["chmod"; "0o755"; "/test-command"];
1550        ["command"; "/test-command 8"]], "\n");
1551     InitBasicFS, Always, TestOutput (
1552       [["upload"; "test-command"; "/test-command"];
1553        ["chmod"; "0o755"; "/test-command"];
1554        ["command"; "/test-command 9"]], "\n\n");
1555     InitBasicFS, Always, TestOutput (
1556       [["upload"; "test-command"; "/test-command"];
1557        ["chmod"; "0o755"; "/test-command"];
1558        ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1559     InitBasicFS, Always, TestOutput (
1560       [["upload"; "test-command"; "/test-command"];
1561        ["chmod"; "0o755"; "/test-command"];
1562        ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1563     InitBasicFS, Always, TestLastFail (
1564       [["upload"; "test-command"; "/test-command"];
1565        ["chmod"; "0o755"; "/test-command"];
1566        ["command"; "/test-command"]])],
1567    "run a command from the guest filesystem",
1568    "\
1569 This call runs a command from the guest filesystem.  The
1570 filesystem must be mounted, and must contain a compatible
1571 operating system (ie. something Linux, with the same
1572 or compatible processor architecture).
1573
1574 The single parameter is an argv-style list of arguments.
1575 The first element is the name of the program to run.
1576 Subsequent elements are parameters.  The list must be
1577 non-empty (ie. must contain a program name).  Note that
1578 the command runs directly, and is I<not> invoked via
1579 the shell (see C<guestfs_sh>).
1580
1581 The return value is anything printed to I<stdout> by
1582 the command.
1583
1584 If the command returns a non-zero exit status, then
1585 this function returns an error message.  The error message
1586 string is the content of I<stderr> from the command.
1587
1588 The C<$PATH> environment variable will contain at least
1589 C</usr/bin> and C</bin>.  If you require a program from
1590 another location, you should provide the full path in the
1591 first parameter.
1592
1593 Shared libraries and data files required by the program
1594 must be available on filesystems which are mounted in the
1595 correct places.  It is the caller's responsibility to ensure
1596 all filesystems that are needed are mounted at the right
1597 locations.");
1598
1599   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1600    [InitBasicFS, Always, TestOutputList (
1601       [["upload"; "test-command"; "/test-command"];
1602        ["chmod"; "0o755"; "/test-command"];
1603        ["command_lines"; "/test-command 1"]], ["Result1"]);
1604     InitBasicFS, Always, TestOutputList (
1605       [["upload"; "test-command"; "/test-command"];
1606        ["chmod"; "0o755"; "/test-command"];
1607        ["command_lines"; "/test-command 2"]], ["Result2"]);
1608     InitBasicFS, Always, TestOutputList (
1609       [["upload"; "test-command"; "/test-command"];
1610        ["chmod"; "0o755"; "/test-command"];
1611        ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1612     InitBasicFS, Always, TestOutputList (
1613       [["upload"; "test-command"; "/test-command"];
1614        ["chmod"; "0o755"; "/test-command"];
1615        ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1616     InitBasicFS, Always, TestOutputList (
1617       [["upload"; "test-command"; "/test-command"];
1618        ["chmod"; "0o755"; "/test-command"];
1619        ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1620     InitBasicFS, Always, TestOutputList (
1621       [["upload"; "test-command"; "/test-command"];
1622        ["chmod"; "0o755"; "/test-command"];
1623        ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1624     InitBasicFS, Always, TestOutputList (
1625       [["upload"; "test-command"; "/test-command"];
1626        ["chmod"; "0o755"; "/test-command"];
1627        ["command_lines"; "/test-command 7"]], []);
1628     InitBasicFS, Always, TestOutputList (
1629       [["upload"; "test-command"; "/test-command"];
1630        ["chmod"; "0o755"; "/test-command"];
1631        ["command_lines"; "/test-command 8"]], [""]);
1632     InitBasicFS, Always, TestOutputList (
1633       [["upload"; "test-command"; "/test-command"];
1634        ["chmod"; "0o755"; "/test-command"];
1635        ["command_lines"; "/test-command 9"]], ["";""]);
1636     InitBasicFS, Always, TestOutputList (
1637       [["upload"; "test-command"; "/test-command"];
1638        ["chmod"; "0o755"; "/test-command"];
1639        ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1640     InitBasicFS, Always, TestOutputList (
1641       [["upload"; "test-command"; "/test-command"];
1642        ["chmod"; "0o755"; "/test-command"];
1643        ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1644    "run a command, returning lines",
1645    "\
1646 This is the same as C<guestfs_command>, but splits the
1647 result into a list of lines.
1648
1649 See also: C<guestfs_sh_lines>");
1650
1651   ("stat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 52, [],
1652    [InitISOFS, Always, TestOutputStruct (
1653       [["stat"; "/empty"]], [CompareWithInt ("size", 0)])],
1654    "get file information",
1655    "\
1656 Returns file information for the given C<path>.
1657
1658 This is the same as the C<stat(2)> system call.");
1659
1660   ("lstat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 53, [],
1661    [InitISOFS, Always, TestOutputStruct (
1662       [["lstat"; "/empty"]], [CompareWithInt ("size", 0)])],
1663    "get file information for a symbolic link",
1664    "\
1665 Returns file information for the given C<path>.
1666
1667 This is the same as C<guestfs_stat> except that if C<path>
1668 is a symbolic link, then the link is stat-ed, not the file it
1669 refers to.
1670
1671 This is the same as the C<lstat(2)> system call.");
1672
1673   ("statvfs", (RStruct ("statbuf", "statvfs"), [Pathname "path"]), 54, [],
1674    [InitISOFS, Always, TestOutputStruct (
1675       [["statvfs"; "/"]], [CompareWithInt ("namemax", 255)])],
1676    "get file system statistics",
1677    "\
1678 Returns file system statistics for any mounted file system.
1679 C<path> should be a file or directory in the mounted file system
1680 (typically it is the mount point itself, but it doesn't need to be).
1681
1682 This is the same as the C<statvfs(2)> system call.");
1683
1684   ("tune2fs_l", (RHashtable "superblock", [Device "device"]), 55, [],
1685    [], (* XXX test *)
1686    "get ext2/ext3/ext4 superblock details",
1687    "\
1688 This returns the contents of the ext2, ext3 or ext4 filesystem
1689 superblock on C<device>.
1690
1691 It is the same as running C<tune2fs -l device>.  See L<tune2fs(8)>
1692 manpage for more details.  The list of fields returned isn't
1693 clearly defined, and depends on both the version of C<tune2fs>
1694 that libguestfs was built against, and the filesystem itself.");
1695
1696   ("blockdev_setro", (RErr, [Device "device"]), 56, [],
1697    [InitEmpty, Always, TestOutputTrue (
1698       [["blockdev_setro"; "/dev/sda"];
1699        ["blockdev_getro"; "/dev/sda"]])],
1700    "set block device to read-only",
1701    "\
1702 Sets the block device named C<device> to read-only.
1703
1704 This uses the L<blockdev(8)> command.");
1705
1706   ("blockdev_setrw", (RErr, [Device "device"]), 57, [],
1707    [InitEmpty, Always, TestOutputFalse (
1708       [["blockdev_setrw"; "/dev/sda"];
1709        ["blockdev_getro"; "/dev/sda"]])],
1710    "set block device to read-write",
1711    "\
1712 Sets the block device named C<device> to read-write.
1713
1714 This uses the L<blockdev(8)> command.");
1715
1716   ("blockdev_getro", (RBool "ro", [Device "device"]), 58, [],
1717    [InitEmpty, Always, TestOutputTrue (
1718       [["blockdev_setro"; "/dev/sda"];
1719        ["blockdev_getro"; "/dev/sda"]])],
1720    "is block device set to read-only",
1721    "\
1722 Returns a boolean indicating if the block device is read-only
1723 (true if read-only, false if not).
1724
1725 This uses the L<blockdev(8)> command.");
1726
1727   ("blockdev_getss", (RInt "sectorsize", [Device "device"]), 59, [],
1728    [InitEmpty, Always, TestOutputInt (
1729       [["blockdev_getss"; "/dev/sda"]], 512)],
1730    "get sectorsize of block device",
1731    "\
1732 This returns the size of sectors on a block device.
1733 Usually 512, but can be larger for modern devices.
1734
1735 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1736 for that).
1737
1738 This uses the L<blockdev(8)> command.");
1739
1740   ("blockdev_getbsz", (RInt "blocksize", [Device "device"]), 60, [],
1741    [InitEmpty, Always, TestOutputInt (
1742       [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1743    "get blocksize of block device",
1744    "\
1745 This returns the block size of a device.
1746
1747 (Note this is different from both I<size in blocks> and
1748 I<filesystem block size>).
1749
1750 This uses the L<blockdev(8)> command.");
1751
1752   ("blockdev_setbsz", (RErr, [Device "device"; Int "blocksize"]), 61, [],
1753    [], (* XXX test *)
1754    "set blocksize of block device",
1755    "\
1756 This sets the block size of a device.
1757
1758 (Note this is different from both I<size in blocks> and
1759 I<filesystem block size>).
1760
1761 This uses the L<blockdev(8)> command.");
1762
1763   ("blockdev_getsz", (RInt64 "sizeinsectors", [Device "device"]), 62, [],
1764    [InitEmpty, Always, TestOutputInt (
1765       [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1766    "get total size of device in 512-byte sectors",
1767    "\
1768 This returns the size of the device in units of 512-byte sectors
1769 (even if the sectorsize isn't 512 bytes ... weird).
1770
1771 See also C<guestfs_blockdev_getss> for the real sector size of
1772 the device, and C<guestfs_blockdev_getsize64> for the more
1773 useful I<size in bytes>.
1774
1775 This uses the L<blockdev(8)> command.");
1776
1777   ("blockdev_getsize64", (RInt64 "sizeinbytes", [Device "device"]), 63, [],
1778    [InitEmpty, Always, TestOutputInt (
1779       [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1780    "get total size of device in bytes",
1781    "\
1782 This returns the size of the device in bytes.
1783
1784 See also C<guestfs_blockdev_getsz>.
1785
1786 This uses the L<blockdev(8)> command.");
1787
1788   ("blockdev_flushbufs", (RErr, [Device "device"]), 64, [],
1789    [InitEmpty, Always, TestRun
1790       [["blockdev_flushbufs"; "/dev/sda"]]],
1791    "flush device buffers",
1792    "\
1793 This tells the kernel to flush internal buffers associated
1794 with C<device>.
1795
1796 This uses the L<blockdev(8)> command.");
1797
1798   ("blockdev_rereadpt", (RErr, [Device "device"]), 65, [],
1799    [InitEmpty, Always, TestRun
1800       [["blockdev_rereadpt"; "/dev/sda"]]],
1801    "reread partition table",
1802    "\
1803 Reread the partition table on C<device>.
1804
1805 This uses the L<blockdev(8)> command.");
1806
1807   ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
1808    [InitBasicFS, Always, TestOutput (
1809       (* Pick a file from cwd which isn't likely to change. *)
1810       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1811        ["checksum"; "md5"; "/COPYING.LIB"]],
1812         Digest.to_hex (Digest.file "COPYING.LIB"))],
1813    "upload a file from the local machine",
1814    "\
1815 Upload local file C<filename> to C<remotefilename> on the
1816 filesystem.
1817
1818 C<filename> can also be a named pipe.
1819
1820 See also C<guestfs_download>.");
1821
1822   ("download", (RErr, [Dev_or_Path "remotefilename"; FileOut "filename"]), 67, [],
1823    [InitBasicFS, Always, TestOutput (
1824       (* Pick a file from cwd which isn't likely to change. *)
1825       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1826        ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1827        ["upload"; "testdownload.tmp"; "/upload"];
1828        ["checksum"; "md5"; "/upload"]],
1829         Digest.to_hex (Digest.file "COPYING.LIB"))],
1830    "download a file to the local machine",
1831    "\
1832 Download file C<remotefilename> and save it as C<filename>
1833 on the local machine.
1834
1835 C<filename> can also be a named pipe.
1836
1837 See also C<guestfs_upload>, C<guestfs_cat>.");
1838
1839   ("checksum", (RString "checksum", [String "csumtype"; Pathname "path"]), 68, [],
1840    [InitISOFS, Always, TestOutput (
1841       [["checksum"; "crc"; "/known-3"]], "2891671662");
1842     InitISOFS, Always, TestLastFail (
1843       [["checksum"; "crc"; "/notexists"]]);
1844     InitISOFS, Always, TestOutput (
1845       [["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c");
1846     InitISOFS, Always, TestOutput (
1847       [["checksum"; "sha1"; "/known-3"]], "b7ebccc3ee418311091c3eda0a45b83c0a770f15");
1848     InitISOFS, Always, TestOutput (
1849       [["checksum"; "sha224"; "/known-3"]], "d2cd1774b28f3659c14116be0a6dc2bb5c4b350ce9cd5defac707741");
1850     InitISOFS, Always, TestOutput (
1851       [["checksum"; "sha256"; "/known-3"]], "75bb71b90cd20cb13f86d2bea8dad63ac7194e7517c3b52b8d06ff52d3487d30");
1852     InitISOFS, Always, TestOutput (
1853       [["checksum"; "sha384"; "/known-3"]], "5fa7883430f357b5d7b7271d3a1d2872b51d73cba72731de6863d3dea55f30646af2799bef44d5ea776a5ec7941ac640");
1854     InitISOFS, Always, TestOutput (
1855       [["checksum"; "sha512"; "/known-3"]], "2794062c328c6b216dca90443b7f7134c5f40e56bd0ed7853123275a09982a6f992e6ca682f9d2fba34a4c5e870d8fe077694ff831e3032a004ee077e00603f6")],
1856    "compute MD5, SHAx or CRC checksum of file",
1857    "\
1858 This call computes the MD5, SHAx or CRC checksum of the
1859 file named C<path>.
1860
1861 The type of checksum to compute is given by the C<csumtype>
1862 parameter which must have one of the following values:
1863
1864 =over 4
1865
1866 =item C<crc>
1867
1868 Compute the cyclic redundancy check (CRC) specified by POSIX
1869 for the C<cksum> command.
1870
1871 =item C<md5>
1872
1873 Compute the MD5 hash (using the C<md5sum> program).
1874
1875 =item C<sha1>
1876
1877 Compute the SHA1 hash (using the C<sha1sum> program).
1878
1879 =item C<sha224>
1880
1881 Compute the SHA224 hash (using the C<sha224sum> program).
1882
1883 =item C<sha256>
1884
1885 Compute the SHA256 hash (using the C<sha256sum> program).
1886
1887 =item C<sha384>
1888
1889 Compute the SHA384 hash (using the C<sha384sum> program).
1890
1891 =item C<sha512>
1892
1893 Compute the SHA512 hash (using the C<sha512sum> program).
1894
1895 =back
1896
1897 The checksum is returned as a printable string.");
1898
1899   ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1900    [InitBasicFS, Always, TestOutput (
1901       [["tar_in"; "../images/helloworld.tar"; "/"];
1902        ["cat"; "/hello"]], "hello\n")],
1903    "unpack tarfile to directory",
1904    "\
1905 This command uploads and unpacks local file C<tarfile> (an
1906 I<uncompressed> tar file) into C<directory>.
1907
1908 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1909
1910   ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1911    [],
1912    "pack directory into tarfile",
1913    "\
1914 This command packs the contents of C<directory> and downloads
1915 it to local file C<tarfile>.
1916
1917 To download a compressed tarball, use C<guestfs_tgz_out>.");
1918
1919   ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1920    [InitBasicFS, Always, TestOutput (
1921       [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
1922        ["cat"; "/hello"]], "hello\n")],
1923    "unpack compressed tarball to directory",
1924    "\
1925 This command uploads and unpacks local file C<tarball> (a
1926 I<gzip compressed> tar file) into C<directory>.
1927
1928 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1929
1930   ("tgz_out", (RErr, [Pathname "directory"; FileOut "tarball"]), 72, [],
1931    [],
1932    "pack directory into compressed tarball",
1933    "\
1934 This command packs the contents of C<directory> and downloads
1935 it to local file C<tarball>.
1936
1937 To download an uncompressed tarball, use C<guestfs_tar_out>.");
1938
1939   ("mount_ro", (RErr, [Device "device"; String "mountpoint"]), 73, [],
1940    [InitBasicFS, Always, TestLastFail (
1941       [["umount"; "/"];
1942        ["mount_ro"; "/dev/sda1"; "/"];
1943        ["touch"; "/new"]]);
1944     InitBasicFS, Always, TestOutput (
1945       [["write_file"; "/new"; "data"; "0"];
1946        ["umount"; "/"];
1947        ["mount_ro"; "/dev/sda1"; "/"];
1948        ["cat"; "/new"]], "data")],
1949    "mount a guest disk, read-only",
1950    "\
1951 This is the same as the C<guestfs_mount> command, but it
1952 mounts the filesystem with the read-only (I<-o ro>) flag.");
1953
1954   ("mount_options", (RErr, [String "options"; Device "device"; String "mountpoint"]), 74, [],
1955    [],
1956    "mount a guest disk with mount options",
1957    "\
1958 This is the same as the C<guestfs_mount> command, but it
1959 allows you to set the mount options as for the
1960 L<mount(8)> I<-o> flag.");
1961
1962   ("mount_vfs", (RErr, [String "options"; String "vfstype"; Device "device"; String "mountpoint"]), 75, [],
1963    [],
1964    "mount a guest disk with mount options and vfstype",
1965    "\
1966 This is the same as the C<guestfs_mount> command, but it
1967 allows you to set both the mount options and the vfstype
1968 as for the L<mount(8)> I<-o> and I<-t> flags.");
1969
1970   ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
1971    [],
1972    "debugging and internals",
1973    "\
1974 The C<guestfs_debug> command exposes some internals of
1975 C<guestfsd> (the guestfs daemon) that runs inside the
1976 qemu subprocess.
1977
1978 There is no comprehensive help for this command.  You have
1979 to look at the file C<daemon/debug.c> in the libguestfs source
1980 to find out what you can do.");
1981
1982   ("lvremove", (RErr, [Device "device"]), 77, [],
1983    [InitEmpty, Always, TestOutputList (
1984       [["sfdiskM"; "/dev/sda"; ","];
1985        ["pvcreate"; "/dev/sda1"];
1986        ["vgcreate"; "VG"; "/dev/sda1"];
1987        ["lvcreate"; "LV1"; "VG"; "50"];
1988        ["lvcreate"; "LV2"; "VG"; "50"];
1989        ["lvremove"; "/dev/VG/LV1"];
1990        ["lvs"]], ["/dev/VG/LV2"]);
1991     InitEmpty, Always, TestOutputList (
1992       [["sfdiskM"; "/dev/sda"; ","];
1993        ["pvcreate"; "/dev/sda1"];
1994        ["vgcreate"; "VG"; "/dev/sda1"];
1995        ["lvcreate"; "LV1"; "VG"; "50"];
1996        ["lvcreate"; "LV2"; "VG"; "50"];
1997        ["lvremove"; "/dev/VG"];
1998        ["lvs"]], []);
1999     InitEmpty, Always, TestOutputList (
2000       [["sfdiskM"; "/dev/sda"; ","];
2001        ["pvcreate"; "/dev/sda1"];
2002        ["vgcreate"; "VG"; "/dev/sda1"];
2003        ["lvcreate"; "LV1"; "VG"; "50"];
2004        ["lvcreate"; "LV2"; "VG"; "50"];
2005        ["lvremove"; "/dev/VG"];
2006        ["vgs"]], ["VG"])],
2007    "remove an LVM logical volume",
2008    "\
2009 Remove an LVM logical volume C<device>, where C<device> is
2010 the path to the LV, such as C</dev/VG/LV>.
2011
2012 You can also remove all LVs in a volume group by specifying
2013 the VG name, C</dev/VG>.");
2014
2015   ("vgremove", (RErr, [String "vgname"]), 78, [],
2016    [InitEmpty, Always, TestOutputList (
2017       [["sfdiskM"; "/dev/sda"; ","];
2018        ["pvcreate"; "/dev/sda1"];
2019        ["vgcreate"; "VG"; "/dev/sda1"];
2020        ["lvcreate"; "LV1"; "VG"; "50"];
2021        ["lvcreate"; "LV2"; "VG"; "50"];
2022        ["vgremove"; "VG"];
2023        ["lvs"]], []);
2024     InitEmpty, Always, TestOutputList (
2025       [["sfdiskM"; "/dev/sda"; ","];
2026        ["pvcreate"; "/dev/sda1"];
2027        ["vgcreate"; "VG"; "/dev/sda1"];
2028        ["lvcreate"; "LV1"; "VG"; "50"];
2029        ["lvcreate"; "LV2"; "VG"; "50"];
2030        ["vgremove"; "VG"];
2031        ["vgs"]], [])],
2032    "remove an LVM volume group",
2033    "\
2034 Remove an LVM volume group C<vgname>, (for example C<VG>).
2035
2036 This also forcibly removes all logical volumes in the volume
2037 group (if any).");
2038
2039   ("pvremove", (RErr, [Device "device"]), 79, [],
2040    [InitEmpty, Always, TestOutputListOfDevices (
2041       [["sfdiskM"; "/dev/sda"; ","];
2042        ["pvcreate"; "/dev/sda1"];
2043        ["vgcreate"; "VG"; "/dev/sda1"];
2044        ["lvcreate"; "LV1"; "VG"; "50"];
2045        ["lvcreate"; "LV2"; "VG"; "50"];
2046        ["vgremove"; "VG"];
2047        ["pvremove"; "/dev/sda1"];
2048        ["lvs"]], []);
2049     InitEmpty, Always, TestOutputListOfDevices (
2050       [["sfdiskM"; "/dev/sda"; ","];
2051        ["pvcreate"; "/dev/sda1"];
2052        ["vgcreate"; "VG"; "/dev/sda1"];
2053        ["lvcreate"; "LV1"; "VG"; "50"];
2054        ["lvcreate"; "LV2"; "VG"; "50"];
2055        ["vgremove"; "VG"];
2056        ["pvremove"; "/dev/sda1"];
2057        ["vgs"]], []);
2058     InitEmpty, Always, TestOutputListOfDevices (
2059       [["sfdiskM"; "/dev/sda"; ","];
2060        ["pvcreate"; "/dev/sda1"];
2061        ["vgcreate"; "VG"; "/dev/sda1"];
2062        ["lvcreate"; "LV1"; "VG"; "50"];
2063        ["lvcreate"; "LV2"; "VG"; "50"];
2064        ["vgremove"; "VG"];
2065        ["pvremove"; "/dev/sda1"];
2066        ["pvs"]], [])],
2067    "remove an LVM physical volume",
2068    "\
2069 This wipes a physical volume C<device> so that LVM will no longer
2070 recognise it.
2071
2072 The implementation uses the C<pvremove> command which refuses to
2073 wipe physical volumes that contain any volume groups, so you have
2074 to remove those first.");
2075
2076   ("set_e2label", (RErr, [Device "device"; String "label"]), 80, [],
2077    [InitBasicFS, Always, TestOutput (
2078       [["set_e2label"; "/dev/sda1"; "testlabel"];
2079        ["get_e2label"; "/dev/sda1"]], "testlabel")],
2080    "set the ext2/3/4 filesystem label",
2081    "\
2082 This sets the ext2/3/4 filesystem label of the filesystem on
2083 C<device> to C<label>.  Filesystem labels are limited to
2084 16 characters.
2085
2086 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
2087 to return the existing label on a filesystem.");
2088
2089   ("get_e2label", (RString "label", [Device "device"]), 81, [],
2090    [],
2091    "get the ext2/3/4 filesystem label",
2092    "\
2093 This returns the ext2/3/4 filesystem label of the filesystem on
2094 C<device>.");
2095
2096   ("set_e2uuid", (RErr, [Device "device"; String "uuid"]), 82, [],
2097    (let uuid = uuidgen () in
2098     [InitBasicFS, Always, TestOutput (
2099        [["set_e2uuid"; "/dev/sda1"; uuid];
2100         ["get_e2uuid"; "/dev/sda1"]], uuid);
2101      InitBasicFS, Always, TestOutput (
2102        [["set_e2uuid"; "/dev/sda1"; "clear"];
2103         ["get_e2uuid"; "/dev/sda1"]], "");
2104      (* We can't predict what UUIDs will be, so just check the commands run. *)
2105      InitBasicFS, Always, TestRun (
2106        [["set_e2uuid"; "/dev/sda1"; "random"]]);
2107      InitBasicFS, Always, TestRun (
2108        [["set_e2uuid"; "/dev/sda1"; "time"]])]),
2109    "set the ext2/3/4 filesystem UUID",
2110    "\
2111 This sets the ext2/3/4 filesystem UUID of the filesystem on
2112 C<device> to C<uuid>.  The format of the UUID and alternatives
2113 such as C<clear>, C<random> and C<time> are described in the
2114 L<tune2fs(8)> manpage.
2115
2116 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
2117 to return the existing UUID of a filesystem.");
2118
2119   ("get_e2uuid", (RString "uuid", [Device "device"]), 83, [],
2120    [],
2121    "get the ext2/3/4 filesystem UUID",
2122    "\
2123 This returns the ext2/3/4 filesystem UUID of the filesystem on
2124 C<device>.");
2125
2126   ("fsck", (RInt "status", [String "fstype"; Device "device"]), 84, [],
2127    [InitBasicFS, Always, TestOutputInt (
2128       [["umount"; "/dev/sda1"];
2129        ["fsck"; "ext2"; "/dev/sda1"]], 0);
2130     InitBasicFS, Always, TestOutputInt (
2131       [["umount"; "/dev/sda1"];
2132        ["zero"; "/dev/sda1"];
2133        ["fsck"; "ext2"; "/dev/sda1"]], 8)],
2134    "run the filesystem checker",
2135    "\
2136 This runs the filesystem checker (fsck) on C<device> which
2137 should have filesystem type C<fstype>.
2138
2139 The returned integer is the status.  See L<fsck(8)> for the
2140 list of status codes from C<fsck>.
2141
2142 Notes:
2143
2144 =over 4
2145
2146 =item *
2147
2148 Multiple status codes can be summed together.
2149
2150 =item *
2151
2152 A non-zero return code can mean \"success\", for example if
2153 errors have been corrected on the filesystem.
2154
2155 =item *
2156
2157 Checking or repairing NTFS volumes is not supported
2158 (by linux-ntfs).
2159
2160 =back
2161
2162 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2163
2164   ("zero", (RErr, [Device "device"]), 85, [],
2165    [InitBasicFS, Always, TestOutput (
2166       [["umount"; "/dev/sda1"];
2167        ["zero"; "/dev/sda1"];
2168        ["file"; "/dev/sda1"]], "data")],
2169    "write zeroes to the device",
2170    "\
2171 This command writes zeroes over the first few blocks of C<device>.
2172
2173 How many blocks are zeroed isn't specified (but it's I<not> enough
2174 to securely wipe the device).  It should be sufficient to remove
2175 any partition tables, filesystem superblocks and so on.
2176
2177 See also: C<guestfs_scrub_device>.");
2178
2179   ("grub_install", (RErr, [Pathname "root"; Device "device"]), 86, [],
2180    (* Test disabled because grub-install incompatible with virtio-blk driver.
2181     * See also: https://bugzilla.redhat.com/show_bug.cgi?id=479760
2182     *)
2183    [InitBasicFS, Disabled, TestOutputTrue (
2184       [["grub_install"; "/"; "/dev/sda1"];
2185        ["is_dir"; "/boot"]])],
2186    "install GRUB",
2187    "\
2188 This command installs GRUB (the Grand Unified Bootloader) on
2189 C<device>, with the root directory being C<root>.");
2190
2191   ("cp", (RErr, [Pathname "src"; Pathname "dest"]), 87, [],
2192    [InitBasicFS, Always, TestOutput (
2193       [["write_file"; "/old"; "file content"; "0"];
2194        ["cp"; "/old"; "/new"];
2195        ["cat"; "/new"]], "file content");
2196     InitBasicFS, Always, TestOutputTrue (
2197       [["write_file"; "/old"; "file content"; "0"];
2198        ["cp"; "/old"; "/new"];
2199        ["is_file"; "/old"]]);
2200     InitBasicFS, Always, TestOutput (
2201       [["write_file"; "/old"; "file content"; "0"];
2202        ["mkdir"; "/dir"];
2203        ["cp"; "/old"; "/dir/new"];
2204        ["cat"; "/dir/new"]], "file content")],
2205    "copy a file",
2206    "\
2207 This copies a file from C<src> to C<dest> where C<dest> is
2208 either a destination filename or destination directory.");
2209
2210   ("cp_a", (RErr, [Pathname "src"; Pathname "dest"]), 88, [],
2211    [InitBasicFS, Always, TestOutput (
2212       [["mkdir"; "/olddir"];
2213        ["mkdir"; "/newdir"];
2214        ["write_file"; "/olddir/file"; "file content"; "0"];
2215        ["cp_a"; "/olddir"; "/newdir"];
2216        ["cat"; "/newdir/olddir/file"]], "file content")],
2217    "copy a file or directory recursively",
2218    "\
2219 This copies a file or directory from C<src> to C<dest>
2220 recursively using the C<cp -a> command.");
2221
2222   ("mv", (RErr, [Pathname "src"; Pathname "dest"]), 89, [],
2223    [InitBasicFS, Always, TestOutput (
2224       [["write_file"; "/old"; "file content"; "0"];
2225        ["mv"; "/old"; "/new"];
2226        ["cat"; "/new"]], "file content");
2227     InitBasicFS, Always, TestOutputFalse (
2228       [["write_file"; "/old"; "file content"; "0"];
2229        ["mv"; "/old"; "/new"];
2230        ["is_file"; "/old"]])],
2231    "move a file",
2232    "\
2233 This moves a file from C<src> to C<dest> where C<dest> is
2234 either a destination filename or destination directory.");
2235
2236   ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2237    [InitEmpty, Always, TestRun (
2238       [["drop_caches"; "3"]])],
2239    "drop kernel page cache, dentries and inodes",
2240    "\
2241 This instructs the guest kernel to drop its page cache,
2242 and/or dentries and inode caches.  The parameter C<whattodrop>
2243 tells the kernel what precisely to drop, see
2244 L<http://linux-mm.org/Drop_Caches>
2245
2246 Setting C<whattodrop> to 3 should drop everything.
2247
2248 This automatically calls L<sync(2)> before the operation,
2249 so that the maximum guest memory is freed.");
2250
2251   ("dmesg", (RString "kmsgs", []), 91, [],
2252    [InitEmpty, Always, TestRun (
2253       [["dmesg"]])],
2254    "return kernel messages",
2255    "\
2256 This returns the kernel messages (C<dmesg> output) from
2257 the guest kernel.  This is sometimes useful for extended
2258 debugging of problems.
2259
2260 Another way to get the same information is to enable
2261 verbose messages with C<guestfs_set_verbose> or by setting
2262 the environment variable C<LIBGUESTFS_DEBUG=1> before
2263 running the program.");
2264
2265   ("ping_daemon", (RErr, []), 92, [],
2266    [InitEmpty, Always, TestRun (
2267       [["ping_daemon"]])],
2268    "ping the guest daemon",
2269    "\
2270 This is a test probe into the guestfs daemon running inside
2271 the qemu subprocess.  Calling this function checks that the
2272 daemon responds to the ping message, without affecting the daemon
2273 or attached block device(s) in any other way.");
2274
2275   ("equal", (RBool "equality", [Pathname "file1"; Pathname "file2"]), 93, [],
2276    [InitBasicFS, Always, TestOutputTrue (
2277       [["write_file"; "/file1"; "contents of a file"; "0"];
2278        ["cp"; "/file1"; "/file2"];
2279        ["equal"; "/file1"; "/file2"]]);
2280     InitBasicFS, Always, TestOutputFalse (
2281       [["write_file"; "/file1"; "contents of a file"; "0"];
2282        ["write_file"; "/file2"; "contents of another file"; "0"];
2283        ["equal"; "/file1"; "/file2"]]);
2284     InitBasicFS, Always, TestLastFail (
2285       [["equal"; "/file1"; "/file2"]])],
2286    "test if two files have equal contents",
2287    "\
2288 This compares the two files C<file1> and C<file2> and returns
2289 true if their content is exactly equal, or false otherwise.
2290
2291 The external L<cmp(1)> program is used for the comparison.");
2292
2293   ("strings", (RStringList "stringsout", [Pathname "path"]), 94, [ProtocolLimitWarning],
2294    [InitISOFS, Always, TestOutputList (
2295       [["strings"; "/known-5"]], ["abcdefghi"; "jklmnopqr"]);
2296     InitISOFS, Always, TestOutputList (
2297       [["strings"; "/empty"]], [])],
2298    "print the printable strings in a file",
2299    "\
2300 This runs the L<strings(1)> command on a file and returns
2301 the list of printable strings found.");
2302
2303   ("strings_e", (RStringList "stringsout", [String "encoding"; Pathname "path"]), 95, [ProtocolLimitWarning],
2304    [InitISOFS, Always, TestOutputList (
2305       [["strings_e"; "b"; "/known-5"]], []);
2306     InitBasicFS, Disabled, TestOutputList (
2307       [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2308        ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2309    "print the printable strings in a file",
2310    "\
2311 This is like the C<guestfs_strings> command, but allows you to
2312 specify the encoding.
2313
2314 See the L<strings(1)> manpage for the full list of encodings.
2315
2316 Commonly useful encodings are C<l> (lower case L) which will
2317 show strings inside Windows/x86 files.
2318
2319 The returned strings are transcoded to UTF-8.");
2320
2321   ("hexdump", (RString "dump", [Pathname "path"]), 96, [ProtocolLimitWarning],
2322    [InitISOFS, Always, TestOutput (
2323       [["hexdump"; "/known-4"]], "00000000  61 62 63 0a 64 65 66 0a  67 68 69                 |abc.def.ghi|\n0000000b\n");
2324     (* Test for RHBZ#501888c2 regression which caused large hexdump
2325      * commands to segfault.
2326      *)
2327     InitISOFS, Always, TestRun (
2328       [["hexdump"; "/100krandom"]])],
2329    "dump a file in hexadecimal",
2330    "\
2331 This runs C<hexdump -C> on the given C<path>.  The result is
2332 the human-readable, canonical hex dump of the file.");
2333
2334   ("zerofree", (RErr, [Device "device"]), 97, [],
2335    [InitNone, Always, TestOutput (
2336       [["sfdiskM"; "/dev/sda"; ","];
2337        ["mkfs"; "ext3"; "/dev/sda1"];
2338        ["mount"; "/dev/sda1"; "/"];
2339        ["write_file"; "/new"; "test file"; "0"];
2340        ["umount"; "/dev/sda1"];
2341        ["zerofree"; "/dev/sda1"];
2342        ["mount"; "/dev/sda1"; "/"];
2343        ["cat"; "/new"]], "test file")],
2344    "zero unused inodes and disk blocks on ext2/3 filesystem",
2345    "\
2346 This runs the I<zerofree> program on C<device>.  This program
2347 claims to zero unused inodes and disk blocks on an ext2/3
2348 filesystem, thus making it possible to compress the filesystem
2349 more effectively.
2350
2351 You should B<not> run this program if the filesystem is
2352 mounted.
2353
2354 It is possible that using this program can damage the filesystem
2355 or data on the filesystem.");
2356
2357   ("pvresize", (RErr, [Device "device"]), 98, [],
2358    [],
2359    "resize an LVM physical volume",
2360    "\
2361 This resizes (expands or shrinks) an existing LVM physical
2362 volume to match the new size of the underlying device.");
2363
2364   ("sfdisk_N", (RErr, [Device "device"; Int "partnum";
2365                        Int "cyls"; Int "heads"; Int "sectors";
2366                        String "line"]), 99, [DangerWillRobinson],
2367    [],
2368    "modify a single partition on a block device",
2369    "\
2370 This runs L<sfdisk(8)> option to modify just the single
2371 partition C<n> (note: C<n> counts from 1).
2372
2373 For other parameters, see C<guestfs_sfdisk>.  You should usually
2374 pass C<0> for the cyls/heads/sectors parameters.");
2375
2376   ("sfdisk_l", (RString "partitions", [Device "device"]), 100, [],
2377    [],
2378    "display the partition table",
2379    "\
2380 This displays the partition table on C<device>, in the
2381 human-readable output of the L<sfdisk(8)> command.  It is
2382 not intended to be parsed.");
2383
2384   ("sfdisk_kernel_geometry", (RString "partitions", [Device "device"]), 101, [],
2385    [],
2386    "display the kernel geometry",
2387    "\
2388 This displays the kernel's idea of the geometry of C<device>.
2389
2390 The result is in human-readable format, and not designed to
2391 be parsed.");
2392
2393   ("sfdisk_disk_geometry", (RString "partitions", [Device "device"]), 102, [],
2394    [],
2395    "display the disk geometry from the partition table",
2396    "\
2397 This displays the disk geometry of C<device> read from the
2398 partition table.  Especially in the case where the underlying
2399 block device has been resized, this can be different from the
2400 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2401
2402 The result is in human-readable format, and not designed to
2403 be parsed.");
2404
2405   ("vg_activate_all", (RErr, [Bool "activate"]), 103, [],
2406    [],
2407    "activate or deactivate all volume groups",
2408    "\
2409 This command activates or (if C<activate> is false) deactivates
2410 all logical volumes in all volume groups.
2411 If activated, then they are made known to the
2412 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2413 then those devices disappear.
2414
2415 This command is the same as running C<vgchange -a y|n>");
2416
2417   ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [],
2418    [],
2419    "activate or deactivate some volume groups",
2420    "\
2421 This command activates or (if C<activate> is false) deactivates
2422 all logical volumes in the listed volume groups C<volgroups>.
2423 If activated, then they are made known to the
2424 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2425 then those devices disappear.
2426
2427 This command is the same as running C<vgchange -a y|n volgroups...>
2428
2429 Note that if C<volgroups> is an empty list then B<all> volume groups
2430 are activated or deactivated.");
2431
2432   ("lvresize", (RErr, [Device "device"; Int "mbytes"]), 105, [],
2433    [InitNone, Always, TestOutput (
2434       [["sfdiskM"; "/dev/sda"; ","];
2435        ["pvcreate"; "/dev/sda1"];
2436        ["vgcreate"; "VG"; "/dev/sda1"];
2437        ["lvcreate"; "LV"; "VG"; "10"];
2438        ["mkfs"; "ext2"; "/dev/VG/LV"];
2439        ["mount"; "/dev/VG/LV"; "/"];
2440        ["write_file"; "/new"; "test content"; "0"];
2441        ["umount"; "/"];
2442        ["lvresize"; "/dev/VG/LV"; "20"];
2443        ["e2fsck_f"; "/dev/VG/LV"];
2444        ["resize2fs"; "/dev/VG/LV"];
2445        ["mount"; "/dev/VG/LV"; "/"];
2446        ["cat"; "/new"]], "test content")],
2447    "resize an LVM logical volume",
2448    "\
2449 This resizes (expands or shrinks) an existing LVM logical
2450 volume to C<mbytes>.  When reducing, data in the reduced part
2451 is lost.");
2452
2453   ("resize2fs", (RErr, [Device "device"]), 106, [],
2454    [], (* lvresize tests this *)
2455    "resize an ext2/ext3 filesystem",
2456    "\
2457 This resizes an ext2 or ext3 filesystem to match the size of
2458 the underlying device.
2459
2460 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2461 on the C<device> before calling this command.  For unknown reasons
2462 C<resize2fs> sometimes gives an error about this and sometimes not.
2463 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2464 calling this function.");
2465
2466   ("find", (RStringList "names", [Pathname "directory"]), 107, [],
2467    [InitBasicFS, Always, TestOutputList (
2468       [["find"; "/"]], ["lost+found"]);
2469     InitBasicFS, Always, TestOutputList (
2470       [["touch"; "/a"];
2471        ["mkdir"; "/b"];
2472        ["touch"; "/b/c"];
2473        ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2474     InitBasicFS, Always, TestOutputList (
2475       [["mkdir_p"; "/a/b/c"];
2476        ["touch"; "/a/b/c/d"];
2477        ["find"; "/a/b/"]], ["c"; "c/d"])],
2478    "find all files and directories",
2479    "\
2480 This command lists out all files and directories, recursively,
2481 starting at C<directory>.  It is essentially equivalent to
2482 running the shell command C<find directory -print> but some
2483 post-processing happens on the output, described below.
2484
2485 This returns a list of strings I<without any prefix>.  Thus
2486 if the directory structure was:
2487
2488  /tmp/a
2489  /tmp/b
2490  /tmp/c/d
2491
2492 then the returned list from C<guestfs_find> C</tmp> would be
2493 4 elements:
2494
2495  a
2496  b
2497  c
2498  c/d
2499
2500 If C<directory> is not a directory, then this command returns
2501 an error.
2502
2503 The returned list is sorted.");
2504
2505   ("e2fsck_f", (RErr, [Device "device"]), 108, [],
2506    [], (* lvresize tests this *)
2507    "check an ext2/ext3 filesystem",
2508    "\
2509 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2510 filesystem checker on C<device>, noninteractively (C<-p>),
2511 even if the filesystem appears to be clean (C<-f>).
2512
2513 This command is only needed because of C<guestfs_resize2fs>
2514 (q.v.).  Normally you should use C<guestfs_fsck>.");
2515
2516   ("sleep", (RErr, [Int "secs"]), 109, [],
2517    [InitNone, Always, TestRun (
2518       [["sleep"; "1"]])],
2519    "sleep for some seconds",
2520    "\
2521 Sleep for C<secs> seconds.");
2522
2523   ("ntfs_3g_probe", (RInt "status", [Bool "rw"; Device "device"]), 110, [],
2524    [InitNone, Always, TestOutputInt (
2525       [["sfdiskM"; "/dev/sda"; ","];
2526        ["mkfs"; "ntfs"; "/dev/sda1"];
2527        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2528     InitNone, Always, TestOutputInt (
2529       [["sfdiskM"; "/dev/sda"; ","];
2530        ["mkfs"; "ext2"; "/dev/sda1"];
2531        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2532    "probe NTFS volume",
2533    "\
2534 This command runs the L<ntfs-3g.probe(8)> command which probes
2535 an NTFS C<device> for mountability.  (Not all NTFS volumes can
2536 be mounted read-write, and some cannot be mounted at all).
2537
2538 C<rw> is a boolean flag.  Set it to true if you want to test
2539 if the volume can be mounted read-write.  Set it to false if
2540 you want to test if the volume can be mounted read-only.
2541
2542 The return value is an integer which C<0> if the operation
2543 would succeed, or some non-zero value documented in the
2544 L<ntfs-3g.probe(8)> manual page.");
2545
2546   ("sh", (RString "output", [String "command"]), 111, [],
2547    [], (* XXX needs tests *)
2548    "run a command via the shell",
2549    "\
2550 This call runs a command from the guest filesystem via the
2551 guest's C</bin/sh>.
2552
2553 This is like C<guestfs_command>, but passes the command to:
2554
2555  /bin/sh -c \"command\"
2556
2557 Depending on the guest's shell, this usually results in
2558 wildcards being expanded, shell expressions being interpolated
2559 and so on.
2560
2561 All the provisos about C<guestfs_command> apply to this call.");
2562
2563   ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2564    [], (* XXX needs tests *)
2565    "run a command via the shell returning lines",
2566    "\
2567 This is the same as C<guestfs_sh>, but splits the result
2568 into a list of lines.
2569
2570 See also: C<guestfs_command_lines>");
2571
2572   ("glob_expand", (RStringList "paths", [Pathname "pattern"]), 113, [],
2573    (* Use Pathname here, and hence ABS_PATH (pattern,... in generated
2574     * code in stubs.c, since all valid glob patterns must start with "/".
2575     * There is no concept of "cwd" in libguestfs, hence no "."-relative names.
2576     *)
2577    [InitBasicFS, Always, TestOutputList (
2578       [["mkdir_p"; "/a/b/c"];
2579        ["touch"; "/a/b/c/d"];
2580        ["touch"; "/a/b/c/e"];
2581        ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2582     InitBasicFS, Always, TestOutputList (
2583       [["mkdir_p"; "/a/b/c"];
2584        ["touch"; "/a/b/c/d"];
2585        ["touch"; "/a/b/c/e"];
2586        ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2587     InitBasicFS, Always, TestOutputList (
2588       [["mkdir_p"; "/a/b/c"];
2589        ["touch"; "/a/b/c/d"];
2590        ["touch"; "/a/b/c/e"];
2591        ["glob_expand"; "/a/*/x/*"]], [])],
2592    "expand a wildcard path",
2593    "\
2594 This command searches for all the pathnames matching
2595 C<pattern> according to the wildcard expansion rules
2596 used by the shell.
2597
2598 If no paths match, then this returns an empty list
2599 (note: not an error).
2600
2601 It is just a wrapper around the C L<glob(3)> function
2602 with flags C<GLOB_MARK|GLOB_BRACE>.
2603 See that manual page for more details.");
2604
2605   ("scrub_device", (RErr, [Device "device"]), 114, [DangerWillRobinson],
2606    [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2607       [["scrub_device"; "/dev/sdc"]])],
2608    "scrub (securely wipe) a device",
2609    "\
2610 This command writes patterns over C<device> to make data retrieval
2611 more difficult.
2612
2613 It is an interface to the L<scrub(1)> program.  See that
2614 manual page for more details.");
2615
2616   ("scrub_file", (RErr, [Pathname "file"]), 115, [],
2617    [InitBasicFS, Always, TestRun (
2618       [["write_file"; "/file"; "content"; "0"];
2619        ["scrub_file"; "/file"]])],
2620    "scrub (securely wipe) a file",
2621    "\
2622 This command writes patterns over a file to make data retrieval
2623 more difficult.
2624
2625 The file is I<removed> after scrubbing.
2626
2627 It is an interface to the L<scrub(1)> program.  See that
2628 manual page for more details.");
2629
2630   ("scrub_freespace", (RErr, [Pathname "dir"]), 116, [],
2631    [], (* XXX needs testing *)
2632    "scrub (securely wipe) free space",
2633    "\
2634 This command creates the directory C<dir> and then fills it
2635 with files until the filesystem is full, and scrubs the files
2636 as for C<guestfs_scrub_file>, and deletes them.
2637 The intention is to scrub any free space on the partition
2638 containing C<dir>.
2639
2640 It is an interface to the L<scrub(1)> program.  See that
2641 manual page for more details.");
2642
2643   ("mkdtemp", (RString "dir", [Pathname "template"]), 117, [],
2644    [InitBasicFS, Always, TestRun (
2645       [["mkdir"; "/tmp"];
2646        ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2647    "create a temporary directory",
2648    "\
2649 This command creates a temporary directory.  The
2650 C<template> parameter should be a full pathname for the
2651 temporary directory name with the final six characters being
2652 \"XXXXXX\".
2653
2654 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2655 the second one being suitable for Windows filesystems.
2656
2657 The name of the temporary directory that was created
2658 is returned.
2659
2660 The temporary directory is created with mode 0700
2661 and is owned by root.
2662
2663 The caller is responsible for deleting the temporary
2664 directory and its contents after use.
2665
2666 See also: L<mkdtemp(3)>");
2667
2668   ("wc_l", (RInt "lines", [Pathname "path"]), 118, [],
2669    [InitISOFS, Always, TestOutputInt (
2670       [["wc_l"; "/10klines"]], 10000)],
2671    "count lines in a file",
2672    "\
2673 This command counts the lines in a file, using the
2674 C<wc -l> external command.");
2675
2676   ("wc_w", (RInt "words", [Pathname "path"]), 119, [],
2677    [InitISOFS, Always, TestOutputInt (
2678       [["wc_w"; "/10klines"]], 10000)],
2679    "count words in a file",
2680    "\
2681 This command counts the words in a file, using the
2682 C<wc -w> external command.");
2683
2684   ("wc_c", (RInt "chars", [Pathname "path"]), 120, [],
2685    [InitISOFS, Always, TestOutputInt (
2686       [["wc_c"; "/100kallspaces"]], 102400)],
2687    "count characters in a file",
2688    "\
2689 This command counts the characters in a file, using the
2690 C<wc -c> external command.");
2691
2692   ("head", (RStringList "lines", [Pathname "path"]), 121, [ProtocolLimitWarning],
2693    [InitISOFS, Always, TestOutputList (
2694       [["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2695    "return first 10 lines of a file",
2696    "\
2697 This command returns up to the first 10 lines of a file as
2698 a list of strings.");
2699
2700   ("head_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 122, [ProtocolLimitWarning],
2701    [InitISOFS, Always, TestOutputList (
2702       [["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2703     InitISOFS, Always, TestOutputList (
2704       [["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2705     InitISOFS, Always, TestOutputList (
2706       [["head_n"; "0"; "/10klines"]], [])],
2707    "return first N lines of a file",
2708    "\
2709 If the parameter C<nrlines> is a positive number, this returns the first
2710 C<nrlines> lines of the file C<path>.
2711
2712 If the parameter C<nrlines> is a negative number, this returns lines
2713 from the file C<path>, excluding the last C<nrlines> lines.
2714
2715 If the parameter C<nrlines> is zero, this returns an empty list.");
2716
2717   ("tail", (RStringList "lines", [Pathname "path"]), 123, [ProtocolLimitWarning],
2718    [InitISOFS, Always, TestOutputList (
2719       [["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2720    "return last 10 lines of a file",
2721    "\
2722 This command returns up to the last 10 lines of a file as
2723 a list of strings.");
2724
2725   ("tail_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 124, [ProtocolLimitWarning],
2726    [InitISOFS, Always, TestOutputList (
2727       [["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2728     InitISOFS, Always, TestOutputList (
2729       [["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2730     InitISOFS, Always, TestOutputList (
2731       [["tail_n"; "0"; "/10klines"]], [])],
2732    "return last N lines of a file",
2733    "\
2734 If the parameter C<nrlines> is a positive number, this returns the last
2735 C<nrlines> lines of the file C<path>.
2736
2737 If the parameter C<nrlines> is a negative number, this returns lines
2738 from the file C<path>, starting with the C<-nrlines>th line.
2739
2740 If the parameter C<nrlines> is zero, this returns an empty list.");
2741
2742   ("df", (RString "output", []), 125, [],
2743    [], (* XXX Tricky to test because it depends on the exact format
2744         * of the 'df' command and other imponderables.
2745         *)
2746    "report file system disk space usage",
2747    "\
2748 This command runs the C<df> command to report disk space used.
2749
2750 This command is mostly useful for interactive sessions.  It
2751 is I<not> intended that you try to parse the output string.
2752 Use C<statvfs> from programs.");
2753
2754   ("df_h", (RString "output", []), 126, [],
2755    [], (* XXX Tricky to test because it depends on the exact format
2756         * of the 'df' command and other imponderables.
2757         *)
2758    "report file system disk space usage (human readable)",
2759    "\
2760 This command runs the C<df -h> command to report disk space used
2761 in human-readable format.
2762
2763 This command is mostly useful for interactive sessions.  It
2764 is I<not> intended that you try to parse the output string.
2765 Use C<statvfs> from programs.");
2766
2767   ("du", (RInt64 "sizekb", [Pathname "path"]), 127, [],
2768    [InitISOFS, Always, TestOutputInt (
2769       [["du"; "/directory"]], 2 (* ISO fs blocksize is 2K *))],
2770    "estimate file space usage",
2771    "\
2772 This command runs the C<du -s> command to estimate file space
2773 usage for C<path>.
2774
2775 C<path> can be a file or a directory.  If C<path> is a directory
2776 then the estimate includes the contents of the directory and all
2777 subdirectories (recursively).
2778
2779 The result is the estimated size in I<kilobytes>
2780 (ie. units of 1024 bytes).");
2781
2782   ("initrd_list", (RStringList "filenames", [Pathname "path"]), 128, [],
2783    [InitISOFS, Always, TestOutputList (
2784       [["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3";"known-4"; "known-5"])],
2785    "list files in an initrd",
2786    "\
2787 This command lists out files contained in an initrd.
2788
2789 The files are listed without any initial C</> character.  The
2790 files are listed in the order they appear (not necessarily
2791 alphabetical).  Directory names are listed as separate items.
2792
2793 Old Linux kernels (2.4 and earlier) used a compressed ext2
2794 filesystem as initrd.  We I<only> support the newer initramfs
2795 format (compressed cpio files).");
2796
2797   ("mount_loop", (RErr, [Pathname "file"; Pathname "mountpoint"]), 129, [],
2798    [],
2799    "mount a file using the loop device",
2800    "\
2801 This command lets you mount C<file> (a filesystem image
2802 in a file) on a mount point.  It is entirely equivalent to
2803 the command C<mount -o loop file mountpoint>.");
2804
2805   ("mkswap", (RErr, [Device "device"]), 130, [],
2806    [InitEmpty, Always, TestRun (
2807       [["sfdiskM"; "/dev/sda"; ","];
2808        ["mkswap"; "/dev/sda1"]])],
2809    "create a swap partition",
2810    "\
2811 Create a swap partition on C<device>.");
2812
2813   ("mkswap_L", (RErr, [String "label"; Device "device"]), 131, [],
2814    [InitEmpty, Always, TestRun (
2815       [["sfdiskM"; "/dev/sda"; ","];
2816        ["mkswap_L"; "hello"; "/dev/sda1"]])],
2817    "create a swap partition with a label",
2818    "\
2819 Create a swap partition on C<device> with label C<label>.
2820
2821 Note that you cannot attach a swap label to a block device
2822 (eg. C</dev/sda>), just to a partition.  This appears to be
2823 a limitation of the kernel or swap tools.");
2824
2825   ("mkswap_U", (RErr, [String "uuid"; Device "device"]), 132, [],
2826    (let uuid = uuidgen () in
2827     [InitEmpty, Always, TestRun (
2828        [["sfdiskM"; "/dev/sda"; ","];
2829         ["mkswap_U"; uuid; "/dev/sda1"]])]),
2830    "create a swap partition with an explicit UUID",
2831    "\
2832 Create a swap partition on C<device> with UUID C<uuid>.");
2833
2834   ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 133, [],
2835    [InitBasicFS, Always, TestOutputStruct (
2836       [["mknod"; "0o10777"; "0"; "0"; "/node"];
2837        (* NB: default umask 022 means 0777 -> 0755 in these tests *)
2838        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
2839     InitBasicFS, Always, TestOutputStruct (
2840       [["mknod"; "0o60777"; "66"; "99"; "/node"];
2841        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2842    "make block, character or FIFO devices",
2843    "\
2844 This call creates block or character special devices, or
2845 named pipes (FIFOs).
2846
2847 The C<mode> parameter should be the mode, using the standard
2848 constants.  C<devmajor> and C<devminor> are the
2849 device major and minor numbers, only used when creating block
2850 and character special devices.");
2851
2852   ("mkfifo", (RErr, [Int "mode"; Pathname "path"]), 134, [],
2853    [InitBasicFS, Always, TestOutputStruct (
2854       [["mkfifo"; "0o777"; "/node"];
2855        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
2856    "make FIFO (named pipe)",
2857    "\
2858 This call creates a FIFO (named pipe) called C<path> with
2859 mode C<mode>.  It is just a convenient wrapper around
2860 C<guestfs_mknod>.");
2861
2862   ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 135, [],
2863    [InitBasicFS, Always, TestOutputStruct (
2864       [["mknod_b"; "0o777"; "99"; "66"; "/node"];
2865        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2866    "make block device node",
2867    "\
2868 This call creates a block device node called C<path> with
2869 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2870 It is just a convenient wrapper around C<guestfs_mknod>.");
2871
2872   ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 136, [],
2873    [InitBasicFS, Always, TestOutputStruct (
2874       [["mknod_c"; "0o777"; "99"; "66"; "/node"];
2875        ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
2876    "make char device node",
2877    "\
2878 This call creates a char device node called C<path> with
2879 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2880 It is just a convenient wrapper around C<guestfs_mknod>.");
2881
2882   ("umask", (RInt "oldmask", [Int "mask"]), 137, [],
2883    [], (* XXX umask is one of those stateful things that we should
2884         * reset between each test.
2885         *)
2886    "set file mode creation mask (umask)",
2887    "\
2888 This function sets the mask used for creating new files and
2889 device nodes to C<mask & 0777>.
2890
2891 Typical umask values would be C<022> which creates new files
2892 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
2893 C<002> which creates new files with permissions like
2894 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
2895
2896 The default umask is C<022>.  This is important because it
2897 means that directories and device nodes will be created with
2898 C<0644> or C<0755> mode even if you specify C<0777>.
2899
2900 See also L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
2901
2902 This call returns the previous umask.");
2903
2904   ("readdir", (RStructList ("entries", "dirent"), [Pathname "dir"]), 138, [],
2905    [],
2906    "read directories entries",
2907    "\
2908 This returns the list of directory entries in directory C<dir>.
2909
2910 All entries in the directory are returned, including C<.> and
2911 C<..>.  The entries are I<not> sorted, but returned in the same
2912 order as the underlying filesystem.
2913
2914 Also this call returns basic file type information about each
2915 file.  The C<ftyp> field will contain one of the following characters:
2916
2917 =over 4
2918
2919 =item 'b'
2920
2921 Block special
2922
2923 =item 'c'
2924
2925 Char special
2926
2927 =item 'd'
2928
2929 Directory
2930
2931 =item 'f'
2932
2933 FIFO (named pipe)
2934
2935 =item 'l'
2936
2937 Symbolic link
2938
2939 =item 'r'
2940
2941 Regular file
2942
2943 =item 's'
2944
2945 Socket
2946
2947 =item 'u'
2948
2949 Unknown file type
2950
2951 =item '?'
2952
2953 The L<readdir(3)> returned a C<d_type> field with an
2954 unexpected value
2955
2956 =back
2957
2958 This function is primarily intended for use by programs.  To
2959 get a simple list of names, use C<guestfs_ls>.  To get a printable
2960 directory for human consumption, use C<guestfs_ll>.");
2961
2962   ("sfdiskM", (RErr, [Device "device"; StringList "lines"]), 139, [DangerWillRobinson],
2963    [],
2964    "create partitions on a block device",
2965    "\
2966 This is a simplified interface to the C<guestfs_sfdisk>
2967 command, where partition sizes are specified in megabytes
2968 only (rounded to the nearest cylinder) and you don't need
2969 to specify the cyls, heads and sectors parameters which
2970 were rarely if ever used anyway.
2971
2972 See also C<guestfs_sfdisk> and the L<sfdisk(8)> manpage.");
2973
2974   ("zfile", (RString "description", [String "meth"; Pathname "path"]), 140, [DeprecatedBy "file"],
2975    [],
2976    "determine file type inside a compressed file",
2977    "\
2978 This command runs C<file> after first decompressing C<path>
2979 using C<method>.
2980
2981 C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
2982
2983 Since 1.0.63, use C<guestfs_file> instead which can now
2984 process compressed files.");
2985
2986   ("getxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 141, [],
2987    [],
2988    "list extended attributes of a file or directory",
2989    "\
2990 This call lists the extended attributes of the file or directory
2991 C<path>.
2992
2993 At the system call level, this is a combination of the
2994 L<listxattr(2)> and L<getxattr(2)> calls.
2995
2996 See also: C<guestfs_lgetxattrs>, L<attr(5)>.");
2997
2998   ("lgetxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 142, [],
2999    [],
3000    "list extended attributes of a file or directory",
3001    "\
3002 This is the same as C<guestfs_getxattrs>, but if C<path>
3003 is a symbolic link, then it returns the extended attributes
3004 of the link itself.");
3005
3006   ("setxattr", (RErr, [String "xattr";
3007                        String "val"; Int "vallen"; (* will be BufferIn *)
3008                        Pathname "path"]), 143, [],
3009    [],
3010    "set extended attribute of a file or directory",
3011    "\
3012 This call sets the extended attribute named C<xattr>
3013 of the file C<path> to the value C<val> (of length C<vallen>).
3014 The value is arbitrary 8 bit data.
3015
3016 See also: C<guestfs_lsetxattr>, L<attr(5)>.");
3017
3018   ("lsetxattr", (RErr, [String "xattr";
3019                         String "val"; Int "vallen"; (* will be BufferIn *)
3020                         Pathname "path"]), 144, [],
3021    [],
3022    "set extended attribute of a file or directory",
3023    "\
3024 This is the same as C<guestfs_setxattr>, but if C<path>
3025 is a symbolic link, then it sets an extended attribute
3026 of the link itself.");
3027
3028   ("removexattr", (RErr, [String "xattr"; Pathname "path"]), 145, [],
3029    [],
3030    "remove extended attribute of a file or directory",
3031    "\
3032 This call removes the extended attribute named C<xattr>
3033 of the file C<path>.
3034
3035 See also: C<guestfs_lremovexattr>, L<attr(5)>.");
3036
3037   ("lremovexattr", (RErr, [String "xattr"; Pathname "path"]), 146, [],
3038    [],
3039    "remove extended attribute of a file or directory",
3040    "\
3041 This is the same as C<guestfs_removexattr>, but if C<path>
3042 is a symbolic link, then it removes an extended attribute
3043 of the link itself.");
3044
3045   ("mountpoints", (RHashtable "mps", []), 147, [],
3046    [],
3047    "show mountpoints",
3048    "\
3049 This call is similar to C<guestfs_mounts>.  That call returns
3050 a list of devices.  This one returns a hash table (map) of
3051 device name to directory where the device is mounted.");
3052
3053   ("mkmountpoint", (RErr, [String "exemptpath"]), 148, [],
3054   (* This is a special case: while you would expect a parameter
3055    * of type "Pathname", that doesn't work, because it implies
3056    * NEED_ROOT in the generated calling code in stubs.c, and
3057    * this function cannot use NEED_ROOT.
3058    *)
3059    [],
3060    "create a mountpoint",
3061    "\
3062 C<guestfs_mkmountpoint> and C<guestfs_rmmountpoint> are
3063 specialized calls that can be used to create extra mountpoints
3064 before mounting the first filesystem.
3065
3066 These calls are I<only> necessary in some very limited circumstances,
3067 mainly the case where you want to mount a mix of unrelated and/or
3068 read-only filesystems together.
3069
3070 For example, live CDs often contain a \"Russian doll\" nest of
3071 filesystems, an ISO outer layer, with a squashfs image inside, with
3072 an ext2/3 image inside that.  You can unpack this as follows
3073 in guestfish:
3074
3075  add-ro Fedora-11-i686-Live.iso
3076  run
3077  mkmountpoint /cd
3078  mkmountpoint /squash
3079  mkmountpoint /ext3
3080  mount /dev/sda /cd
3081  mount-loop /cd/LiveOS/squashfs.img /squash
3082  mount-loop /squash/LiveOS/ext3fs.img /ext3
3083
3084 The inner filesystem is now unpacked under the /ext3 mountpoint.");
3085
3086   ("rmmountpoint", (RErr, [String "exemptpath"]), 149, [],
3087    [],
3088    "remove a mountpoint",
3089    "\
3090 This calls removes a mountpoint that was previously created
3091 with C<guestfs_mkmountpoint>.  See C<guestfs_mkmountpoint>
3092 for full details.");
3093
3094   ("read_file", (RBufferOut "content", [Pathname "path"]), 150, [ProtocolLimitWarning],
3095    [InitISOFS, Always, TestOutputBuffer (
3096       [["read_file"; "/known-4"]], "abc\ndef\nghi")],
3097    "read a file",
3098    "\
3099 This calls returns the contents of the file C<path> as a
3100 buffer.
3101
3102 Unlike C<guestfs_cat>, this function can correctly
3103 handle files that contain embedded ASCII NUL characters.
3104 However unlike C<guestfs_download>, this function is limited
3105 in the total size of file that can be handled.");
3106
3107   ("grep", (RStringList "lines", [String "regex"; Pathname "path"]), 151, [ProtocolLimitWarning],
3108    [InitISOFS, Always, TestOutputList (
3109       [["grep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"]);
3110     InitISOFS, Always, TestOutputList (
3111       [["grep"; "nomatch"; "/test-grep.txt"]], [])],
3112    "return lines matching a pattern",
3113    "\
3114 This calls the external C<grep> program and returns the
3115 matching lines.");
3116
3117   ("egrep", (RStringList "lines", [String "regex"; Pathname "path"]), 152, [ProtocolLimitWarning],
3118    [InitISOFS, Always, TestOutputList (
3119       [["egrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3120    "return lines matching a pattern",
3121    "\
3122 This calls the external C<egrep> program and returns the
3123 matching lines.");
3124
3125   ("fgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 153, [ProtocolLimitWarning],
3126    [InitISOFS, Always, TestOutputList (
3127       [["fgrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3128    "return lines matching a pattern",
3129    "\
3130 This calls the external C<fgrep> program and returns the
3131 matching lines.");
3132
3133   ("grepi", (RStringList "lines", [String "regex"; Pathname "path"]), 154, [ProtocolLimitWarning],
3134    [InitISOFS, Always, TestOutputList (
3135       [["grepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3136    "return lines matching a pattern",
3137    "\
3138 This calls the external C<grep -i> program and returns the
3139 matching lines.");
3140
3141   ("egrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 155, [ProtocolLimitWarning],
3142    [InitISOFS, Always, TestOutputList (
3143       [["egrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3144    "return lines matching a pattern",
3145    "\
3146 This calls the external C<egrep -i> program and returns the
3147 matching lines.");
3148
3149   ("fgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 156, [ProtocolLimitWarning],
3150    [InitISOFS, Always, TestOutputList (
3151       [["fgrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3152    "return lines matching a pattern",
3153    "\
3154 This calls the external C<fgrep -i> program and returns the
3155 matching lines.");
3156
3157   ("zgrep", (RStringList "lines", [String "regex"; Pathname "path"]), 157, [ProtocolLimitWarning],
3158    [InitISOFS, Always, TestOutputList (
3159       [["zgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3160    "return lines matching a pattern",
3161    "\
3162 This calls the external C<zgrep> program and returns the
3163 matching lines.");
3164
3165   ("zegrep", (RStringList "lines", [String "regex"; Pathname "path"]), 158, [ProtocolLimitWarning],
3166    [InitISOFS, Always, TestOutputList (
3167       [["zegrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3168    "return lines matching a pattern",
3169    "\
3170 This calls the external C<zegrep> program and returns the
3171 matching lines.");
3172
3173   ("zfgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 159, [ProtocolLimitWarning],
3174    [InitISOFS, Always, TestOutputList (
3175       [["zfgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3176    "return lines matching a pattern",
3177    "\
3178 This calls the external C<zfgrep> program and returns the
3179 matching lines.");
3180
3181   ("zgrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 160, [ProtocolLimitWarning],
3182    [InitISOFS, Always, TestOutputList (
3183       [["zgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3184    "return lines matching a pattern",
3185    "\
3186 This calls the external C<zgrep -i> program and returns the
3187 matching lines.");
3188
3189   ("zegrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 161, [ProtocolLimitWarning],
3190    [InitISOFS, Always, TestOutputList (
3191       [["zegrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3192    "return lines matching a pattern",
3193    "\
3194 This calls the external C<zegrep -i> program and returns the
3195 matching lines.");
3196
3197   ("zfgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 162, [ProtocolLimitWarning],
3198    [InitISOFS, Always, TestOutputList (
3199       [["zfgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3200    "return lines matching a pattern",
3201    "\
3202 This calls the external C<zfgrep -i> program and returns the
3203 matching lines.");
3204
3205   ("realpath", (RString "rpath", [Pathname "path"]), 163, [],
3206    [InitISOFS, Always, TestOutput (
3207       [["realpath"; "/../directory"]], "/directory")],
3208    "canonicalized absolute pathname",
3209    "\
3210 Return the canonicalized absolute pathname of C<path>.  The
3211 returned path has no C<.>, C<..> or symbolic link path elements.");
3212
3213   ("ln", (RErr, [String "target"; Pathname "linkname"]), 164, [],
3214    [InitBasicFS, Always, TestOutputStruct (
3215       [["touch"; "/a"];
3216        ["ln"; "/a"; "/b"];
3217        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3218    "create a hard link",
3219    "\
3220 This command creates a hard link using the C<ln> command.");
3221
3222   ("ln_f", (RErr, [String "target"; Pathname "linkname"]), 165, [],
3223    [InitBasicFS, Always, TestOutputStruct (
3224       [["touch"; "/a"];
3225        ["touch"; "/b"];
3226        ["ln_f"; "/a"; "/b"];
3227        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3228    "create a hard link",
3229    "\
3230 This command creates a hard link using the C<ln -f> command.
3231 The C<-f> option removes the link (C<linkname>) if it exists already.");
3232
3233   ("ln_s", (RErr, [String "target"; Pathname "linkname"]), 166, [],
3234    [InitBasicFS, Always, TestOutputStruct (
3235       [["touch"; "/a"];
3236        ["ln_s"; "a"; "/b"];
3237        ["lstat"; "/b"]], [CompareWithInt ("mode", 0o120777)])],
3238    "create a symbolic link",
3239    "\
3240 This command creates a symbolic link using the C<ln -s> command.");
3241
3242   ("ln_sf", (RErr, [String "target"; Pathname "linkname"]), 167, [],
3243    [InitBasicFS, Always, TestOutput (
3244       [["mkdir_p"; "/a/b"];
3245        ["touch"; "/a/b/c"];
3246        ["ln_sf"; "../d"; "/a/b/c"];
3247        ["readlink"; "/a/b/c"]], "../d")],
3248    "create a symbolic link",
3249    "\
3250 This command creates a symbolic link using the C<ln -sf> command,
3251 The C<-f> option removes the link (C<linkname>) if it exists already.");
3252
3253   ("readlink", (RString "link", [Pathname "path"]), 168, [],
3254    [] (* XXX tested above *),
3255    "read the target of a symbolic link",
3256    "\
3257 This command reads the target of a symbolic link.");
3258
3259   ("fallocate", (RErr, [Pathname "path"; Int "len"]), 169, [],
3260    [InitBasicFS, Always, TestOutputStruct (
3261       [["fallocate"; "/a"; "1000000"];
3262        ["stat"; "/a"]], [CompareWithInt ("size", 1_000_000)])],
3263    "preallocate a file in the guest filesystem",
3264    "\
3265 This command preallocates a file (containing zero bytes) named
3266 C<path> of size C<len> bytes.  If the file exists already, it
3267 is overwritten.
3268
3269 Do not confuse this with the guestfish-specific
3270 C<alloc> command which allocates a file in the host and
3271 attaches it as a device.");
3272
3273   ("swapon_device", (RErr, [Device "device"]), 170, [],
3274    [InitPartition, Always, TestRun (
3275       [["mkswap"; "/dev/sda1"];
3276        ["swapon_device"; "/dev/sda1"];
3277        ["swapoff_device"; "/dev/sda1"]])],
3278    "enable swap on device",
3279    "\
3280 This command enables the libguestfs appliance to use the
3281 swap device or partition named C<device>.  The increased
3282 memory is made available for all commands, for example
3283 those run using C<guestfs_command> or C<guestfs_sh>.
3284
3285 Note that you should not swap to existing guest swap
3286 partitions unless you know what you are doing.  They may
3287 contain hibernation information, or other information that
3288 the guest doesn't want you to trash.  You also risk leaking
3289 information about the host to the guest this way.  Instead,
3290 attach a new host device to the guest and swap on that.");
3291
3292   ("swapoff_device", (RErr, [Device "device"]), 171, [],
3293    [], (* XXX tested by swapon_device *)
3294    "disable swap on device",
3295    "\
3296 This command disables the libguestfs appliance swap
3297 device or partition named C<device>.
3298 See C<guestfs_swapon_device>.");
3299
3300   ("swapon_file", (RErr, [Pathname "file"]), 172, [],
3301    [InitBasicFS, Always, TestRun (
3302       [["fallocate"; "/swap"; "8388608"];
3303        ["mkswap_file"; "/swap"];
3304        ["swapon_file"; "/swap"];
3305        ["swapoff_file"; "/swap"]])],
3306    "enable swap on file",
3307    "\
3308 This command enables swap to a file.
3309 See C<guestfs_swapon_device> for other notes.");
3310
3311   ("swapoff_file", (RErr, [Pathname "file"]), 173, [],
3312    [], (* XXX tested by swapon_file *)
3313    "disable swap on file",
3314    "\
3315 This command disables the libguestfs appliance swap on file.");
3316
3317   ("swapon_label", (RErr, [String "label"]), 174, [],
3318    [InitEmpty, Always, TestRun (
3319       [["sfdiskM"; "/dev/sdb"; ","];
3320        ["mkswap_L"; "swapit"; "/dev/sdb1"];
3321        ["swapon_label"; "swapit"];
3322        ["swapoff_label"; "swapit"];
3323        ["zero"; "/dev/sdb"];
3324        ["blockdev_rereadpt"; "/dev/sdb"]])],
3325    "enable swap on labeled swap partition",
3326    "\
3327 This command enables swap to a labeled swap partition.
3328 See C<guestfs_swapon_device> for other notes.");
3329
3330   ("swapoff_label", (RErr, [String "label"]), 175, [],
3331    [], (* XXX tested by swapon_label *)
3332    "disable swap on labeled swap partition",
3333    "\
3334 This command disables the libguestfs appliance swap on
3335 labeled swap partition.");
3336
3337   ("swapon_uuid", (RErr, [String "uuid"]), 176, [],
3338    (let uuid = uuidgen () in
3339     [InitEmpty, Always, TestRun (
3340        [["mkswap_U"; uuid; "/dev/sdb"];
3341         ["swapon_uuid"; uuid];
3342         ["swapoff_uuid"; uuid]])]),
3343    "enable swap on swap partition by UUID",
3344    "\
3345 This command enables swap to a swap partition with the given UUID.
3346 See C<guestfs_swapon_device> for other notes.");
3347
3348   ("swapoff_uuid", (RErr, [String "uuid"]), 177, [],
3349    [], (* XXX tested by swapon_uuid *)
3350    "disable swap on swap partition by UUID",
3351    "\
3352 This command disables the libguestfs appliance swap partition
3353 with the given UUID.");
3354
3355   ("mkswap_file", (RErr, [Pathname "path"]), 178, [],
3356    [InitBasicFS, Always, TestRun (
3357       [["fallocate"; "/swap"; "8388608"];
3358        ["mkswap_file"; "/swap"]])],
3359    "create a swap file",
3360    "\
3361 Create a swap file.
3362
3363 This command just writes a swap file signature to an existing
3364 file.  To create the file itself, use something like C<guestfs_fallocate>.");
3365
3366   ("inotify_init", (RErr, [Int "maxevents"]), 179, [],
3367    [InitISOFS, Always, TestRun (
3368       [["inotify_init"; "0"]])],
3369    "create an inotify handle",
3370    "\
3371 This command creates a new inotify handle.
3372 The inotify subsystem can be used to notify events which happen to
3373 objects in the guest filesystem.
3374
3375 C<maxevents> is the maximum number of events which will be
3376 queued up between calls to C<guestfs_inotify_read> or
3377 C<guestfs_inotify_files>.
3378 If this is passed as C<0>, then the kernel (or previously set)
3379 default is used.  For Linux 2.6.29 the default was 16384 events.
3380 Beyond this limit, the kernel throws away events, but records
3381 the fact that it threw them away by setting a flag
3382 C<IN_Q_OVERFLOW> in the returned structure list (see
3383 C<guestfs_inotify_read>).
3384
3385 Before any events are generated, you have to add some
3386 watches to the internal watch list.  See:
3387 C<guestfs_inotify_add_watch>,
3388 C<guestfs_inotify_rm_watch> and
3389 C<guestfs_inotify_watch_all>.
3390
3391 Queued up events should be read periodically by calling
3392 C<guestfs_inotify_read>
3393 (or C<guestfs_inotify_files> which is just a helpful
3394 wrapper around C<guestfs_inotify_read>).  If you don't
3395 read the events out often enough then you risk the internal
3396 queue overflowing.
3397
3398 The handle should be closed after use by calling
3399 C<guestfs_inotify_close>.  This also removes any
3400 watches automatically.
3401
3402 See also L<inotify(7)> for an overview of the inotify interface
3403 as exposed by the Linux kernel, which is roughly what we expose
3404 via libguestfs.  Note that there is one global inotify handle
3405 per libguestfs instance.");
3406
3407   ("inotify_add_watch", (RInt64 "wd", [Pathname "path"; Int "mask"]), 180, [],
3408    [InitBasicFS, Always, TestOutputList (
3409       [["inotify_init"; "0"];
3410        ["inotify_add_watch"; "/"; "1073741823"];
3411        ["touch"; "/a"];
3412        ["touch"; "/b"];
3413        ["inotify_files"]], ["a"; "b"])],
3414    "add an inotify watch",
3415    "\
3416 Watch C<path> for the events listed in C<mask>.
3417
3418 Note that if C<path> is a directory then events within that
3419 directory are watched, but this does I<not> happen recursively
3420 (in subdirectories).
3421
3422 Note for non-C or non-Linux callers: the inotify events are
3423 defined by the Linux kernel ABI and are listed in
3424 C</usr/include/sys/inotify.h>.");
3425
3426   ("inotify_rm_watch", (RErr, [Int(*XXX64*) "wd"]), 181, [],
3427    [],
3428    "remove an inotify watch",
3429    "\
3430 Remove a previously defined inotify watch.
3431 See C<guestfs_inotify_add_watch>.");
3432
3433   ("inotify_read", (RStructList ("events", "inotify_event"), []), 182, [],
3434    [],
3435    "return list of inotify events",
3436    "\
3437 Return the complete queue of events that have happened
3438 since the previous read call.
3439
3440 If no events have happened, this returns an empty list.
3441
3442 I<Note>: In order to make sure that all events have been
3443 read, you must call this function repeatedly until it
3444 returns an empty list.  The reason is that the call will
3445 read events up to the maximum appliance-to-host message
3446 size and leave remaining events in the queue.");
3447
3448   ("inotify_files", (RStringList "paths", []), 183, [],
3449    [],
3450    "return list of watched files that had events",
3451    "\
3452 This function is a helpful wrapper around C<guestfs_inotify_read>
3453 which just returns a list of pathnames of objects that were
3454 touched.  The returned pathnames are sorted and deduplicated.");
3455
3456   ("inotify_close", (RErr, []), 184, [],
3457    [],
3458    "close the inotify handle",
3459    "\
3460 This closes the inotify handle which was previously
3461 opened by inotify_init.  It removes all watches, throws
3462 away any pending events, and deallocates all resources.");
3463
3464   ("setcon", (RErr, [String "context"]), 185, [],
3465    [],
3466    "set SELinux security context",
3467    "\
3468 This sets the SELinux security context of the daemon
3469 to the string C<context>.
3470
3471 See the documentation about SELINUX in L<guestfs(3)>.");
3472
3473   ("getcon", (RString "context", []), 186, [],
3474    [],
3475    "get SELinux security context",
3476    "\
3477 This gets the SELinux security context of the daemon.
3478
3479 See the documentation about SELINUX in L<guestfs(3)>,
3480 and C<guestfs_setcon>");
3481
3482   ("mkfs_b", (RErr, [String "fstype"; Int "blocksize"; Device "device"]), 187, [],
3483    [InitEmpty, Always, TestOutput (
3484       [["sfdiskM"; "/dev/sda"; ","];
3485        ["mkfs_b"; "ext2"; "4096"; "/dev/sda1"];
3486        ["mount"; "/dev/sda1"; "/"];
3487        ["write_file"; "/new"; "new file contents"; "0"];
3488        ["cat"; "/new"]], "new file contents")],
3489    "make a filesystem with block size",
3490    "\
3491 This call is similar to C<guestfs_mkfs>, but it allows you to
3492 control the block size of the resulting filesystem.  Supported
3493 block sizes depend on the filesystem type, but typically they
3494 are C<1024>, C<2048> or C<4096> only.");
3495
3496   ("mke2journal", (RErr, [Int "blocksize"; Device "device"]), 188, [],
3497    [InitEmpty, Always, TestOutput (
3498       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3499        ["mke2journal"; "4096"; "/dev/sda1"];
3500        ["mke2fs_J"; "ext2"; "4096"; "/dev/sda2"; "/dev/sda1"];
3501        ["mount"; "/dev/sda2"; "/"];
3502        ["write_file"; "/new"; "new file contents"; "0"];
3503        ["cat"; "/new"]], "new file contents")],
3504    "make ext2/3/4 external journal",
3505    "\
3506 This creates an ext2 external journal on C<device>.  It is equivalent
3507 to the command:
3508
3509  mke2fs -O journal_dev -b blocksize device");
3510
3511   ("mke2journal_L", (RErr, [Int "blocksize"; String "label"; Device "device"]), 189, [],
3512    [InitEmpty, Always, TestOutput (
3513       [["sfdiskM"; "/dev/sda"; ",100 ,"];
3514        ["mke2journal_L"; "4096"; "JOURNAL"; "/dev/sda1"];
3515        ["mke2fs_JL"; "ext2"; "4096"; "/dev/sda2"; "JOURNAL"];
3516        ["mount"; "/dev/sda2"; "/"];
3517        ["write_file"; "/new"; "new file contents"; "0"];
3518        ["cat"; "/new"]], "new file contents")],
3519    "make ext2/3/4 external journal with label",
3520    "\
3521 This creates an ext2 external journal on C<device> with label C<label>.");
3522
3523   ("mke2journal_U", (RErr, [Int "blocksize"; String "uuid"; Device "device"]), 190, [],
3524    (let uuid = uuidgen () in
3525     [InitEmpty, Always, TestOutput (
3526        [["sfdiskM"; "/dev/sda"; ",100 ,"];
3527         ["mke2journal_U"; "4096"; uuid; "/dev/sda1"];
3528         ["mke2fs_JU"; "ext2"; "4096"; "/dev/sda2"; uuid];
3529         ["mount"; "/dev/sda2"; "/"];
3530         ["write_file"; "/new"; "new file contents"; "0"];
3531         ["cat"; "/new"]], "new file contents")]),
3532    "make ext2/3/4 external journal with UUID",
3533    "\
3534 This creates an ext2 external journal on C<device> with UUID C<uuid>.");
3535
3536   ("mke2fs_J", (RErr, [String "fstype"; Int "blocksize"; Device "device"; Device "journal"]), 191, [],
3537    [],
3538    "make ext2/3/4 filesystem with external journal",
3539    "\
3540 This creates an ext2/3/4 filesystem on C<device> with
3541 an external journal on C<journal>.  It is equivalent
3542 to the command:
3543
3544  mke2fs -t fstype -b blocksize -J device=<journal> <device>
3545
3546 See also C<guestfs_mke2journal>.");
3547
3548   ("mke2fs_JL", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "label"]), 192, [],
3549    [],
3550    "make ext2/3/4 filesystem with external journal",
3551    "\
3552 This creates an ext2/3/4 filesystem on C<device> with
3553 an external journal on the journal labeled C<label>.
3554
3555 See also C<guestfs_mke2journal_L>.");
3556
3557   ("mke2fs_JU", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "uuid"]), 193, [],
3558    [],
3559    "make ext2/3/4 filesystem with external journal",
3560    "\
3561 This creates an ext2/3/4 filesystem on C<device> with
3562 an external journal on the journal with UUID C<uuid>.
3563
3564 See also C<guestfs_mke2journal_U>.");
3565
3566   ("modprobe", (RErr, [String "modulename"]), 194, [],
3567    [InitNone, Always, TestRun [["modprobe"; "fat"]]],
3568    "load a kernel module",
3569    "\
3570 This loads a kernel module in the appliance.
3571
3572 The kernel module must have been whitelisted when libguestfs
3573 was built (see C<appliance/kmod.whitelist.in> in the source).");
3574
3575   ("echo_daemon", (RString "output", [StringList "words"]), 195, [],
3576    [InitNone, Always, TestOutput (
3577      [["echo_daemon"; "This is a test"]], "This is a test"
3578    )],
3579    "echo arguments back to the client",
3580    "\
3581 This command concatenate the list of C<words> passed with single spaces between
3582 them and returns the resulting string.
3583
3584 You can use this command to test the connection through to the daemon.
3585
3586 See also C<guestfs_ping_daemon>.");
3587
3588 ]
3589
3590 let all_functions = non_daemon_functions @ daemon_functions
3591
3592 (* In some places we want the functions to be displayed sorted
3593  * alphabetically, so this is useful:
3594  *)
3595 let all_functions_sorted =
3596   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
3597                compare n1 n2) all_functions
3598
3599 (* Field types for structures. *)
3600 type field =
3601   | FChar                       (* C 'char' (really, a 7 bit byte). *)
3602   | FString                     (* nul-terminated ASCII string, NOT NULL. *)
3603   | FBuffer                     (* opaque buffer of bytes, (char *, int) pair *)
3604   | FUInt32
3605   | FInt32
3606   | FUInt64
3607   | FInt64
3608   | FBytes                      (* Any int measure that counts bytes. *)
3609   | FUUID                       (* 32 bytes long, NOT nul-terminated. *)
3610   | FOptPercent                 (* [0..100], or -1 meaning "not present". *)
3611
3612 (* Because we generate extra parsing code for LVM command line tools,
3613  * we have to pull out the LVM columns separately here.
3614  *)
3615 let lvm_pv_cols = [
3616   "pv_name", FString;
3617   "pv_uuid", FUUID;
3618   "pv_fmt", FString;
3619   "pv_size", FBytes;
3620   "dev_size", FBytes;
3621   "pv_free", FBytes;
3622   "pv_used", FBytes;
3623   "pv_attr", FString (* XXX *);
3624   "pv_pe_count", FInt64;
3625   "pv_pe_alloc_count", FInt64;
3626   "pv_tags", FString;
3627   "pe_start", FBytes;
3628   "pv_mda_count", FInt64;
3629   "pv_mda_free", FBytes;
3630   (* Not in Fedora 10:
3631      "pv_mda_size", FBytes;
3632   *)
3633 ]
3634 let lvm_vg_cols = [
3635   "vg_name", FString;
3636   "vg_uuid", FUUID;
3637   "vg_fmt", FString;
3638   "vg_attr", FString (* XXX *);
3639   "vg_size", FBytes;
3640   "vg_free", FBytes;
3641   "vg_sysid", FString;
3642   "vg_extent_size", FBytes;
3643   "vg_extent_count", FInt64;
3644   "vg_free_count", FInt64;
3645   "max_lv", FInt64;
3646   "max_pv", FInt64;
3647   "pv_count", FInt64;
3648   "lv_count", FInt64;
3649   "snap_count", FInt64;
3650   "vg_seqno", FInt64;
3651   "vg_tags", FString;
3652   "vg_mda_count", FInt64;
3653   "vg_mda_free", FBytes;
3654   (* Not in Fedora 10:
3655      "vg_mda_size", FBytes;
3656   *)
3657 ]
3658 let lvm_lv_cols = [
3659   "lv_name", FString;
3660   "lv_uuid", FUUID;
3661   "lv_attr", FString (* XXX *);
3662   "lv_major", FInt64;
3663   "lv_minor", FInt64;
3664   "lv_kernel_major", FInt64;
3665   "lv_kernel_minor", FInt64;
3666   "lv_size", FBytes;
3667   "seg_count", FInt64;
3668   "origin", FString;
3669   "snap_percent", FOptPercent;
3670   "copy_percent", FOptPercent;
3671   "move_pv", FString;
3672   "lv_tags", FString;
3673   "mirror_log", FString;
3674   "modules", FString;
3675 ]
3676
3677 (* Names and fields in all structures (in RStruct and RStructList)
3678  * that we support.
3679  *)
3680 let structs = [
3681   (* The old RIntBool return type, only ever used for aug_defnode.  Do
3682    * not use this struct in any new code.
3683    *)
3684   "int_bool", [
3685     "i", FInt32;                (* for historical compatibility *)
3686     "b", FInt32;                (* for historical compatibility *)
3687   ];
3688
3689   (* LVM PVs, VGs, LVs. *)
3690   "lvm_pv", lvm_pv_cols;
3691   "lvm_vg", lvm_vg_cols;
3692   "lvm_lv", lvm_lv_cols;
3693
3694   (* Column names and types from stat structures.
3695    * NB. Can't use things like 'st_atime' because glibc header files
3696    * define some of these as macros.  Ugh.
3697    *)
3698   "stat", [
3699     "dev", FInt64;
3700     "ino", FInt64;
3701     "mode", FInt64;
3702     "nlink", FInt64;
3703     "uid", FInt64;
3704     "gid", FInt64;
3705     "rdev", FInt64;
3706     "size", FInt64;
3707     "blksize", FInt64;
3708     "blocks", FInt64;
3709     "atime", FInt64;
3710     "mtime", FInt64;
3711     "ctime", FInt64;
3712   ];
3713   "statvfs", [
3714     "bsize", FInt64;
3715     "frsize", FInt64;
3716     "blocks", FInt64;
3717     "bfree", FInt64;
3718     "bavail", FInt64;
3719     "files", FInt64;
3720     "ffree", FInt64;
3721     "favail", FInt64;
3722     "fsid", FInt64;
3723     "flag", FInt64;
3724     "namemax", FInt64;
3725   ];
3726
3727   (* Column names in dirent structure. *)
3728   "dirent", [
3729     "ino", FInt64;
3730     (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
3731     "ftyp", FChar;
3732     "name", FString;
3733   ];
3734
3735   (* Version numbers. *)
3736   "version", [
3737     "major", FInt64;
3738     "minor", FInt64;
3739     "release", FInt64;
3740     "extra", FString;
3741   ];
3742
3743   (* Extended attribute. *)
3744   "xattr", [
3745     "attrname", FString;
3746     "attrval", FBuffer;
3747   ];
3748
3749   (* Inotify events. *)
3750   "inotify_event", [
3751     "in_wd", FInt64;
3752     "in_mask", FUInt32;
3753     "in_cookie", FUInt32;
3754     "in_name", FString;
3755   ];
3756 ] (* end of structs *)
3757
3758 (* Ugh, Java has to be different ..
3759  * These names are also used by the Haskell bindings.
3760  *)
3761 let java_structs = [
3762   "int_bool", "IntBool";
3763   "lvm_pv", "PV";
3764   "lvm_vg", "VG";
3765   "lvm_lv", "LV";
3766   "stat", "Stat";
3767   "statvfs", "StatVFS";
3768   "dirent", "Dirent";
3769   "version", "Version";
3770   "xattr", "XAttr";
3771   "inotify_event", "INotifyEvent";
3772 ]
3773
3774 (* What structs are actually returned. *)
3775 type rstructs_used_t = RStructOnly | RStructListOnly | RStructAndList
3776
3777 (* Returns a list of RStruct/RStructList structs that are returned
3778  * by any function.  Each element of returned list is a pair:
3779  *
3780  * (structname, RStructOnly)
3781  *    == there exists function which returns RStruct (_, structname)
3782  * (structname, RStructListOnly)
3783  *    == there exists function which returns RStructList (_, structname)
3784  * (structname, RStructAndList)
3785  *    == there are functions returning both RStruct (_, structname)
3786  *                                      and RStructList (_, structname)
3787  *)
3788 let rstructs_used =
3789   (* ||| is a "logical OR" for rstructs_used_t *)
3790   let (|||) a b =
3791     match a, b with
3792     | RStructAndList, _
3793     | _, RStructAndList -> RStructAndList
3794     | RStructOnly, RStructListOnly
3795     | RStructListOnly, RStructOnly -> RStructAndList
3796     | RStructOnly, RStructOnly -> RStructOnly
3797     | RStructListOnly, RStructListOnly -> RStructListOnly
3798   in
3799
3800   let h = Hashtbl.create 13 in
3801
3802   (* if elem->oldv exists, update entry using ||| operator,
3803    * else just add elem->newv to the hash
3804    *)
3805   let update elem newv =
3806     try  let oldv = Hashtbl.find h elem in
3807          Hashtbl.replace h elem (newv ||| oldv)
3808     with Not_found -> Hashtbl.add h elem newv
3809   in
3810
3811   List.iter (
3812     fun (_, style, _, _, _, _, _) ->
3813       match fst style with
3814       | RStruct (_, structname) -> update structname RStructOnly
3815       | RStructList (_, structname) -> update structname RStructListOnly
3816       | _ -> ()
3817   ) all_functions;
3818
3819   (* return key->values as a list of (key,value) *)
3820   Hashtbl.fold (fun key value xs -> (key, value) :: xs) h []
3821
3822 (* debug:
3823 let () =
3824   List.iter (
3825     function
3826     | sn, RStructOnly -> printf "%s RStructOnly\n" sn
3827     | sn, RStructListOnly -> printf "%s RStructListOnly\n" sn
3828     | sn, RStructAndList -> printf "%s RStructAndList\n" sn
3829   ) rstructs_used
3830 *)
3831
3832 (* Used for testing language bindings. *)
3833 type callt =
3834   | CallString of string
3835   | CallOptString of string option
3836   | CallStringList of string list
3837   | CallInt of int
3838   | CallBool of bool
3839
3840 (* Used to memoize the result of pod2text. *)
3841 let pod2text_memo_filename = "src/.pod2text.data"
3842 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
3843   try
3844     let chan = open_in pod2text_memo_filename in
3845     let v = input_value chan in
3846     close_in chan;
3847     v
3848   with
3849     _ -> Hashtbl.create 13
3850 let pod2text_memo_updated () =
3851   let chan = open_out pod2text_memo_filename in
3852   output_value chan pod2text_memo;
3853   close_out chan
3854
3855 (* Useful functions.
3856  * Note we don't want to use any external OCaml libraries which
3857  * makes this a bit harder than it should be.
3858  *)
3859 let failwithf fs = ksprintf failwith fs
3860
3861 let replace_char s c1 c2 =
3862   let s2 = String.copy s in
3863   let r = ref false in
3864   for i = 0 to String.length s2 - 1 do
3865     if String.unsafe_get s2 i = c1 then (
3866       String.unsafe_set s2 i c2;
3867       r := true
3868     )
3869   done;
3870   if not !r then s else s2
3871
3872 let isspace c =
3873   c = ' '
3874   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
3875
3876 let triml ?(test = isspace) str =
3877   let i = ref 0 in
3878   let n = ref (String.length str) in
3879   while !n > 0 && test str.[!i]; do
3880     decr n;
3881     incr i
3882   done;
3883   if !i = 0 then str
3884   else String.sub str !i !n
3885
3886 let trimr ?(test = isspace) str =
3887   let n = ref (String.length str) in
3888   while !n > 0 && test str.[!n-1]; do
3889     decr n
3890   done;
3891   if !n = String.length str then str
3892   else String.sub str 0 !n
3893
3894 let trim ?(test = isspace) str =
3895   trimr ~test (triml ~test str)
3896
3897 let rec find s sub =
3898   let len = String.length s in
3899   let sublen = String.length sub in
3900   let rec loop i =
3901     if i <= len-sublen then (
3902       let rec loop2 j =
3903         if j < sublen then (
3904           if s.[i+j] = sub.[j] then loop2 (j+1)
3905           else -1
3906         ) else
3907           i (* found *)
3908       in
3909       let r = loop2 0 in
3910       if r = -1 then loop (i+1) else r
3911     ) else
3912       -1 (* not found *)
3913   in
3914   loop 0
3915
3916 let rec replace_str s s1 s2 =
3917   let len = String.length s in
3918   let sublen = String.length s1 in
3919   let i = find s s1 in
3920   if i = -1 then s
3921   else (
3922     let s' = String.sub s 0 i in
3923     let s'' = String.sub s (i+sublen) (len-i-sublen) in
3924     s' ^ s2 ^ replace_str s'' s1 s2
3925   )
3926
3927 let rec string_split sep str =
3928   let len = String.length str in
3929   let seplen = String.length sep in
3930   let i = find str sep in
3931   if i = -1 then [str]
3932   else (
3933     let s' = String.sub str 0 i in
3934     let s'' = String.sub str (i+seplen) (len-i-seplen) in
3935     s' :: string_split sep s''
3936   )
3937
3938 let files_equal n1 n2 =
3939   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
3940   match Sys.command cmd with
3941   | 0 -> true
3942   | 1 -> false
3943   | i -> failwithf "%s: failed with error code %d" cmd i
3944
3945 let rec filter_map f = function
3946   | [] -> []
3947   | x :: xs ->
3948       match f x with
3949       | Some y -> y :: filter_map f xs
3950       | None -> filter_map f xs
3951
3952 let rec find_map f = function
3953   | [] -> raise Not_found
3954   | x :: xs ->
3955       match f x with
3956       | Some y -> y
3957       | None -> find_map f xs
3958
3959 let iteri f xs =
3960   let rec loop i = function
3961     | [] -> ()
3962     | x :: xs -> f i x; loop (i+1) xs
3963   in
3964   loop 0 xs
3965
3966 let mapi f xs =
3967   let rec loop i = function
3968     | [] -> []
3969     | x :: xs -> let r = f i x in r :: loop (i+1) xs
3970   in
3971   loop 0 xs
3972
3973 let name_of_argt = function
3974   | Pathname n | Device n | Dev_or_Path n | String n | OptString n
3975   | StringList n | DeviceList n | Bool n | Int n
3976   | FileIn n | FileOut n -> n
3977
3978 let java_name_of_struct typ =
3979   try List.assoc typ java_structs
3980   with Not_found ->
3981     failwithf
3982       "java_name_of_struct: no java_structs entry corresponding to %s" typ
3983
3984 let cols_of_struct typ =
3985   try List.assoc typ structs
3986   with Not_found ->
3987     failwithf "cols_of_struct: unknown struct %s" typ
3988
3989 let seq_of_test = function
3990   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
3991   | TestOutputListOfDevices (s, _)
3992   | TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
3993   | TestOutputTrue s | TestOutputFalse s
3994   | TestOutputLength (s, _) | TestOutputBuffer (s, _)
3995   | TestOutputStruct (s, _)
3996   | TestLastFail s -> s
3997
3998 (* Handling for function flags. *)
3999 let protocol_limit_warning =
4000   "Because of the message protocol, there is a transfer limit
4001 of somewhere between 2MB and 4MB.  To transfer large files you should use
4002 FTP."
4003
4004 let danger_will_robinson =
4005   "B<This command is dangerous.  Without careful use you
4006 can easily destroy all your data>."
4007
4008 let deprecation_notice flags =
4009   try
4010     let alt =
4011       find_map (function DeprecatedBy str -> Some str | _ -> None) flags in
4012     let txt =
4013       sprintf "This function is deprecated.
4014 In new code, use the C<%s> call instead.
4015
4016 Deprecated functions will not be removed from the API, but the
4017 fact that they are deprecated indicates that there are problems
4018 with correct use of these functions." alt in
4019     Some txt
4020   with
4021     Not_found -> None
4022
4023 (* Check function names etc. for consistency. *)
4024 let check_functions () =
4025   let contains_uppercase str =
4026     let len = String.length str in
4027     let rec loop i =
4028       if i >= len then false
4029       else (
4030         let c = str.[i] in
4031         if c >= 'A' && c <= 'Z' then true
4032         else loop (i+1)
4033       )
4034     in
4035     loop 0
4036   in
4037
4038   (* Check function names. *)
4039   List.iter (
4040     fun (name, _, _, _, _, _, _) ->
4041       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
4042         failwithf "function name %s does not need 'guestfs' prefix" name;
4043       if name = "" then
4044         failwithf "function name is empty";
4045       if name.[0] < 'a' || name.[0] > 'z' then
4046         failwithf "function name %s must start with lowercase a-z" name;
4047       if String.contains name '-' then
4048         failwithf "function name %s should not contain '-', use '_' instead."
4049           name
4050   ) all_functions;
4051
4052   (* Check function parameter/return names. *)
4053   List.iter (
4054     fun (name, style, _, _, _, _, _) ->
4055       let check_arg_ret_name n =
4056         if contains_uppercase n then
4057           failwithf "%s param/ret %s should not contain uppercase chars"
4058             name n;
4059         if String.contains n '-' || String.contains n '_' then
4060           failwithf "%s param/ret %s should not contain '-' or '_'"
4061             name n;
4062         if n = "value" then
4063           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;
4064         if n = "int" || n = "char" || n = "short" || n = "long" then
4065           failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
4066         if n = "i" || n = "n" then
4067           failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
4068         if n = "argv" || n = "args" then
4069           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name;
4070
4071         (* List Haskell, OCaml and C keywords here.
4072          * http://www.haskell.org/haskellwiki/Keywords
4073          * http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#operator-char
4074          * http://en.wikipedia.org/wiki/C_syntax#Reserved_keywords
4075          * Formatted via: cat c haskell ocaml|sort -u|grep -vE '_|^val$' \
4076          *   |perl -pe 's/(.+)/"$1";/'|fmt -70
4077          * Omitting _-containing words, since they're handled above.
4078          * Omitting the OCaml reserved word, "val", is ok,
4079          * and saves us from renaming several parameters.
4080          *)
4081         let reserved = [
4082           "and"; "as"; "asr"; "assert"; "auto"; "begin"; "break"; "case";
4083           "char"; "class"; "const"; "constraint"; "continue"; "data";
4084           "default"; "deriving"; "do"; "done"; "double"; "downto"; "else";
4085           "end"; "enum"; "exception"; "extern"; "external"; "false"; "float";
4086           "for"; "forall"; "foreign"; "fun"; "function"; "functor"; "goto";
4087           "hiding"; "if"; "import"; "in"; "include"; "infix"; "infixl";
4088           "infixr"; "inherit"; "initializer"; "inline"; "instance"; "int";
4089           "land"; "lazy"; "let"; "long"; "lor"; "lsl"; "lsr"; "lxor";
4090           "match"; "mdo"; "method"; "mod"; "module"; "mutable"; "new";
4091           "newtype"; "object"; "of"; "open"; "or"; "private"; "qualified";
4092           "rec"; "register"; "restrict"; "return"; "short"; "sig"; "signed";
4093           "sizeof"; "static"; "struct"; "switch"; "then"; "to"; "true"; "try";
4094           "type"; "typedef"; "union"; "unsigned"; "virtual"; "void";
4095           "volatile"; "when"; "where"; "while";
4096           ] in
4097         if List.mem n reserved then
4098           failwithf "%s has param/ret using reserved word %s" name n;
4099       in
4100
4101       (match fst style with
4102        | RErr -> ()
4103        | RInt n | RInt64 n | RBool n
4104        | RConstString n | RConstOptString n | RString n
4105        | RStringList n | RStruct (n, _) | RStructList (n, _)
4106        | RHashtable n | RBufferOut n ->
4107            check_arg_ret_name n
4108       );
4109       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
4110   ) all_functions;
4111
4112   (* Check short descriptions. *)
4113   List.iter (
4114     fun (name, _, _, _, _, shortdesc, _) ->
4115       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
4116         failwithf "short description of %s should begin with lowercase." name;
4117       let c = shortdesc.[String.length shortdesc-1] in
4118       if c = '\n' || c = '.' then
4119         failwithf "short description of %s should not end with . or \\n." name
4120   ) all_functions;
4121
4122   (* Check long dscriptions. *)
4123   List.iter (
4124     fun (name, _, _, _, _, _, longdesc) ->
4125       if longdesc.[String.length longdesc-1] = '\n' then
4126         failwithf "long description of %s should not end with \\n." name
4127   ) all_functions;
4128
4129   (* Check proc_nrs. *)
4130   List.iter (
4131     fun (name, _, proc_nr, _, _, _, _) ->
4132       if proc_nr <= 0 then
4133         failwithf "daemon function %s should have proc_nr > 0" name
4134   ) daemon_functions;
4135
4136   List.iter (
4137     fun (name, _, proc_nr, _, _, _, _) ->
4138       if proc_nr <> -1 then
4139         failwithf "non-daemon function %s should have proc_nr -1" name
4140   ) non_daemon_functions;
4141
4142   let proc_nrs =
4143     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
4144       daemon_functions in
4145   let proc_nrs =
4146     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
4147   let rec loop = function
4148     | [] -> ()
4149     | [_] -> ()
4150     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
4151         loop rest
4152     | (name1,nr1) :: (name2,nr2) :: _ ->
4153         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
4154           name1 name2 nr1 nr2
4155   in
4156   loop proc_nrs;
4157
4158   (* Check tests. *)
4159   List.iter (
4160     function
4161       (* Ignore functions that have no tests.  We generate a
4162        * warning when the user does 'make check' instead.
4163        *)
4164     | name, _, _, _, [], _, _ -> ()
4165     | name, _, _, _, tests, _, _ ->
4166         let funcs =
4167           List.map (
4168             fun (_, _, test) ->
4169               match seq_of_test test with
4170               | [] ->
4171                   failwithf "%s has a test containing an empty sequence" name
4172               | cmds -> List.map List.hd cmds
4173           ) tests in
4174         let funcs = List.flatten funcs in
4175
4176         let tested = List.mem name funcs in
4177
4178         if not tested then
4179           failwithf "function %s has tests but does not test itself" name
4180   ) all_functions
4181
4182 (* 'pr' prints to the current output file. *)
4183 let chan = ref stdout
4184 let pr fs = ksprintf (output_string !chan) fs
4185
4186 (* Generate a header block in a number of standard styles. *)
4187 type comment_style = CStyle | HashStyle | OCamlStyle | HaskellStyle
4188 type license = GPLv2 | LGPLv2
4189
4190 let generate_header comment license =
4191   let c = match comment with
4192     | CStyle ->     pr "/* "; " *"
4193     | HashStyle ->  pr "# ";  "#"
4194     | OCamlStyle -> pr "(* "; " *"
4195     | HaskellStyle -> pr "{- "; "  " in
4196   pr "libguestfs generated file\n";
4197   pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
4198   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
4199   pr "%s\n" c;
4200   pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
4201   pr "%s\n" c;
4202   (match license with
4203    | GPLv2 ->
4204        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
4205        pr "%s it under the terms of the GNU General Public License as published by\n" c;
4206        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
4207        pr "%s (at your option) any later version.\n" c;
4208        pr "%s\n" c;
4209        pr "%s This program is distributed in the hope that it will be useful,\n" c;
4210        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
4211        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
4212        pr "%s GNU General Public License for more details.\n" c;
4213        pr "%s\n" c;
4214        pr "%s You should have received a copy of the GNU General Public License along\n" c;
4215        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
4216        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
4217
4218    | LGPLv2 ->
4219        pr "%s This library is free software; you can redistribute it and/or\n" c;
4220        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
4221        pr "%s License as published by the Free Software Foundation; either\n" c;
4222        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
4223        pr "%s\n" c;
4224        pr "%s This library is distributed in the hope that it will be useful,\n" c;
4225        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
4226        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
4227        pr "%s Lesser General Public License for more details.\n" c;
4228        pr "%s\n" c;
4229        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
4230        pr "%s License along with this library; if not, write to the Free Software\n" c;
4231        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
4232   );
4233   (match comment with
4234    | CStyle -> pr " */\n"
4235    | HashStyle -> ()
4236    | OCamlStyle -> pr " *)\n"
4237    | HaskellStyle -> pr "-}\n"
4238   );
4239   pr "\n"
4240
4241 (* Start of main code generation functions below this line. *)
4242
4243 (* Generate the pod documentation for the C API. *)
4244 let rec generate_actions_pod () =
4245   List.iter (
4246     fun (shortname, style, _, flags, _, _, longdesc) ->
4247       if not (List.mem NotInDocs flags) then (
4248         let name = "guestfs_" ^ shortname in
4249         pr "=head2 %s\n\n" name;
4250         pr " ";
4251         generate_prototype ~extern:false ~handle:"handle" name style;
4252         pr "\n\n";
4253         pr "%s\n\n" longdesc;
4254         (match fst style with
4255          | RErr ->
4256              pr "This function returns 0 on success or -1 on error.\n\n"
4257          | RInt _ ->
4258              pr "On error this function returns -1.\n\n"
4259          | RInt64 _ ->
4260              pr "On error this function returns -1.\n\n"
4261          | RBool _ ->
4262              pr "This function returns a C truth value on success or -1 on error.\n\n"
4263          | RConstString _ ->
4264              pr "This function returns a string, or NULL on error.
4265 The string is owned by the guest handle and must I<not> be freed.\n\n"
4266          | RConstOptString _ ->
4267              pr "This function returns a string which may be NULL.
4268 There is way to return an error from this function.
4269 The string is owned by the guest handle and must I<not> be freed.\n\n"
4270          | RString _ ->
4271              pr "This function returns a string, or NULL on error.
4272 I<The caller must free the returned string after use>.\n\n"
4273          | RStringList _ ->
4274              pr "This function returns a NULL-terminated array of strings
4275 (like L<environ(3)>), or NULL if there was an error.
4276 I<The caller must free the strings and the array after use>.\n\n"
4277          | RStruct (_, typ) ->
4278              pr "This function returns a C<struct guestfs_%s *>,
4279 or NULL if there was an error.
4280 I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ
4281          | RStructList (_, typ) ->
4282              pr "This function returns a C<struct guestfs_%s_list *>
4283 (see E<lt>guestfs-structs.hE<gt>),
4284 or NULL if there was an error.
4285 I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ
4286          | RHashtable _ ->
4287              pr "This function returns a NULL-terminated array of
4288 strings, or NULL if there was an error.
4289 The array of strings will always have length C<2n+1>, where
4290 C<n> keys and values alternate, followed by the trailing NULL entry.
4291 I<The caller must free the strings and the array after use>.\n\n"
4292          | RBufferOut _ ->
4293              pr "This function returns a buffer, or NULL on error.
4294 The size of the returned buffer is written to C<*size_r>.
4295 I<The caller must free the returned buffer after use>.\n\n"
4296         );
4297         if List.mem ProtocolLimitWarning flags then
4298           pr "%s\n\n" protocol_limit_warning;
4299         if List.mem DangerWillRobinson flags then
4300           pr "%s\n\n" danger_will_robinson;
4301         match deprecation_notice flags with
4302         | None -> ()
4303         | Some txt -> pr "%s\n\n" txt
4304       )
4305   ) all_functions_sorted
4306
4307 and generate_structs_pod () =
4308   (* Structs documentation. *)
4309   List.iter (
4310     fun (typ, cols) ->
4311       pr "=head2 guestfs_%s\n" typ;
4312       pr "\n";
4313       pr " struct guestfs_%s {\n" typ;
4314       List.iter (
4315         function
4316         | name, FChar -> pr "   char %s;\n" name
4317         | name, FUInt32 -> pr "   uint32_t %s;\n" name
4318         | name, FInt32 -> pr "   int32_t %s;\n" name
4319         | name, (FUInt64|FBytes) -> pr "   uint64_t %s;\n" name
4320         | name, FInt64 -> pr "   int64_t %s;\n" name
4321         | name, FString -> pr "   char *%s;\n" name
4322         | name, FBuffer ->
4323             pr "   /* The next two fields describe a byte array. */\n";
4324             pr "   uint32_t %s_len;\n" name;
4325             pr "   char *%s;\n" name
4326         | name, FUUID ->
4327             pr "   /* The next field is NOT nul-terminated, be careful when printing it: */\n";
4328             pr "   char %s[32];\n" name
4329         | name, FOptPercent ->
4330             pr "   /* The next field is [0..100] or -1 meaning 'not present': */\n";
4331             pr "   float %s;\n" name
4332       ) cols;
4333       pr " };\n";
4334       pr " \n";
4335       pr " struct guestfs_%s_list {\n" typ;
4336       pr "   uint32_t len; /* Number of elements in list. */\n";
4337       pr "   struct guestfs_%s *val; /* Elements. */\n" typ;
4338       pr " };\n";
4339       pr " \n";
4340       pr " void guestfs_free_%s (struct guestfs_free_%s *);\n" typ typ;
4341       pr " void guestfs_free_%s_list (struct guestfs_free_%s_list *);\n"
4342         typ typ;
4343       pr "\n"
4344   ) structs
4345
4346 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
4347  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
4348  *
4349  * We have to use an underscore instead of a dash because otherwise
4350  * rpcgen generates incorrect code.
4351  *
4352  * This header is NOT exported to clients, but see also generate_structs_h.
4353  *)
4354 and generate_xdr () =
4355   generate_header CStyle LGPLv2;
4356
4357   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
4358   pr "typedef string str<>;\n";
4359   pr "\n";
4360
4361   (* Internal structures. *)
4362   List.iter (
4363     function
4364     | typ, cols ->
4365         pr "struct guestfs_int_%s {\n" typ;
4366         List.iter (function
4367                    | name, FChar -> pr "  char %s;\n" name
4368                    | name, FString -> pr "  string %s<>;\n" name
4369                    | name, FBuffer -> pr "  opaque %s<>;\n" name
4370                    | name, FUUID -> pr "  opaque %s[32];\n" name
4371                    | name, (FInt32|FUInt32) -> pr "  int %s;\n" name
4372                    | name, (FInt64|FUInt64|FBytes) -> pr "  hyper %s;\n" name
4373                    | name, FOptPercent -> pr "  float %s;\n" name
4374                   ) cols;
4375         pr "};\n";
4376         pr "\n";
4377         pr "typedef struct guestfs_int_%s guestfs_int_%s_list<>;\n" typ typ;
4378         pr "\n";
4379   ) structs;
4380
4381   List.iter (
4382     fun (shortname, style, _, _, _, _, _) ->
4383       let name = "guestfs_" ^ shortname in
4384
4385       (match snd style with
4386        | [] -> ()
4387        | args ->
4388            pr "struct %s_args {\n" name;
4389            List.iter (
4390              function
4391              | Pathname n | Device n | Dev_or_Path n | String n -> pr "  string %s<>;\n" n
4392              | OptString n -> pr "  str *%s;\n" n
4393              | StringList n | DeviceList n -> pr "  str %s<>;\n" n
4394              | Bool n -> pr "  bool %s;\n" n
4395              | Int n -> pr "  int %s;\n" n
4396              | FileIn _ | FileOut _ -> ()
4397            ) args;
4398            pr "};\n\n"
4399       );
4400       (match fst style with
4401        | RErr -> ()
4402        | RInt n ->
4403            pr "struct %s_ret {\n" name;
4404            pr "  int %s;\n" n;
4405            pr "};\n\n"
4406        | RInt64 n ->
4407            pr "struct %s_ret {\n" name;
4408            pr "  hyper %s;\n" n;
4409            pr "};\n\n"
4410        | RBool n ->
4411            pr "struct %s_ret {\n" name;
4412            pr "  bool %s;\n" n;
4413            pr "};\n\n"
4414        | RConstString _ | RConstOptString _ ->
4415            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4416        | RString n ->
4417            pr "struct %s_ret {\n" name;
4418            pr "  string %s<>;\n" n;
4419            pr "};\n\n"
4420        | RStringList n ->
4421            pr "struct %s_ret {\n" name;
4422            pr "  str %s<>;\n" n;
4423            pr "};\n\n"
4424        | RStruct (n, typ) ->
4425            pr "struct %s_ret {\n" name;
4426            pr "  guestfs_int_%s %s;\n" typ n;
4427            pr "};\n\n"
4428        | RStructList (n, typ) ->
4429            pr "struct %s_ret {\n" name;
4430            pr "  guestfs_int_%s_list %s;\n" typ n;
4431            pr "};\n\n"
4432        | RHashtable n ->
4433            pr "struct %s_ret {\n" name;
4434            pr "  str %s<>;\n" n;
4435            pr "};\n\n"
4436        | RBufferOut n ->
4437            pr "struct %s_ret {\n" name;
4438            pr "  opaque %s<>;\n" n;
4439            pr "};\n\n"
4440       );
4441   ) daemon_functions;
4442
4443   (* Table of procedure numbers. *)
4444   pr "enum guestfs_procedure {\n";
4445   List.iter (
4446     fun (shortname, _, proc_nr, _, _, _, _) ->
4447       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
4448   ) daemon_functions;
4449   pr "  GUESTFS_PROC_NR_PROCS\n";
4450   pr "};\n";
4451   pr "\n";
4452
4453   (* Having to choose a maximum message size is annoying for several
4454    * reasons (it limits what we can do in the API), but it (a) makes
4455    * the protocol a lot simpler, and (b) provides a bound on the size
4456    * of the daemon which operates in limited memory space.  For large
4457    * file transfers you should use FTP.
4458    *)
4459   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
4460   pr "\n";
4461
4462   (* Message header, etc. *)
4463   pr "\
4464 /* The communication protocol is now documented in the guestfs(3)
4465  * manpage.
4466  */
4467
4468 const GUESTFS_PROGRAM = 0x2000F5F5;
4469 const GUESTFS_PROTOCOL_VERSION = 1;
4470
4471 /* These constants must be larger than any possible message length. */
4472 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
4473 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
4474
4475 enum guestfs_message_direction {
4476   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
4477   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
4478 };
4479
4480 enum guestfs_message_status {
4481   GUESTFS_STATUS_OK = 0,
4482   GUESTFS_STATUS_ERROR = 1
4483 };
4484
4485 const GUESTFS_ERROR_LEN = 256;
4486
4487 struct guestfs_message_error {
4488   string error_message<GUESTFS_ERROR_LEN>;
4489 };
4490
4491 struct guestfs_message_header {
4492   unsigned prog;                     /* GUESTFS_PROGRAM */
4493   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
4494   guestfs_procedure proc;            /* GUESTFS_PROC_x */
4495   guestfs_message_direction direction;
4496   unsigned serial;                   /* message serial number */
4497   guestfs_message_status status;
4498 };
4499
4500 const GUESTFS_MAX_CHUNK_SIZE = 8192;
4501
4502 struct guestfs_chunk {
4503   int cancel;                        /* if non-zero, transfer is cancelled */
4504   /* data size is 0 bytes if the transfer has finished successfully */
4505   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
4506 };
4507 "
4508
4509 (* Generate the guestfs-structs.h file. *)
4510 and generate_structs_h () =
4511   generate_header CStyle LGPLv2;
4512
4513   (* This is a public exported header file containing various
4514    * structures.  The structures are carefully written to have
4515    * exactly the same in-memory format as the XDR structures that
4516    * we use on the wire to the daemon.  The reason for creating
4517    * copies of these structures here is just so we don't have to
4518    * export the whole of guestfs_protocol.h (which includes much
4519    * unrelated and XDR-dependent stuff that we don't want to be
4520    * public, or required by clients).
4521    *
4522    * To reiterate, we will pass these structures to and from the
4523    * client with a simple assignment or memcpy, so the format
4524    * must be identical to what rpcgen / the RFC defines.
4525    *)
4526
4527   (* Public structures. *)
4528   List.iter (
4529     fun (typ, cols) ->
4530       pr "struct guestfs_%s {\n" typ;
4531       List.iter (
4532         function
4533         | name, FChar -> pr "  char %s;\n" name
4534         | name, FString -> pr "  char *%s;\n" name
4535         | name, FBuffer ->
4536             pr "  uint32_t %s_len;\n" name;
4537             pr "  char *%s;\n" name
4538         | name, FUUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
4539         | name, FUInt32 -> pr "  uint32_t %s;\n" name
4540         | name, FInt32 -> pr "  int32_t %s;\n" name
4541         | name, (FUInt64|FBytes) -> pr "  uint64_t %s;\n" name
4542         | name, FInt64 -> pr "  int64_t %s;\n" name
4543         | name, FOptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
4544       ) cols;
4545       pr "};\n";
4546       pr "\n";
4547       pr "struct guestfs_%s_list {\n" typ;
4548       pr "  uint32_t len;\n";
4549       pr "  struct guestfs_%s *val;\n" typ;
4550       pr "};\n";
4551       pr "\n";
4552       pr "extern void guestfs_free_%s (struct guestfs_%s *);\n" typ typ;
4553       pr "extern void guestfs_free_%s_list (struct guestfs_%s_list *);\n" typ typ;
4554       pr "\n"
4555   ) structs
4556
4557 (* Generate the guestfs-actions.h file. *)
4558 and generate_actions_h () =
4559   generate_header CStyle LGPLv2;
4560   List.iter (
4561     fun (shortname, style, _, _, _, _, _) ->
4562       let name = "guestfs_" ^ shortname in
4563       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
4564         name style
4565   ) all_functions
4566
4567 (* Generate the guestfs-internal-actions.h file. *)
4568 and generate_internal_actions_h () =
4569   generate_header CStyle LGPLv2;
4570   List.iter (
4571     fun (shortname, style, _, _, _, _, _) ->
4572       let name = "guestfs__" ^ shortname in
4573       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
4574         name style
4575   ) non_daemon_functions
4576
4577 (* Generate the client-side dispatch stubs. *)
4578 and generate_client_actions () =
4579   generate_header CStyle LGPLv2;
4580
4581   pr "\
4582 #include <stdio.h>
4583 #include <stdlib.h>
4584
4585 #include \"guestfs.h\"
4586 #include \"guestfs-internal-actions.h\"
4587 #include \"guestfs_protocol.h\"
4588
4589 #define error guestfs_error
4590 //#define perrorf guestfs_perrorf
4591 //#define safe_malloc guestfs_safe_malloc
4592 #define safe_realloc guestfs_safe_realloc
4593 //#define safe_strdup guestfs_safe_strdup
4594 #define safe_memdup guestfs_safe_memdup
4595
4596 /* Check the return message from a call for validity. */
4597 static int
4598 check_reply_header (guestfs_h *g,
4599                     const struct guestfs_message_header *hdr,
4600                     unsigned int proc_nr, unsigned int serial)
4601 {
4602   if (hdr->prog != GUESTFS_PROGRAM) {
4603     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
4604     return -1;
4605   }
4606   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
4607     error (g, \"wrong protocol version (%%d/%%d)\",
4608            hdr->vers, GUESTFS_PROTOCOL_VERSION);
4609     return -1;
4610   }
4611   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
4612     error (g, \"unexpected message direction (%%d/%%d)\",
4613            hdr->direction, GUESTFS_DIRECTION_REPLY);
4614     return -1;
4615   }
4616   if (hdr->proc != proc_nr) {
4617     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
4618     return -1;
4619   }
4620   if (hdr->serial != serial) {
4621     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
4622     return -1;
4623   }
4624
4625   return 0;
4626 }
4627
4628 /* Check we are in the right state to run a high-level action. */
4629 static int
4630 check_state (guestfs_h *g, const char *caller)
4631 {
4632   if (!guestfs__is_ready (g)) {
4633     if (guestfs__is_config (g) || guestfs__is_launching (g))
4634       error (g, \"%%s: call launch before using this function\\n(in guestfish, don't forget to use the 'run' command)\",
4635         caller);
4636     else
4637       error (g, \"%%s called from the wrong state, %%d != READY\",
4638         caller, guestfs__get_state (g));
4639     return -1;
4640   }
4641   return 0;
4642 }
4643
4644 ";
4645
4646   (* Generate code to generate guestfish call traces. *)
4647   let trace_call shortname style =
4648     pr "  if (guestfs__get_trace (g)) {\n";
4649
4650     let needs_i =
4651       List.exists (function
4652                    | StringList _ | DeviceList _ -> true
4653                    | _ -> false) (snd style) in
4654     if needs_i then (
4655       pr "    int i;\n";
4656       pr "\n"
4657     );
4658
4659     pr "    printf (\"%s\");\n" shortname;
4660     List.iter (
4661       function
4662       | String n                        (* strings *)
4663       | Device n
4664       | Pathname n
4665       | Dev_or_Path n
4666       | FileIn n
4667       | FileOut n ->
4668           (* guestfish doesn't support string escaping, so neither do we *)
4669           pr "    printf (\" \\\"%%s\\\"\", %s);\n" n
4670       | OptString n ->                  (* string option *)
4671           pr "    if (%s) printf (\" \\\"%%s\\\"\", %s);\n" n n;
4672           pr "    else printf (\" null\");\n"
4673       | StringList n
4674       | DeviceList n ->                 (* string list *)
4675           pr "    putchar (' ');\n";
4676           pr "    putchar ('\"');\n";
4677           pr "    for (i = 0; %s[i]; ++i) {\n" n;
4678           pr "      if (i > 0) putchar (' ');\n";
4679           pr "      fputs (%s[i], stdout);\n" n;
4680           pr "    }\n";
4681           pr "    putchar ('\"');\n";
4682       | Bool n ->                       (* boolean *)
4683           pr "    fputs (%s ? \" true\" : \" false\", stdout);\n" n
4684       | Int n ->                        (* int *)
4685           pr "    printf (\" %%d\", %s);\n" n
4686     ) (snd style);
4687     pr "    putchar ('\\n');\n";
4688     pr "  }\n";
4689     pr "\n";
4690   in
4691
4692   (* For non-daemon functions, generate a wrapper around each function. *)
4693   List.iter (
4694     fun (shortname, style, _, _, _, _, _) ->
4695       let name = "guestfs_" ^ shortname in
4696
4697       generate_prototype ~extern:false ~semicolon:false ~newline:true
4698         ~handle:"g" name style;
4699       pr "{\n";
4700       trace_call shortname style;
4701       pr "  return guestfs__%s " shortname;
4702       generate_c_call_args ~handle:"g" style;
4703       pr ";\n";
4704       pr "}\n";
4705       pr "\n"
4706   ) non_daemon_functions;
4707
4708   (* Client-side stubs for each function. *)
4709   List.iter (
4710     fun (shortname, style, _, _, _, _, _) ->
4711       let name = "guestfs_" ^ shortname in
4712
4713       (* Generate the action stub. *)
4714       generate_prototype ~extern:false ~semicolon:false ~newline:true
4715         ~handle:"g" name style;
4716
4717       let error_code =
4718         match fst style with
4719         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
4720         | RConstString _ | RConstOptString _ ->
4721             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4722         | RString _ | RStringList _
4723         | RStruct _ | RStructList _
4724         | RHashtable _ | RBufferOut _ ->
4725             "NULL" in
4726
4727       pr "{\n";
4728
4729       (match snd style with
4730        | [] -> ()
4731        | _ -> pr "  struct %s_args args;\n" name
4732       );
4733
4734       pr "  guestfs_message_header hdr;\n";
4735       pr "  guestfs_message_error err;\n";
4736       let has_ret =
4737         match fst style with
4738         | RErr -> false
4739         | RConstString _ | RConstOptString _ ->
4740             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4741         | RInt _ | RInt64 _
4742         | RBool _ | RString _ | RStringList _
4743         | RStruct _ | RStructList _
4744         | RHashtable _ | RBufferOut _ ->
4745             pr "  struct %s_ret ret;\n" name;
4746             true in
4747
4748       pr "  int serial;\n";
4749       pr "  int r;\n";
4750       pr "\n";
4751       trace_call shortname style;
4752       pr "  if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
4753       pr "  guestfs___set_busy (g);\n";
4754       pr "\n";
4755
4756       (* Send the main header and arguments. *)
4757       (match snd style with
4758        | [] ->
4759            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s, NULL, NULL);\n"
4760              (String.uppercase shortname)
4761        | args ->
4762            List.iter (
4763              function
4764              | Pathname n | Device n | Dev_or_Path n | String n ->
4765                  pr "  args.%s = (char *) %s;\n" n n
4766              | OptString n ->
4767                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
4768              | StringList n | DeviceList n ->
4769                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
4770                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
4771              | Bool n ->
4772                  pr "  args.%s = %s;\n" n n
4773              | Int n ->
4774                  pr "  args.%s = %s;\n" n n
4775              | FileIn _ | FileOut _ -> ()
4776            ) args;
4777            pr "  serial = guestfs___send (g, GUESTFS_PROC_%s,\n"
4778              (String.uppercase shortname);
4779            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
4780              name;
4781       );
4782       pr "  if (serial == -1) {\n";
4783       pr "    guestfs___end_busy (g);\n";
4784       pr "    return %s;\n" error_code;
4785       pr "  }\n";
4786       pr "\n";
4787
4788       (* Send any additional files (FileIn) requested. *)
4789       let need_read_reply_label = ref false in
4790       List.iter (
4791         function
4792         | FileIn n ->
4793             pr "  r = guestfs___send_file (g, %s);\n" n;
4794             pr "  if (r == -1) {\n";
4795             pr "    guestfs___end_busy (g);\n";
4796             pr "    return %s;\n" error_code;
4797             pr "  }\n";
4798             pr "  if (r == -2) /* daemon cancelled */\n";
4799             pr "    goto read_reply;\n";
4800             need_read_reply_label := true;
4801             pr "\n";
4802         | _ -> ()
4803       ) (snd style);
4804
4805       (* Wait for the reply from the remote end. *)
4806       if !need_read_reply_label then pr " read_reply:\n";
4807       pr "  memset (&hdr, 0, sizeof hdr);\n";
4808       pr "  memset (&err, 0, sizeof err);\n";
4809       if has_ret then pr "  memset (&ret, 0, sizeof ret);\n";
4810       pr "\n";
4811       pr "  r = guestfs___recv (g, \"%s\", &hdr, &err,\n        " shortname;
4812       if not has_ret then
4813         pr "NULL, NULL"
4814       else
4815         pr "(xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret" shortname;
4816       pr ");\n";
4817
4818       pr "  if (r == -1) {\n";
4819       pr "    guestfs___end_busy (g);\n";
4820       pr "    return %s;\n" error_code;
4821       pr "  }\n";
4822       pr "\n";
4823
4824       pr "  if (check_reply_header (g, &hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
4825         (String.uppercase shortname);
4826       pr "    guestfs___end_busy (g);\n";
4827       pr "    return %s;\n" error_code;
4828       pr "  }\n";
4829       pr "\n";
4830
4831       pr "  if (hdr.status == GUESTFS_STATUS_ERROR) {\n";
4832       pr "    error (g, \"%%s: %%s\", \"%s\", err.error_message);\n" shortname;
4833       pr "    free (err.error_message);\n";
4834       pr "    guestfs___end_busy (g);\n";
4835       pr "    return %s;\n" error_code;
4836       pr "  }\n";
4837       pr "\n";
4838
4839       (* Expecting to receive further files (FileOut)? *)
4840       List.iter (
4841         function
4842         | FileOut n ->
4843             pr "  if (guestfs___recv_file (g, %s) == -1) {\n" n;
4844             pr "    guestfs___end_busy (g);\n";
4845             pr "    return %s;\n" error_code;
4846             pr "  }\n";
4847             pr "\n";
4848         | _ -> ()
4849       ) (snd style);
4850
4851       pr "  guestfs___end_busy (g);\n";
4852
4853       (match fst style with
4854        | RErr -> pr "  return 0;\n"
4855        | RInt n | RInt64 n | RBool n ->
4856            pr "  return ret.%s;\n" n
4857        | RConstString _ | RConstOptString _ ->
4858            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4859        | RString n ->
4860            pr "  return ret.%s; /* caller will free */\n" n
4861        | RStringList n | RHashtable n ->
4862            pr "  /* caller will free this, but we need to add a NULL entry */\n";
4863            pr "  ret.%s.%s_val =\n" n n;
4864            pr "    safe_realloc (g, ret.%s.%s_val,\n" n n;
4865            pr "                  sizeof (char *) * (ret.%s.%s_len + 1));\n"
4866              n n;
4867            pr "  ret.%s.%s_val[ret.%s.%s_len] = NULL;\n" n n n n;
4868            pr "  return ret.%s.%s_val;\n" n n
4869        | RStruct (n, _) ->
4870            pr "  /* caller will free this */\n";
4871            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
4872        | RStructList (n, _) ->
4873            pr "  /* caller will free this */\n";
4874            pr "  return safe_memdup (g, &ret.%s, sizeof (ret.%s));\n" n n
4875        | RBufferOut n ->
4876            pr "  *size_r = ret.%s.%s_len;\n" n n;
4877            pr "  return ret.%s.%s_val; /* caller will free */\n" n n
4878       );
4879
4880       pr "}\n\n"
4881   ) daemon_functions;
4882
4883   (* Functions to free structures. *)
4884   pr "/* Structure-freeing functions.  These rely on the fact that the\n";
4885   pr " * structure format is identical to the XDR format.  See note in\n";
4886   pr " * generator.ml.\n";
4887   pr " */\n";
4888   pr "\n";
4889
4890   List.iter (
4891     fun (typ, _) ->
4892       pr "void\n";
4893       pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
4894       pr "{\n";
4895       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
4896       pr "  free (x);\n";
4897       pr "}\n";
4898       pr "\n";
4899
4900       pr "void\n";
4901       pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
4902       pr "{\n";
4903       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
4904       pr "  free (x);\n";
4905       pr "}\n";
4906       pr "\n";
4907
4908   ) structs;
4909
4910 (* Generate daemon/actions.h. *)
4911 and generate_daemon_actions_h () =
4912   generate_header CStyle GPLv2;
4913
4914   pr "#include \"../src/guestfs_protocol.h\"\n";
4915   pr "\n";
4916
4917   List.iter (
4918     fun (name, style, _, _, _, _, _) ->
4919       generate_prototype
4920         ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
4921         name style;
4922   ) daemon_functions
4923
4924 (* Generate the server-side stubs. *)
4925 and generate_daemon_actions () =
4926   generate_header CStyle GPLv2;
4927
4928   pr "#include <config.h>\n";
4929   pr "\n";
4930   pr "#include <stdio.h>\n";
4931   pr "#include <stdlib.h>\n";
4932   pr "#include <string.h>\n";
4933   pr "#include <inttypes.h>\n";
4934   pr "#include <ctype.h>\n";
4935   pr "#include <rpc/types.h>\n";
4936   pr "#include <rpc/xdr.h>\n";
4937   pr "\n";
4938   pr "#include \"daemon.h\"\n";
4939   pr "#include \"../src/guestfs_protocol.h\"\n";
4940   pr "#include \"actions.h\"\n";
4941   pr "\n";
4942
4943   List.iter (
4944     fun (name, style, _, _, _, _, _) ->
4945       (* Generate server-side stubs. *)
4946       pr "static void %s_stub (XDR *xdr_in)\n" name;
4947       pr "{\n";
4948       let error_code =
4949         match fst style with
4950         | RErr | RInt _ -> pr "  int r;\n"; "-1"
4951         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
4952         | RBool _ -> pr "  int r;\n"; "-1"
4953         | RConstString _ | RConstOptString _ ->
4954             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4955         | RString _ -> pr "  char *r;\n"; "NULL"
4956         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
4957         | RStruct (_, typ) -> pr "  guestfs_int_%s *r;\n" typ; "NULL"
4958         | RStructList (_, typ) -> pr "  guestfs_int_%s_list *r;\n" typ; "NULL"
4959         | RBufferOut _ ->
4960             pr "  size_t size;\n";
4961             pr "  char *r;\n";
4962             "NULL" in
4963
4964       (match snd style with
4965        | [] -> ()
4966        | args ->
4967            pr "  struct guestfs_%s_args args;\n" name;
4968            List.iter (
4969              function
4970              | Device n | Dev_or_Path n
4971              | Pathname n
4972              | String n -> ()
4973              | OptString n -> pr "  char *%s;\n" n
4974              | StringList n | DeviceList n -> pr "  char **%s;\n" n
4975              | Bool n -> pr "  int %s;\n" n
4976              | Int n -> pr "  int %s;\n" n
4977              | FileIn _ | FileOut _ -> ()
4978            ) args
4979       );
4980       pr "\n";
4981
4982       (match snd style with
4983        | [] -> ()
4984        | args ->
4985            pr "  memset (&args, 0, sizeof args);\n";
4986            pr "\n";
4987            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
4988            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
4989            pr "    return;\n";
4990            pr "  }\n";
4991            let pr_args n =
4992              pr "  char *%s = args.%s;\n" n n
4993            in
4994            let pr_list_handling_code n =
4995              pr "  %s = realloc (args.%s.%s_val,\n" n n n;
4996              pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
4997              pr "  if (%s == NULL) {\n" n;
4998              pr "    reply_with_perror (\"realloc\");\n";
4999              pr "    goto done;\n";
5000              pr "  }\n";
5001              pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
5002              pr "  args.%s.%s_val = %s;\n" n n n;
5003            in
5004            List.iter (
5005              function
5006              | Pathname n ->
5007                  pr_args n;
5008                  pr "  ABS_PATH (%s, goto done);\n" n;
5009              | Device n ->
5010                  pr_args n;
5011                  pr "  RESOLVE_DEVICE (%s, goto done);\n" n;
5012              | Dev_or_Path n ->
5013                  pr_args n;
5014                  pr "  REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, goto done);\n" n;
5015              | String n -> pr_args n
5016              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
5017              | StringList n ->
5018                  pr_list_handling_code n;
5019              | DeviceList n ->
5020                  pr_list_handling_code n;
5021                  pr "  /* Ensure that each is a device,\n";
5022                  pr "   * and perform device name translation. */\n";
5023                  pr "  { int pvi; for (pvi = 0; physvols[pvi] != NULL; ++pvi)\n";
5024                  pr "    RESOLVE_DEVICE (physvols[pvi], goto done);\n";
5025                  pr "  }\n";
5026              | Bool n -> pr "  %s = args.%s;\n" n n
5027              | Int n -> pr "  %s = args.%s;\n" n n
5028              | FileIn _ | FileOut _ -> ()
5029            ) args;
5030            pr "\n"
5031       );
5032
5033
5034       (* this is used at least for do_equal *)
5035       if List.exists (function Pathname _ -> true | _ -> false) (snd style) then (
5036         (* Emit NEED_ROOT just once, even when there are two or
5037            more Pathname args *)
5038         pr "  NEED_ROOT (goto done);\n";
5039       );
5040
5041       (* Don't want to call the impl with any FileIn or FileOut
5042        * parameters, since these go "outside" the RPC protocol.
5043        *)
5044       let args' =
5045         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
5046           (snd style) in
5047       pr "  r = do_%s " name;
5048       generate_c_call_args (fst style, args');
5049       pr ";\n";
5050
5051       pr "  if (r == %s)\n" error_code;
5052       pr "    /* do_%s has already called reply_with_error */\n" name;
5053       pr "    goto done;\n";
5054       pr "\n";
5055
5056       (* If there are any FileOut parameters, then the impl must
5057        * send its own reply.
5058        *)
5059       let no_reply =
5060         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
5061       if no_reply then
5062         pr "  /* do_%s has already sent a reply */\n" name
5063       else (
5064         match fst style with
5065         | RErr -> pr "  reply (NULL, NULL);\n"
5066         | RInt n | RInt64 n | RBool n ->
5067             pr "  struct guestfs_%s_ret ret;\n" name;
5068             pr "  ret.%s = r;\n" n;
5069             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5070               name
5071         | RConstString _ | RConstOptString _ ->
5072             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
5073         | RString n ->
5074             pr "  struct guestfs_%s_ret ret;\n" name;
5075             pr "  ret.%s = r;\n" n;
5076             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5077               name;
5078             pr "  free (r);\n"
5079         | RStringList n | RHashtable n ->
5080             pr "  struct guestfs_%s_ret ret;\n" name;
5081             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
5082             pr "  ret.%s.%s_val = r;\n" n n;
5083             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5084               name;
5085             pr "  free_strings (r);\n"
5086         | RStruct (n, _) ->
5087             pr "  struct guestfs_%s_ret ret;\n" name;
5088             pr "  ret.%s = *r;\n" n;
5089             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5090               name;
5091             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5092               name
5093         | RStructList (n, _) ->
5094             pr "  struct guestfs_%s_ret ret;\n" name;
5095             pr "  ret.%s = *r;\n" n;
5096             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5097               name;
5098             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
5099               name
5100         | RBufferOut n ->
5101             pr "  struct guestfs_%s_ret ret;\n" name;
5102             pr "  ret.%s.%s_val = r;\n" n n;
5103             pr "  ret.%s.%s_len = size;\n" n n;
5104             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
5105               name;
5106             pr "  free (r);\n"
5107       );
5108
5109       (* Free the args. *)
5110       (match snd style with
5111        | [] ->
5112            pr "done: ;\n";
5113        | _ ->
5114            pr "done:\n";
5115            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
5116              name
5117       );
5118
5119       pr "}\n\n";
5120   ) daemon_functions;
5121
5122   (* Dispatch function. *)
5123   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
5124   pr "{\n";
5125   pr "  switch (proc_nr) {\n";
5126
5127   List.iter (
5128     fun (name, style, _, _, _, _, _) ->
5129       pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
5130       pr "      %s_stub (xdr_in);\n" name;
5131       pr "      break;\n"
5132   ) daemon_functions;
5133
5134   pr "    default:\n";
5135   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";
5136   pr "  }\n";
5137   pr "}\n";
5138   pr "\n";
5139
5140   (* LVM columns and tokenization functions. *)
5141   (* XXX This generates crap code.  We should rethink how we
5142    * do this parsing.
5143    *)
5144   List.iter (
5145     function
5146     | typ, cols ->
5147         pr "static const char *lvm_%s_cols = \"%s\";\n"
5148           typ (String.concat "," (List.map fst cols));
5149         pr "\n";
5150
5151         pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
5152         pr "{\n";
5153         pr "  char *tok, *p, *next;\n";
5154         pr "  int i, j;\n";
5155         pr "\n";
5156         (*
5157           pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
5158           pr "\n";
5159         *)
5160         pr "  if (!str) {\n";
5161         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
5162         pr "    return -1;\n";
5163         pr "  }\n";
5164         pr "  if (!*str || isspace (*str)) {\n";
5165         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
5166         pr "    return -1;\n";
5167         pr "  }\n";
5168         pr "  tok = str;\n";
5169         List.iter (
5170           fun (name, coltype) ->
5171             pr "  if (!tok) {\n";
5172             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
5173             pr "    return -1;\n";
5174             pr "  }\n";
5175             pr "  p = strchrnul (tok, ',');\n";
5176             pr "  if (*p) next = p+1; else next = NULL;\n";
5177             pr "  *p = '\\0';\n";
5178             (match coltype with
5179              | FString ->
5180                  pr "  r->%s = strdup (tok);\n" name;
5181                  pr "  if (r->%s == NULL) {\n" name;
5182                  pr "    perror (\"strdup\");\n";
5183                  pr "    return -1;\n";
5184                  pr "  }\n"
5185              | FUUID ->
5186                  pr "  for (i = j = 0; i < 32; ++j) {\n";
5187                  pr "    if (tok[j] == '\\0') {\n";
5188                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
5189                  pr "      return -1;\n";
5190                  pr "    } else if (tok[j] != '-')\n";
5191                  pr "      r->%s[i++] = tok[j];\n" name;
5192                  pr "  }\n";
5193              | FBytes ->
5194                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
5195                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
5196                  pr "    return -1;\n";
5197                  pr "  }\n";
5198              | FInt64 ->
5199                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
5200                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
5201                  pr "    return -1;\n";
5202                  pr "  }\n";
5203              | FOptPercent ->
5204                  pr "  if (tok[0] == '\\0')\n";
5205                  pr "    r->%s = -1;\n" name;
5206                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
5207                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
5208                  pr "    return -1;\n";
5209                  pr "  }\n";
5210              | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
5211                  assert false (* can never be an LVM column *)
5212             );
5213             pr "  tok = next;\n";
5214         ) cols;
5215
5216         pr "  if (tok != NULL) {\n";
5217         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
5218         pr "    return -1;\n";
5219         pr "  }\n";
5220         pr "  return 0;\n";
5221         pr "}\n";
5222         pr "\n";
5223
5224         pr "guestfs_int_lvm_%s_list *\n" typ;
5225         pr "parse_command_line_%ss (void)\n" typ;
5226         pr "{\n";
5227         pr "  char *out, *err;\n";
5228         pr "  char *p, *pend;\n";
5229         pr "  int r, i;\n";
5230         pr "  guestfs_int_lvm_%s_list *ret;\n" typ;
5231         pr "  void *newp;\n";
5232         pr "\n";
5233         pr "  ret = malloc (sizeof *ret);\n";
5234         pr "  if (!ret) {\n";
5235         pr "    reply_with_perror (\"malloc\");\n";
5236         pr "    return NULL;\n";
5237         pr "  }\n";
5238         pr "\n";
5239         pr "  ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
5240         pr "  ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
5241         pr "\n";
5242         pr "  r = command (&out, &err,\n";
5243         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
5244         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
5245         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
5246         pr "  if (r == -1) {\n";
5247         pr "    reply_with_error (\"%%s\", err);\n";
5248         pr "    free (out);\n";
5249         pr "    free (err);\n";
5250         pr "    free (ret);\n";
5251         pr "    return NULL;\n";
5252         pr "  }\n";
5253         pr "\n";
5254         pr "  free (err);\n";
5255         pr "\n";
5256         pr "  /* Tokenize each line of the output. */\n";
5257         pr "  p = out;\n";
5258         pr "  i = 0;\n";
5259         pr "  while (p) {\n";
5260         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
5261         pr "    if (pend) {\n";
5262         pr "      *pend = '\\0';\n";
5263         pr "      pend++;\n";
5264         pr "    }\n";
5265         pr "\n";
5266         pr "    while (*p && isspace (*p))      /* Skip any leading whitespace. */\n";
5267         pr "      p++;\n";
5268         pr "\n";
5269         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
5270         pr "      p = pend;\n";
5271         pr "      continue;\n";
5272         pr "    }\n";
5273         pr "\n";
5274         pr "    /* Allocate some space to store this next entry. */\n";
5275         pr "    newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
5276         pr "                sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
5277         pr "    if (newp == NULL) {\n";
5278         pr "      reply_with_perror (\"realloc\");\n";
5279         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
5280         pr "      free (ret);\n";
5281         pr "      free (out);\n";
5282         pr "      return NULL;\n";
5283         pr "    }\n";
5284         pr "    ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
5285         pr "\n";
5286         pr "    /* Tokenize the next entry. */\n";
5287         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
5288         pr "    if (r == -1) {\n";
5289         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
5290         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
5291         pr "      free (ret);\n";
5292         pr "      free (out);\n";
5293         pr "      return NULL;\n";
5294         pr "    }\n";
5295         pr "\n";
5296         pr "    ++i;\n";
5297         pr "    p = pend;\n";
5298         pr "  }\n";
5299         pr "\n";
5300         pr "  ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
5301         pr "\n";
5302         pr "  free (out);\n";
5303         pr "  return ret;\n";
5304         pr "}\n"
5305
5306   ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
5307
5308 (* Generate a list of function names, for debugging in the daemon.. *)
5309 and generate_daemon_names () =
5310   generate_header CStyle GPLv2;
5311
5312   pr "#include <config.h>\n";
5313   pr "\n";
5314   pr "#include \"daemon.h\"\n";
5315   pr "\n";
5316
5317   pr "/* This array is indexed by proc_nr.  See guestfs_protocol.x. */\n";
5318   pr "const char *function_names[] = {\n";
5319   List.iter (
5320     fun (name, _, proc_nr, _, _, _, _) -> pr "  [%d] = \"%s\",\n" proc_nr name
5321   ) daemon_functions;
5322   pr "};\n";
5323
5324 (* Generate the tests. *)
5325 and generate_tests () =
5326   generate_header CStyle GPLv2;
5327
5328   pr "\
5329 #include <stdio.h>
5330 #include <stdlib.h>
5331 #include <string.h>
5332 #include <unistd.h>
5333 #include <sys/types.h>
5334 #include <fcntl.h>
5335
5336 #include \"guestfs.h\"
5337
5338 static guestfs_h *g;
5339 static int suppress_error = 0;
5340
5341 static void print_error (guestfs_h *g, void *data, const char *msg)
5342 {
5343   if (!suppress_error)
5344     fprintf (stderr, \"%%s\\n\", msg);
5345 }
5346
5347 /* FIXME: nearly identical code appears in fish.c */
5348 static void print_strings (char *const *argv)
5349 {
5350   int argc;
5351
5352   for (argc = 0; argv[argc] != NULL; ++argc)
5353     printf (\"\\t%%s\\n\", argv[argc]);
5354 }
5355
5356 /*
5357 static void print_table (char const *const *argv)
5358 {
5359   int i;
5360
5361   for (i = 0; argv[i] != NULL; i += 2)
5362     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
5363 }
5364 */
5365
5366 ";
5367
5368   (* Generate a list of commands which are not tested anywhere. *)
5369   pr "static void no_test_warnings (void)\n";
5370   pr "{\n";
5371
5372   let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
5373   List.iter (
5374     fun (_, _, _, _, tests, _, _) ->
5375       let tests = filter_map (
5376         function
5377         | (_, (Always|If _|Unless _), test) -> Some test
5378         | (_, Disabled, _) -> None
5379       ) tests in
5380       let seq = List.concat (List.map seq_of_test tests) in
5381       let cmds_tested = List.map List.hd seq in
5382       List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
5383   ) all_functions;
5384
5385   List.iter (
5386     fun (name, _, _, _, _, _, _) ->
5387       if not (Hashtbl.mem hash name) then
5388         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
5389   ) all_functions;
5390
5391   pr "}\n";
5392   pr "\n";
5393
5394   (* Generate the actual tests.  Note that we generate the tests
5395    * in reverse order, deliberately, so that (in general) the
5396    * newest tests run first.  This makes it quicker and easier to
5397    * debug them.
5398    *)
5399   let test_names =
5400     List.map (
5401       fun (name, _, _, _, tests, _, _) ->
5402         mapi (generate_one_test name) tests
5403     ) (List.rev all_functions) in
5404   let test_names = List.concat test_names in
5405   let nr_tests = List.length test_names in
5406
5407   pr "\
5408 int main (int argc, char *argv[])
5409 {
5410   char c = 0;
5411   unsigned long int n_failed = 0;
5412   const char *filename;
5413   int fd;
5414   int nr_tests, test_num = 0;
5415
5416   setbuf (stdout, NULL);
5417
5418   no_test_warnings ();
5419
5420   g = guestfs_create ();
5421   if (g == NULL) {
5422     printf (\"guestfs_create FAILED\\n\");
5423     exit (1);
5424   }
5425
5426   guestfs_set_error_handler (g, print_error, NULL);
5427
5428   guestfs_set_path (g, \"../appliance\");
5429
5430   filename = \"test1.img\";
5431   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
5432   if (fd == -1) {
5433     perror (filename);
5434     exit (1);
5435   }
5436   if (lseek (fd, %d, SEEK_SET) == -1) {
5437     perror (\"lseek\");
5438     close (fd);
5439     unlink (filename);
5440     exit (1);
5441   }
5442   if (write (fd, &c, 1) == -1) {
5443     perror (\"write\");
5444     close (fd);
5445     unlink (filename);
5446     exit (1);
5447   }
5448   if (close (fd) == -1) {
5449     perror (filename);
5450     unlink (filename);
5451     exit (1);
5452   }
5453   if (guestfs_add_drive (g, filename) == -1) {
5454     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
5455     exit (1);
5456   }
5457
5458   filename = \"test2.img\";
5459   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
5460   if (fd == -1) {
5461     perror (filename);
5462     exit (1);
5463   }
5464   if (lseek (fd, %d, SEEK_SET) == -1) {
5465     perror (\"lseek\");
5466     close (fd);
5467     unlink (filename);
5468     exit (1);
5469   }
5470   if (write (fd, &c, 1) == -1) {
5471     perror (\"write\");
5472     close (fd);
5473     unlink (filename);
5474     exit (1);
5475   }
5476   if (close (fd) == -1) {
5477     perror (filename);
5478     unlink (filename);
5479     exit (1);
5480   }
5481   if (guestfs_add_drive (g, filename) == -1) {
5482     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
5483     exit (1);
5484   }
5485
5486   filename = \"test3.img\";
5487   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
5488   if (fd == -1) {
5489     perror (filename);
5490     exit (1);
5491   }
5492   if (lseek (fd, %d, SEEK_SET) == -1) {
5493     perror (\"lseek\");
5494     close (fd);
5495     unlink (filename);
5496     exit (1);
5497   }
5498   if (write (fd, &c, 1) == -1) {
5499     perror (\"write\");
5500     close (fd);
5501     unlink (filename);
5502     exit (1);
5503   }
5504   if (close (fd) == -1) {
5505     perror (filename);
5506     unlink (filename);
5507     exit (1);
5508   }
5509   if (guestfs_add_drive (g, filename) == -1) {
5510     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
5511     exit (1);
5512   }
5513
5514   if (guestfs_add_drive_ro (g, \"../images/test.iso\") == -1) {
5515     printf (\"guestfs_add_drive_ro ../images/test.iso FAILED\\n\");
5516     exit (1);
5517   }
5518
5519   if (guestfs_launch (g) == -1) {
5520     printf (\"guestfs_launch FAILED\\n\");
5521     exit (1);
5522   }
5523
5524   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
5525   alarm (600);
5526
5527   /* Cancel previous alarm. */
5528   alarm (0);
5529
5530   nr_tests = %d;
5531
5532 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
5533
5534   iteri (
5535     fun i test_name ->
5536       pr "  test_num++;\n";
5537       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
5538       pr "  if (%s () == -1) {\n" test_name;
5539       pr "    printf (\"%s FAILED\\n\");\n" test_name;
5540       pr "    n_failed++;\n";
5541       pr "  }\n";
5542   ) test_names;
5543   pr "\n";
5544
5545   pr "  guestfs_close (g);\n";
5546   pr "  unlink (\"test1.img\");\n";
5547   pr "  unlink (\"test2.img\");\n";
5548   pr "  unlink (\"test3.img\");\n";
5549   pr "\n";
5550
5551   pr "  if (n_failed > 0) {\n";
5552   pr "    printf (\"***** %%lu / %%d tests FAILED *****\\n\", n_failed, nr_tests);\n";
5553   pr "    exit (1);\n";
5554   pr "  }\n";
5555   pr "\n";
5556
5557   pr "  exit (0);\n";
5558   pr "}\n"
5559
5560 and generate_one_test name i (init, prereq, test) =
5561   let test_name = sprintf "test_%s_%d" name i in
5562
5563   pr "\
5564 static int %s_skip (void)
5565 {
5566   const char *str;
5567
5568   str = getenv (\"TEST_ONLY\");
5569   if (str)
5570     return strstr (str, \"%s\") == NULL;
5571   str = getenv (\"SKIP_%s\");
5572   if (str && strcmp (str, \"1\") == 0) return 1;
5573   str = getenv (\"SKIP_TEST_%s\");
5574   if (str && strcmp (str, \"1\") == 0) return 1;
5575   return 0;
5576 }
5577
5578 " test_name name (String.uppercase test_name) (String.uppercase name);
5579
5580   (match prereq with
5581    | Disabled | Always -> ()
5582    | If code | Unless code ->
5583        pr "static int %s_prereq (void)\n" test_name;
5584        pr "{\n";
5585        pr "  %s\n" code;
5586        pr "}\n";
5587        pr "\n";
5588   );
5589
5590   pr "\
5591 static int %s (void)
5592 {
5593   if (%s_skip ()) {
5594     printf (\"        %%s skipped (reason: environment variable set)\\n\", \"%s\");
5595     return 0;
5596   }
5597
5598 " test_name test_name test_name;
5599
5600   (match prereq with
5601    | Disabled ->
5602        pr "  printf (\"        %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
5603    | If _ ->
5604        pr "  if (! %s_prereq ()) {\n" test_name;
5605        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
5606        pr "    return 0;\n";
5607        pr "  }\n";
5608        pr "\n";
5609        generate_one_test_body name i test_name init test;
5610    | Unless _ ->
5611        pr "  if (%s_prereq ()) {\n" test_name;
5612        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
5613        pr "    return 0;\n";
5614        pr "  }\n";
5615        pr "\n";
5616        generate_one_test_body name i test_name init test;
5617    | Always ->
5618        generate_one_test_body name i test_name init test
5619   );
5620
5621   pr "  return 0;\n";
5622   pr "}\n";
5623   pr "\n";
5624   test_name
5625
5626 and generate_one_test_body name i test_name init test =
5627   (match init with
5628    | InitNone (* XXX at some point, InitNone and InitEmpty became
5629                * folded together as the same thing.  Really we should
5630                * make InitNone do nothing at all, but the tests may
5631                * need to be checked to make sure this is OK.
5632                *)
5633    | InitEmpty ->
5634        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
5635        List.iter (generate_test_command_call test_name)
5636          [["blockdev_setrw"; "/dev/sda"];
5637           ["umount_all"];
5638           ["lvm_remove_all"]]
5639    | InitPartition ->
5640        pr "  /* InitPartition for %s: create /dev/sda1 */\n" test_name;
5641        List.iter (generate_test_command_call test_name)
5642          [["blockdev_setrw"; "/dev/sda"];
5643           ["umount_all"];
5644           ["lvm_remove_all"];
5645           ["sfdiskM"; "/dev/sda"; ","]]
5646    | InitBasicFS ->
5647        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
5648        List.iter (generate_test_command_call test_name)
5649          [["blockdev_setrw"; "/dev/sda"];
5650           ["umount_all"];
5651           ["lvm_remove_all"];
5652           ["sfdiskM"; "/dev/sda"; ","];
5653           ["mkfs"; "ext2"; "/dev/sda1"];
5654           ["mount"; "/dev/sda1"; "/"]]
5655    | InitBasicFSonLVM ->
5656        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
5657          test_name;
5658        List.iter (generate_test_command_call test_name)
5659          [["blockdev_setrw"; "/dev/sda"];
5660           ["umount_all"];
5661           ["lvm_remove_all"];
5662           ["sfdiskM"; "/dev/sda"; ","];
5663           ["pvcreate"; "/dev/sda1"];
5664           ["vgcreate"; "VG"; "/dev/sda1"];
5665           ["lvcreate"; "LV"; "VG"; "8"];
5666           ["mkfs"; "ext2"; "/dev/VG/LV"];
5667           ["mount"; "/dev/VG/LV"; "/"]]
5668    | InitISOFS ->
5669        pr "  /* InitISOFS for %s */\n" test_name;
5670        List.iter (generate_test_command_call test_name)
5671          [["blockdev_setrw"; "/dev/sda"];
5672           ["umount_all"];
5673           ["lvm_remove_all"];
5674           ["mount_ro"; "/dev/sdd"; "/"]]
5675   );
5676
5677   let get_seq_last = function
5678     | [] ->
5679         failwithf "%s: you cannot use [] (empty list) when expecting a command"
5680           test_name
5681     | seq ->
5682         let seq = List.rev seq in
5683         List.rev (List.tl seq), List.hd seq
5684   in
5685
5686   match test with
5687   | TestRun seq ->
5688       pr "  /* TestRun for %s (%d) */\n" name i;
5689       List.iter (generate_test_command_call test_name) seq
5690   | TestOutput (seq, expected) ->
5691       pr "  /* TestOutput for %s (%d) */\n" name i;
5692       pr "  const char *expected = \"%s\";\n" (c_quote expected);
5693       let seq, last = get_seq_last seq in
5694       let test () =
5695         pr "    if (strcmp (r, expected) != 0) {\n";
5696         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
5697         pr "      return -1;\n";
5698         pr "    }\n"
5699       in
5700       List.iter (generate_test_command_call test_name) seq;
5701       generate_test_command_call ~test test_name last
5702   | TestOutputList (seq, expected) ->
5703       pr "  /* TestOutputList for %s (%d) */\n" name i;
5704       let seq, last = get_seq_last seq in
5705       let test () =
5706         iteri (
5707           fun i str ->
5708             pr "    if (!r[%d]) {\n" i;
5709             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
5710             pr "      print_strings (r);\n";
5711             pr "      return -1;\n";
5712             pr "    }\n";
5713             pr "    {\n";
5714             pr "      const char *expected = \"%s\";\n" (c_quote str);
5715             pr "      if (strcmp (r[%d], expected) != 0) {\n" i;
5716             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
5717             pr "        return -1;\n";
5718             pr "      }\n";
5719             pr "    }\n"
5720         ) expected;
5721         pr "    if (r[%d] != NULL) {\n" (List.length expected);
5722         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
5723           test_name;
5724         pr "      print_strings (r);\n";
5725         pr "      return -1;\n";
5726         pr "    }\n"
5727       in
5728       List.iter (generate_test_command_call test_name) seq;
5729       generate_test_command_call ~test test_name last
5730   | TestOutputListOfDevices (seq, expected) ->
5731       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
5732       let seq, last = get_seq_last seq in
5733       let test () =
5734         iteri (
5735           fun i str ->
5736             pr "    if (!r[%d]) {\n" i;
5737             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
5738             pr "      print_strings (r);\n";
5739             pr "      return -1;\n";
5740             pr "    }\n";
5741             pr "    {\n";
5742             pr "      const char *expected = \"%s\";\n" (c_quote str);
5743             pr "      r[%d][5] = 's';\n" i;
5744             pr "      if (strcmp (r[%d], expected) != 0) {\n" i;
5745             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
5746             pr "        return -1;\n";
5747             pr "      }\n";
5748             pr "    }\n"
5749         ) expected;
5750         pr "    if (r[%d] != NULL) {\n" (List.length expected);
5751         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
5752           test_name;
5753         pr "      print_strings (r);\n";
5754         pr "      return -1;\n";
5755         pr "    }\n"
5756       in
5757       List.iter (generate_test_command_call test_name) seq;
5758       generate_test_command_call ~test test_name last
5759   | TestOutputInt (seq, expected) ->
5760       pr "  /* TestOutputInt for %s (%d) */\n" name i;
5761       let seq, last = get_seq_last seq in
5762       let test () =
5763         pr "    if (r != %d) {\n" expected;
5764         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
5765           test_name expected;
5766         pr "               (int) r);\n";
5767         pr "      return -1;\n";
5768         pr "    }\n"
5769       in
5770       List.iter (generate_test_command_call test_name) seq;
5771       generate_test_command_call ~test test_name last
5772   | TestOutputIntOp (seq, op, expected) ->
5773       pr "  /* TestOutputIntOp for %s (%d) */\n" name i;
5774       let seq, last = get_seq_last seq in
5775       let test () =
5776         pr "    if (! (r %s %d)) {\n" op expected;
5777         pr "      fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
5778           test_name op expected;
5779         pr "               (int) r);\n";
5780         pr "      return -1;\n";
5781         pr "    }\n"
5782       in
5783       List.iter (generate_test_command_call test_name) seq;
5784       generate_test_command_call ~test test_name last
5785   | TestOutputTrue seq ->
5786       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
5787       let seq, last = get_seq_last seq in
5788       let test () =
5789         pr "    if (!r) {\n";
5790         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
5791           test_name;
5792         pr "      return -1;\n";
5793         pr "    }\n"
5794       in
5795       List.iter (generate_test_command_call test_name) seq;
5796       generate_test_command_call ~test test_name last
5797   | TestOutputFalse seq ->
5798       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
5799       let seq, last = get_seq_last seq in
5800       let test () =
5801         pr "    if (r) {\n";
5802         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
5803           test_name;
5804         pr "      return -1;\n";
5805         pr "    }\n"
5806       in
5807       List.iter (generate_test_command_call test_name) seq;
5808       generate_test_command_call ~test test_name last
5809   | TestOutputLength (seq, expected) ->
5810       pr "  /* TestOutputLength for %s (%d) */\n" name i;
5811       let seq, last = get_seq_last seq in
5812       let test () =
5813         pr "    int j;\n";
5814         pr "    for (j = 0; j < %d; ++j)\n" expected;
5815         pr "      if (r[j] == NULL) {\n";
5816         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
5817           test_name;
5818         pr "        print_strings (r);\n";
5819         pr "        return -1;\n";
5820         pr "      }\n";
5821         pr "    if (r[j] != NULL) {\n";
5822         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
5823           test_name;
5824         pr "      print_strings (r);\n";
5825         pr "      return -1;\n";
5826         pr "    }\n"
5827       in
5828       List.iter (generate_test_command_call test_name) seq;
5829       generate_test_command_call ~test test_name last
5830   | TestOutputBuffer (seq, expected) ->
5831       pr "  /* TestOutputBuffer for %s (%d) */\n" name i;
5832       pr "  const char *expected = \"%s\";\n" (c_quote expected);
5833       let seq, last = get_seq_last seq in
5834       let len = String.length expected in
5835       let test () =
5836         pr "    if (size != %d) {\n" len;
5837         pr "      fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
5838         pr "      return -1;\n";
5839         pr "    }\n";
5840         pr "    if (strncmp (r, expected, size) != 0) {\n";
5841         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
5842         pr "      return -1;\n";
5843         pr "    }\n"
5844       in
5845       List.iter (generate_test_command_call test_name) seq;
5846       generate_test_command_call ~test test_name last
5847   | TestOutputStruct (seq, checks) ->
5848       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
5849       let seq, last = get_seq_last seq in
5850       let test () =
5851         List.iter (
5852           function
5853           | CompareWithInt (field, expected) ->
5854               pr "    if (r->%s != %d) {\n" field expected;
5855               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
5856                 test_name field expected;
5857               pr "               (int) r->%s);\n" field;
5858               pr "      return -1;\n";
5859               pr "    }\n"
5860           | CompareWithIntOp (field, op, expected) ->
5861               pr "    if (!(r->%s %s %d)) {\n" field op expected;
5862               pr "      fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
5863                 test_name field op expected;
5864               pr "               (int) r->%s);\n" field;
5865               pr "      return -1;\n";
5866               pr "    }\n"
5867           | CompareWithString (field, expected) ->
5868               pr "    if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
5869               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
5870                 test_name field expected;
5871               pr "               r->%s);\n" field;
5872               pr "      return -1;\n";
5873               pr "    }\n"
5874           | CompareFieldsIntEq (field1, field2) ->
5875               pr "    if (r->%s != r->%s) {\n" field1 field2;
5876               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
5877                 test_name field1 field2;
5878               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
5879               pr "      return -1;\n";
5880               pr "    }\n"
5881           | CompareFieldsStrEq (field1, field2) ->
5882               pr "    if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
5883               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
5884                 test_name field1 field2;
5885               pr "               r->%s, r->%s);\n" field1 field2;
5886               pr "      return -1;\n";
5887               pr "    }\n"
5888         ) checks
5889       in
5890       List.iter (generate_test_command_call test_name) seq;
5891       generate_test_command_call ~test test_name last
5892   | TestLastFail seq ->
5893       pr "  /* TestLastFail for %s (%d) */\n" name i;
5894       let seq, last = get_seq_last seq in
5895       List.iter (generate_test_command_call test_name) seq;
5896       generate_test_command_call test_name ~expect_error:true last
5897
5898 (* Generate the code to run a command, leaving the result in 'r'.
5899  * If you expect to get an error then you should set expect_error:true.
5900  *)
5901 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
5902   match cmd with
5903   | [] -> assert false
5904   | name :: args ->
5905       (* Look up the command to find out what args/ret it has. *)
5906       let style =
5907         try
5908           let _, style, _, _, _, _, _ =
5909             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
5910           style
5911         with Not_found ->
5912           failwithf "%s: in test, command %s was not found" test_name name in
5913
5914       if List.length (snd style) <> List.length args then
5915         failwithf "%s: in test, wrong number of args given to %s"
5916           test_name name;
5917
5918       pr "  {\n";
5919
5920       List.iter (
5921         function
5922         | OptString n, "NULL" -> ()
5923         | Pathname n, arg
5924         | Device n, arg
5925         | Dev_or_Path n, arg
5926         | String n, arg
5927         | OptString n, arg ->
5928             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
5929         | Int _, _
5930         | Bool _, _
5931         | FileIn _, _ | FileOut _, _ -> ()
5932         | StringList n, arg | DeviceList n, arg ->
5933             let strs = string_split " " arg in
5934             iteri (
5935               fun i str ->
5936                 pr "    const char *%s_%d = \"%s\";\n" n i (c_quote str);
5937             ) strs;
5938             pr "    const char *const %s[] = {\n" n;
5939             iteri (
5940               fun i _ -> pr "      %s_%d,\n" n i
5941             ) strs;
5942             pr "      NULL\n";
5943             pr "    };\n";
5944       ) (List.combine (snd style) args);
5945
5946       let error_code =
5947         match fst style with
5948         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
5949         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
5950         | RConstString _ | RConstOptString _ ->
5951             pr "    const char *r;\n"; "NULL"
5952         | RString _ -> pr "    char *r;\n"; "NULL"
5953         | RStringList _ | RHashtable _ ->
5954             pr "    char **r;\n";
5955             pr "    int i;\n";
5956             "NULL"
5957         | RStruct (_, typ) ->
5958             pr "    struct guestfs_%s *r;\n" typ; "NULL"
5959         | RStructList (_, typ) ->
5960             pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
5961         | RBufferOut _ ->
5962             pr "    char *r;\n";
5963             pr "    size_t size;\n";
5964             "NULL" in
5965
5966       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
5967       pr "    r = guestfs_%s (g" name;
5968
5969       (* Generate the parameters. *)
5970       List.iter (
5971         function
5972         | OptString _, "NULL" -> pr ", NULL"
5973         | Pathname n, _
5974         | Device n, _ | Dev_or_Path n, _
5975         | String n, _
5976         | OptString n, _ ->
5977             pr ", %s" n
5978         | FileIn _, arg | FileOut _, arg ->
5979             pr ", \"%s\"" (c_quote arg)
5980         | StringList n, _ | DeviceList n, _ ->
5981             pr ", (char **) %s" n
5982         | Int _, arg ->
5983             let i =
5984               try int_of_string arg
5985               with Failure "int_of_string" ->
5986                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
5987             pr ", %d" i
5988         | Bool _, arg ->
5989             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
5990       ) (List.combine (snd style) args);
5991
5992       (match fst style with
5993        | RBufferOut _ -> pr ", &size"
5994        | _ -> ()
5995       );
5996
5997       pr ");\n";
5998
5999       if not expect_error then
6000         pr "    if (r == %s)\n" error_code
6001       else
6002         pr "    if (r != %s)\n" error_code;
6003       pr "      return -1;\n";
6004
6005       (* Insert the test code. *)
6006       (match test with
6007        | None -> ()
6008        | Some f -> f ()
6009       );
6010
6011       (match fst style with
6012        | RErr | RInt _ | RInt64 _ | RBool _
6013        | RConstString _ | RConstOptString _ -> ()
6014        | RString _ | RBufferOut _ -> pr "    free (r);\n"
6015        | RStringList _ | RHashtable _ ->
6016            pr "    for (i = 0; r[i] != NULL; ++i)\n";
6017            pr "      free (r[i]);\n";
6018            pr "    free (r);\n"
6019        | RStruct (_, typ) ->
6020            pr "    guestfs_free_%s (r);\n" typ
6021        | RStructList (_, typ) ->
6022            pr "    guestfs_free_%s_list (r);\n" typ
6023       );
6024
6025       pr "  }\n"
6026
6027 and c_quote str =
6028   let str = replace_str str "\r" "\\r" in
6029   let str = replace_str str "\n" "\\n" in
6030   let str = replace_str str "\t" "\\t" in
6031   let str = replace_str str "\000" "\\0" in
6032   str
6033
6034 (* Generate a lot of different functions for guestfish. *)
6035 and generate_fish_cmds () =
6036   generate_header CStyle GPLv2;
6037
6038   let all_functions =
6039     List.filter (
6040       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
6041     ) all_functions in
6042   let all_functions_sorted =
6043     List.filter (
6044       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
6045     ) all_functions_sorted in
6046
6047   pr "#include <stdio.h>\n";
6048   pr "#include <stdlib.h>\n";
6049   pr "#include <string.h>\n";
6050   pr "#include <inttypes.h>\n";
6051   pr "#include <ctype.h>\n";
6052   pr "\n";
6053   pr "#include <guestfs.h>\n";
6054   pr "#include \"fish.h\"\n";
6055   pr "\n";
6056
6057   (* list_commands function, which implements guestfish -h *)
6058   pr "void list_commands (void)\n";
6059   pr "{\n";
6060   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
6061   pr "  list_builtin_commands ();\n";
6062   List.iter (
6063     fun (name, _, _, flags, _, shortdesc, _) ->
6064       let name = replace_char name '_' '-' in
6065       pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
6066         name shortdesc
6067   ) all_functions_sorted;
6068   pr "  printf (\"    %%s\\n\",";
6069   pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
6070   pr "}\n";
6071   pr "\n";
6072
6073   (* display_command function, which implements guestfish -h cmd *)
6074   pr "void display_command (const char *cmd)\n";
6075   pr "{\n";
6076   List.iter (
6077     fun (name, style, _, flags, _, shortdesc, longdesc) ->
6078       let name2 = replace_char name '_' '-' in
6079       let alias =
6080         try find_map (function FishAlias n -> Some n | _ -> None) flags
6081         with Not_found -> name in
6082       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
6083       let synopsis =
6084         match snd style with
6085         | [] -> name2
6086         | args ->
6087             sprintf "%s <%s>"
6088               name2 (String.concat "> <" (List.map name_of_argt args)) in
6089
6090       let warnings =
6091         if List.mem ProtocolLimitWarning flags then
6092           ("\n\n" ^ protocol_limit_warning)
6093         else "" in
6094
6095       (* For DangerWillRobinson commands, we should probably have
6096        * guestfish prompt before allowing you to use them (especially
6097        * in interactive mode). XXX
6098        *)
6099       let warnings =
6100         warnings ^
6101           if List.mem DangerWillRobinson flags then
6102             ("\n\n" ^ danger_will_robinson)
6103           else "" in
6104
6105       let warnings =
6106         warnings ^
6107           match deprecation_notice flags with
6108           | None -> ""
6109           | Some txt -> "\n\n" ^ txt in
6110
6111       let describe_alias =
6112         if name <> alias then
6113           sprintf "\n\nYou can use '%s' as an alias for this command." alias
6114         else "" in
6115
6116       pr "  if (";
6117       pr "strcasecmp (cmd, \"%s\") == 0" name;
6118       if name <> name2 then
6119         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
6120       if name <> alias then
6121         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
6122       pr ")\n";
6123       pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
6124         name2 shortdesc
6125         (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
6126       pr "  else\n"
6127   ) all_functions;
6128   pr "    display_builtin_command (cmd);\n";
6129   pr "}\n";
6130   pr "\n";
6131
6132   let emit_print_list_function typ =
6133     pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
6134       typ typ typ;
6135     pr "{\n";
6136     pr "  unsigned int i;\n";
6137     pr "\n";
6138     pr "  for (i = 0; i < %ss->len; ++i) {\n" typ;
6139     pr "    printf (\"[%%d] = {\\n\", i);\n";
6140     pr "    print_%s_indent (&%ss->val[i], \"  \");\n" typ typ;
6141     pr "    printf (\"}\\n\");\n";
6142     pr "  }\n";
6143     pr "}\n";
6144     pr "\n";
6145   in
6146
6147   (* print_* functions *)
6148   List.iter (
6149     fun (typ, cols) ->
6150       let needs_i =
6151         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
6152
6153       pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
6154       pr "{\n";
6155       if needs_i then (
6156         pr "  unsigned int i;\n";
6157         pr "\n"
6158       );
6159       List.iter (
6160         function
6161         | name, FString ->
6162             pr "  printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
6163         | name, FUUID ->
6164             pr "  printf (\"%s: \");\n" name;
6165             pr "  for (i = 0; i < 32; ++i)\n";
6166             pr "    printf (\"%%s%%c\", indent, %s->%s[i]);\n" typ name;
6167             pr "  printf (\"\\n\");\n"
6168         | name, FBuffer ->
6169             pr "  printf (\"%%s%s: \", indent);\n" name;
6170             pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
6171             pr "    if (isprint (%s->%s[i]))\n" typ name;
6172             pr "      printf (\"%%s%%c\", indent, %s->%s[i]);\n" typ name;
6173             pr "    else\n";
6174             pr "      printf (\"%%s\\\\x%%02x\", indent, %s->%s[i]);\n" typ name;
6175             pr "  printf (\"\\n\");\n"
6176         | name, (FUInt64|FBytes) ->
6177             pr "  printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
6178               name typ name
6179         | name, FInt64 ->
6180             pr "  printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
6181               name typ name
6182         | name, FUInt32 ->
6183             pr "  printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
6184               name typ name
6185         | name, FInt32 ->
6186             pr "  printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
6187               name typ name
6188         | name, FChar ->
6189             pr "  printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
6190               name typ name
6191         | name, FOptPercent ->
6192             pr "  if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
6193               typ name name typ name;
6194             pr "  else printf (\"%%s%s: \\n\", indent);\n" name
6195       ) cols;
6196       pr "}\n";
6197       pr "\n";
6198   ) structs;
6199
6200   (* Emit a print_TYPE_list function definition only if that function is used. *)
6201   List.iter (
6202     function
6203     | typ, (RStructListOnly | RStructAndList) ->
6204         (* generate the function for typ *)
6205         emit_print_list_function typ
6206     | typ, _ -> () (* empty *)
6207   ) rstructs_used;
6208
6209   (* Emit a print_TYPE function definition only if that function is used. *)
6210   List.iter (
6211     function
6212     | typ, RStructOnly ->
6213         pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
6214         pr "{\n";
6215         pr "  print_%s_indent (%s, \"\");\n" typ typ;
6216         pr "}\n";
6217         pr "\n";
6218     | typ, _ -> () (* empty *)
6219   ) rstructs_used;
6220
6221   (* run_<action> actions *)
6222   List.iter (
6223     fun (name, style, _, flags, _, _, _) ->
6224       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
6225       pr "{\n";
6226       (match fst style with
6227        | RErr
6228        | RInt _
6229        | RBool _ -> pr "  int r;\n"
6230        | RInt64 _ -> pr "  int64_t r;\n"
6231        | RConstString _ | RConstOptString _ -> pr "  const char *r;\n"
6232        | RString _ -> pr "  char *r;\n"
6233        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
6234        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
6235        | RStructList (_, typ) -> pr "  struct guestfs_%s_list *r;\n" typ
6236        | RBufferOut _ ->
6237            pr "  char *r;\n";
6238            pr "  size_t size;\n";
6239       );
6240       List.iter (
6241         function
6242         | Pathname n
6243         | Device n | Dev_or_Path n
6244         | String n
6245         | OptString n
6246         | FileIn n
6247         | FileOut n -> pr "  const char *%s;\n" n
6248         | StringList n | DeviceList n -> pr "  char **%s;\n" n
6249         | Bool n -> pr "  int %s;\n" n
6250         | Int n -> pr "  int %s;\n" n
6251       ) (snd style);
6252
6253       (* Check and convert parameters. *)
6254       let argc_expected = List.length (snd style) in
6255       pr "  if (argc != %d) {\n" argc_expected;
6256       pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
6257         argc_expected;
6258       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
6259       pr "    return -1;\n";
6260       pr "  }\n";
6261       iteri (
6262         fun i ->
6263           function
6264           | Pathname name
6265           | Device name | Dev_or_Path name | String name -> pr "  %s = argv[%d];\n" name i
6266           | OptString name ->
6267               pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
6268                 name i i
6269           | FileIn name ->
6270               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
6271                 name i i
6272           | FileOut name ->
6273               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
6274                 name i i
6275           | StringList name | DeviceList name ->
6276               pr "  %s = parse_string_list (argv[%d]);\n" name i;
6277               pr "  if (%s == NULL) return -1;\n" name;
6278           | Bool name ->
6279               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
6280           | Int name ->
6281               pr "  %s = atoi (argv[%d]);\n" name i
6282       ) (snd style);
6283
6284       (* Call C API function. *)
6285       let fn =
6286         try find_map (function FishAction n -> Some n | _ -> None) flags
6287         with Not_found -> sprintf "guestfs_%s" name in
6288       pr "  r = %s " fn;
6289       generate_c_call_args ~handle:"g" style;
6290       pr ";\n";
6291
6292       List.iter (
6293         function
6294         | Pathname name | Device name | Dev_or_Path name | String name
6295         | OptString name | FileIn name | FileOut name | Bool name
6296         | Int name -> ()
6297         | StringList name | DeviceList name ->
6298             pr "  free_strings (%s);\n" name
6299       ) (snd style);
6300
6301       (* Check return value for errors and display command results. *)
6302       (match fst style with
6303        | RErr -> pr "  return r;\n"
6304        | RInt _ ->
6305            pr "  if (r == -1) return -1;\n";
6306            pr "  printf (\"%%d\\n\", r);\n";
6307            pr "  return 0;\n"
6308        | RInt64 _ ->
6309            pr "  if (r == -1) return -1;\n";
6310            pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
6311            pr "  return 0;\n"
6312        | RBool _ ->
6313            pr "  if (r == -1) return -1;\n";
6314            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
6315            pr "  return 0;\n"
6316        | RConstString _ ->
6317            pr "  if (r == NULL) return -1;\n";
6318            pr "  printf (\"%%s\\n\", r);\n";
6319            pr "  return 0;\n"
6320        | RConstOptString _ ->
6321            pr "  printf (\"%%s\\n\", r ? : \"(null)\");\n";
6322            pr "  return 0;\n"
6323        | RString _ ->
6324            pr "  if (r == NULL) return -1;\n";
6325            pr "  printf (\"%%s\\n\", r);\n";
6326            pr "  free (r);\n";
6327            pr "  return 0;\n"
6328        | RStringList _ ->
6329            pr "  if (r == NULL) return -1;\n";
6330            pr "  print_strings (r);\n";
6331            pr "  free_strings (r);\n";
6332            pr "  return 0;\n"
6333        | RStruct (_, typ) ->
6334            pr "  if (r == NULL) return -1;\n";
6335            pr "  print_%s (r);\n" typ;
6336            pr "  guestfs_free_%s (r);\n" typ;
6337            pr "  return 0;\n"
6338        | RStructList (_, typ) ->
6339            pr "  if (r == NULL) return -1;\n";
6340            pr "  print_%s_list (r);\n" typ;
6341            pr "  guestfs_free_%s_list (r);\n" typ;
6342            pr "  return 0;\n"
6343        | RHashtable _ ->
6344            pr "  if (r == NULL) return -1;\n";
6345            pr "  print_table (r);\n";
6346            pr "  free_strings (r);\n";
6347            pr "  return 0;\n"
6348        | RBufferOut _ ->
6349            pr "  if (r == NULL) return -1;\n";
6350            pr "  fwrite (r, size, 1, stdout);\n";
6351            pr "  free (r);\n";
6352            pr "  return 0;\n"
6353       );
6354       pr "}\n";
6355       pr "\n"
6356   ) all_functions;
6357
6358   (* run_action function *)
6359   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
6360   pr "{\n";
6361   List.iter (
6362     fun (name, _, _, flags, _, _, _) ->
6363       let name2 = replace_char name '_' '-' in
6364       let alias =
6365         try find_map (function FishAlias n -> Some n | _ -> None) flags
6366         with Not_found -> name in
6367       pr "  if (";
6368       pr "strcasecmp (cmd, \"%s\") == 0" name;
6369       if name <> name2 then
6370         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
6371       if name <> alias then
6372         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
6373       pr ")\n";
6374       pr "    return run_%s (cmd, argc, argv);\n" name;
6375       pr "  else\n";
6376   ) all_functions;
6377   pr "    {\n";
6378   pr "      fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
6379   pr "      return -1;\n";
6380   pr "    }\n";
6381   pr "  return 0;\n";
6382   pr "}\n";
6383   pr "\n"
6384
6385 (* Readline completion for guestfish. *)
6386 and generate_fish_completion () =
6387   generate_header CStyle GPLv2;
6388
6389   let all_functions =
6390     List.filter (
6391       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
6392     ) all_functions in
6393
6394   pr "\
6395 #include <config.h>
6396
6397 #include <stdio.h>
6398 #include <stdlib.h>
6399 #include <string.h>
6400
6401 #ifdef HAVE_LIBREADLINE
6402 #include <readline/readline.h>
6403 #endif
6404
6405 #include \"fish.h\"
6406
6407 #ifdef HAVE_LIBREADLINE
6408
6409 static const char *const commands[] = {
6410   BUILTIN_COMMANDS_FOR_COMPLETION,
6411 ";
6412
6413   (* Get the commands, including the aliases.  They don't need to be
6414    * sorted - the generator() function just does a dumb linear search.
6415    *)
6416   let commands =
6417     List.map (
6418       fun (name, _, _, flags, _, _, _) ->
6419         let name2 = replace_char name '_' '-' in
6420         let alias =
6421           try find_map (function FishAlias n -> Some n | _ -> None) flags
6422           with Not_found -> name in
6423
6424         if name <> alias then [name2; alias] else [name2]
6425     ) all_functions in
6426   let commands = List.flatten commands in
6427
6428   List.iter (pr "  \"%s\",\n") commands;
6429
6430   pr "  NULL
6431 };
6432
6433 static char *
6434 generator (const char *text, int state)
6435 {
6436   static int index, len;
6437   const char *name;
6438
6439   if (!state) {
6440     index = 0;
6441     len = strlen (text);
6442   }
6443
6444   rl_attempted_completion_over = 1;
6445
6446   while ((name = commands[index]) != NULL) {
6447     index++;
6448     if (strncasecmp (name, text, len) == 0)
6449       return strdup (name);
6450   }
6451
6452   return NULL;
6453 }
6454
6455 #endif /* HAVE_LIBREADLINE */
6456
6457 char **do_completion (const char *text, int start, int end)
6458 {
6459   char **matches = NULL;
6460
6461 #ifdef HAVE_LIBREADLINE
6462   rl_completion_append_character = ' ';
6463
6464   if (start == 0)
6465     matches = rl_completion_matches (text, generator);
6466   else if (complete_dest_paths)
6467     matches = rl_completion_matches (text, complete_dest_paths_generator);
6468 #endif
6469
6470   return matches;
6471 }
6472 ";
6473
6474 (* Generate the POD documentation for guestfish. *)
6475 and generate_fish_actions_pod () =
6476   let all_functions_sorted =
6477     List.filter (
6478       fun (_, _, _, flags, _, _, _) ->
6479         not (List.mem NotInFish flags || List.mem NotInDocs flags)
6480     ) all_functions_sorted in
6481
6482   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
6483
6484   List.iter (
6485     fun (name, style, _, flags, _, _, longdesc) ->
6486       let longdesc =
6487         Str.global_substitute rex (
6488           fun s ->
6489             let sub =
6490               try Str.matched_group 1 s
6491               with Not_found ->
6492                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
6493             "C<" ^ replace_char sub '_' '-' ^ ">"
6494         ) longdesc in
6495       let name = replace_char name '_' '-' in
6496       let alias =
6497         try find_map (function FishAlias n -> Some n | _ -> None) flags
6498         with Not_found -> name in
6499
6500       pr "=head2 %s" name;
6501       if name <> alias then
6502         pr " | %s" alias;
6503       pr "\n";
6504       pr "\n";
6505       pr " %s" name;
6506       List.iter (
6507         function
6508         | Pathname n | Device n | Dev_or_Path n | String n -> pr " %s" n
6509         | OptString n -> pr " %s" n
6510         | StringList n | DeviceList n -> pr " '%s ...'" n
6511         | Bool _ -> pr " true|false"
6512         | Int n -> pr " %s" n
6513         | FileIn n | FileOut n -> pr " (%s|-)" n
6514       ) (snd style);
6515       pr "\n";
6516       pr "\n";
6517       pr "%s\n\n" longdesc;
6518
6519       if List.exists (function FileIn _ | FileOut _ -> true
6520                       | _ -> false) (snd style) then
6521         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
6522
6523       if List.mem ProtocolLimitWarning flags then
6524         pr "%s\n\n" protocol_limit_warning;
6525
6526       if List.mem DangerWillRobinson flags then
6527         pr "%s\n\n" danger_will_robinson;
6528
6529       match deprecation_notice flags with
6530       | None -> ()
6531       | Some txt -> pr "%s\n\n" txt
6532   ) all_functions_sorted
6533
6534 (* Generate a C function prototype. *)
6535 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
6536     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
6537     ?(prefix = "")
6538     ?handle name style =
6539   if extern then pr "extern ";
6540   if static then pr "static ";
6541   (match fst style with
6542    | RErr -> pr "int "
6543    | RInt _ -> pr "int "
6544    | RInt64 _ -> pr "int64_t "
6545    | RBool _ -> pr "int "
6546    | RConstString _ | RConstOptString _ -> pr "const char *"
6547    | RString _ | RBufferOut _ -> pr "char *"
6548    | RStringList _ | RHashtable _ -> pr "char **"
6549    | RStruct (_, typ) ->
6550        if not in_daemon then pr "struct guestfs_%s *" typ
6551        else pr "guestfs_int_%s *" typ
6552    | RStructList (_, typ) ->
6553        if not in_daemon then pr "struct guestfs_%s_list *" typ
6554        else pr "guestfs_int_%s_list *" typ
6555   );
6556   let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
6557   pr "%s%s (" prefix name;
6558   if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
6559     pr "void"
6560   else (
6561     let comma = ref false in
6562     (match handle with
6563      | None -> ()
6564      | Some handle -> pr "guestfs_h *%s" handle; comma := true
6565     );
6566     let next () =
6567       if !comma then (
6568         if single_line then pr ", " else pr ",\n\t\t"
6569       );
6570       comma := true
6571     in
6572     List.iter (
6573       function
6574       | Pathname n
6575       | Device n | Dev_or_Path n
6576       | String n
6577       | OptString n ->
6578           next ();
6579           pr "const char *%s" n
6580       | StringList n | DeviceList n ->
6581           next ();
6582           pr "char *const *%s" n
6583       | Bool n -> next (); pr "int %s" n
6584       | Int n -> next (); pr "int %s" n
6585       | FileIn n
6586       | FileOut n ->
6587           if not in_daemon then (next (); pr "const char *%s" n)
6588     ) (snd style);
6589     if is_RBufferOut then (next (); pr "size_t *size_r");
6590   );
6591   pr ")";
6592   if semicolon then pr ";";
6593   if newline then pr "\n"
6594
6595 (* Generate C call arguments, eg "(handle, foo, bar)" *)
6596 and generate_c_call_args ?handle ?(decl = false) style =
6597   pr "(";
6598   let comma = ref false in
6599   let next () =
6600     if !comma then pr ", ";
6601     comma := true
6602   in
6603   (match handle with
6604    | None -> ()
6605    | Some handle -> pr "%s" handle; comma := true
6606   );
6607   List.iter (
6608     fun arg ->
6609       next ();
6610       pr "%s" (name_of_argt arg)
6611   ) (snd style);
6612   (* For RBufferOut calls, add implicit &size parameter. *)
6613   if not decl then (
6614     match fst style with
6615     | RBufferOut _ ->
6616         next ();
6617         pr "&size"
6618     | _ -> ()
6619   );
6620   pr ")"
6621
6622 (* Generate the OCaml bindings interface. *)
6623 and generate_ocaml_mli () =
6624   generate_header OCamlStyle LGPLv2;
6625
6626   pr "\
6627 (** For API documentation you should refer to the C API
6628     in the guestfs(3) manual page.  The OCaml API uses almost
6629     exactly the same calls. *)
6630
6631 type t
6632 (** A [guestfs_h] handle. *)
6633
6634 exception Error of string
6635 (** This exception is raised when there is an error. *)
6636
6637 val create : unit -> t
6638
6639 val close : t -> unit
6640 (** Handles are closed by the garbage collector when they become
6641     unreferenced, but callers can also call this in order to
6642     provide predictable cleanup. *)
6643
6644 ";
6645   generate_ocaml_structure_decls ();
6646
6647   (* The actions. *)
6648   List.iter (
6649     fun (name, style, _, _, _, shortdesc, _) ->
6650       generate_ocaml_prototype name style;
6651       pr "(** %s *)\n" shortdesc;
6652       pr "\n"
6653   ) all_functions
6654
6655 (* Generate the OCaml bindings implementation. *)
6656 and generate_ocaml_ml () =
6657   generate_header OCamlStyle LGPLv2;
6658
6659   pr "\
6660 type t
6661 exception Error of string
6662 external create : unit -> t = \"ocaml_guestfs_create\"
6663 external close : t -> unit = \"ocaml_guestfs_close\"
6664
6665 let () =
6666   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
6667
6668 ";
6669
6670   generate_ocaml_structure_decls ();
6671
6672   (* The actions. *)
6673   List.iter (
6674     fun (name, style, _, _, _, shortdesc, _) ->
6675       generate_ocaml_prototype ~is_external:true name style;
6676   ) all_functions
6677
6678 (* Generate the OCaml bindings C implementation. *)
6679 and generate_ocaml_c () =
6680   generate_header CStyle LGPLv2;
6681
6682   pr "\
6683 #include <stdio.h>
6684 #include <stdlib.h>
6685 #include <string.h>
6686
6687 #include <caml/config.h>
6688 #include <caml/alloc.h>
6689 #include <caml/callback.h>
6690 #include <caml/fail.h>
6691 #include <caml/memory.h>
6692 #include <caml/mlvalues.h>
6693 #include <caml/signals.h>
6694
6695 #include <guestfs.h>
6696
6697 #include \"guestfs_c.h\"
6698
6699 /* Copy a hashtable of string pairs into an assoc-list.  We return
6700  * the list in reverse order, but hashtables aren't supposed to be
6701  * ordered anyway.
6702  */
6703 static CAMLprim value
6704 copy_table (char * const * argv)
6705 {
6706   CAMLparam0 ();
6707   CAMLlocal5 (rv, pairv, kv, vv, cons);
6708   int i;
6709
6710   rv = Val_int (0);
6711   for (i = 0; argv[i] != NULL; i += 2) {
6712     kv = caml_copy_string (argv[i]);
6713     vv = caml_copy_string (argv[i+1]);
6714     pairv = caml_alloc (2, 0);
6715     Store_field (pairv, 0, kv);
6716     Store_field (pairv, 1, vv);
6717     cons = caml_alloc (2, 0);
6718     Store_field (cons, 1, rv);
6719     rv = cons;
6720     Store_field (cons, 0, pairv);
6721   }
6722
6723   CAMLreturn (rv);
6724 }
6725
6726 ";
6727
6728   (* Struct copy functions. *)
6729
6730   let emit_ocaml_copy_list_function typ =
6731     pr "static CAMLprim value\n";
6732     pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n" typ typ typ;
6733     pr "{\n";
6734     pr "  CAMLparam0 ();\n";
6735     pr "  CAMLlocal2 (rv, v);\n";
6736     pr "  unsigned int i;\n";
6737     pr "\n";
6738     pr "  if (%ss->len == 0)\n" typ;
6739     pr "    CAMLreturn (Atom (0));\n";
6740     pr "  else {\n";
6741     pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
6742     pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
6743     pr "      v = copy_%s (&%ss->val[i]);\n" typ typ;
6744     pr "      caml_modify (&Field (rv, i), v);\n";
6745     pr "    }\n";
6746     pr "    CAMLreturn (rv);\n";
6747     pr "  }\n";
6748     pr "}\n";
6749     pr "\n";
6750   in
6751
6752   List.iter (
6753     fun (typ, cols) ->
6754       let has_optpercent_col =
6755         List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
6756
6757       pr "static CAMLprim value\n";
6758       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
6759       pr "{\n";
6760       pr "  CAMLparam0 ();\n";
6761       if has_optpercent_col then
6762         pr "  CAMLlocal3 (rv, v, v2);\n"
6763       else
6764         pr "  CAMLlocal2 (rv, v);\n";
6765       pr "\n";
6766       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
6767       iteri (
6768         fun i col ->
6769           (match col with
6770            | name, FString ->
6771                pr "  v = caml_copy_string (%s->%s);\n" typ name
6772            | name, FBuffer ->
6773                pr "  v = caml_alloc_string (%s->%s_len);\n" typ name;
6774                pr "  memcpy (String_val (v), %s->%s, %s->%s_len);\n"
6775                  typ name typ name
6776            | name, FUUID ->
6777                pr "  v = caml_alloc_string (32);\n";
6778                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
6779            | name, (FBytes|FInt64|FUInt64) ->
6780                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
6781            | name, (FInt32|FUInt32) ->
6782                pr "  v = caml_copy_int32 (%s->%s);\n" typ name
6783            | name, FOptPercent ->
6784                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
6785                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
6786                pr "    v = caml_alloc (1, 0);\n";
6787                pr "    Store_field (v, 0, v2);\n";
6788                pr "  } else /* None */\n";
6789                pr "    v = Val_int (0);\n";
6790            | name, FChar ->
6791                pr "  v = Val_int (%s->%s);\n" typ name
6792           );
6793           pr "  Store_field (rv, %d, v);\n" i
6794       ) cols;
6795       pr "  CAMLreturn (rv);\n";
6796       pr "}\n";
6797       pr "\n";
6798   ) structs;
6799
6800   (* Emit a copy_TYPE_list function definition only if that function is used. *)
6801   List.iter (
6802     function
6803     | typ, (RStructListOnly | RStructAndList) ->
6804         (* generate the function for typ *)
6805         emit_ocaml_copy_list_function typ
6806     | typ, _ -> () (* empty *)
6807   ) rstructs_used;
6808
6809   (* The wrappers. *)
6810   List.iter (
6811     fun (name, style, _, _, _, _, _) ->
6812       let params =
6813         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
6814
6815       let needs_extra_vs =
6816         match fst style with RConstOptString _ -> true | _ -> false in
6817
6818       pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
6819       pr "CAMLprim value ocaml_guestfs_%s (value %s" name (List.hd params);
6820       List.iter (pr ", value %s") (List.tl params); pr ");\n";
6821
6822       pr "CAMLprim value\n";
6823       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
6824       List.iter (pr ", value %s") (List.tl params);
6825       pr ")\n";
6826       pr "{\n";
6827
6828       (match params with
6829        | [p1; p2; p3; p4; p5] ->
6830            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
6831        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
6832            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
6833            pr "  CAMLxparam%d (%s);\n"
6834              (List.length rest) (String.concat ", " rest)
6835        | ps ->
6836            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
6837       );
6838       if not needs_extra_vs then
6839         pr "  CAMLlocal1 (rv);\n"
6840       else
6841         pr "  CAMLlocal3 (rv, v, v2);\n";
6842       pr "\n";
6843
6844       pr "  guestfs_h *g = Guestfs_val (gv);\n";
6845       pr "  if (g == NULL)\n";
6846       pr "    caml_failwith (\"%s: used handle after closing it\");\n" name;
6847       pr "\n";
6848
6849       List.iter (
6850         function
6851         | Pathname n
6852         | Device n | Dev_or_Path n
6853         | String n
6854         | FileIn n
6855         | FileOut n ->
6856             pr "  const char *%s = String_val (%sv);\n" n n
6857         | OptString n ->
6858             pr "  const char *%s =\n" n;
6859             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
6860               n n
6861         | StringList n | DeviceList n ->
6862             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
6863         | Bool n ->
6864             pr "  int %s = Bool_val (%sv);\n" n n
6865         | Int n ->
6866             pr "  int %s = Int_val (%sv);\n" n n
6867       ) (snd style);
6868       let error_code =
6869         match fst style with
6870         | RErr -> pr "  int r;\n"; "-1"
6871         | RInt _ -> pr "  int r;\n"; "-1"
6872         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
6873         | RBool _ -> pr "  int r;\n"; "-1"
6874         | RConstString _ | RConstOptString _ ->
6875             pr "  const char *r;\n"; "NULL"
6876         | RString _ -> pr "  char *r;\n"; "NULL"
6877         | RStringList _ ->
6878             pr "  int i;\n";
6879             pr "  char **r;\n";
6880             "NULL"
6881         | RStruct (_, typ) ->
6882             pr "  struct guestfs_%s *r;\n" typ; "NULL"
6883         | RStructList (_, typ) ->
6884             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
6885         | RHashtable _ ->
6886             pr "  int i;\n";
6887             pr "  char **r;\n";
6888             "NULL"
6889         | RBufferOut _ ->
6890             pr "  char *r;\n";
6891             pr "  size_t size;\n";
6892             "NULL" in
6893       pr "\n";
6894
6895       pr "  caml_enter_blocking_section ();\n";
6896       pr "  r = guestfs_%s " name;
6897       generate_c_call_args ~handle:"g" style;
6898       pr ";\n";
6899       pr "  caml_leave_blocking_section ();\n";
6900
6901       List.iter (
6902         function
6903         | StringList n | DeviceList n ->
6904             pr "  ocaml_guestfs_free_strings (%s);\n" n;
6905         | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _ | Bool _ | Int _
6906         | FileIn _ | FileOut _ -> ()
6907       ) (snd style);
6908
6909       pr "  if (r == %s)\n" error_code;
6910       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
6911       pr "\n";
6912
6913       (match fst style with
6914        | RErr -> pr "  rv = Val_unit;\n"
6915        | RInt _ -> pr "  rv = Val_int (r);\n"
6916        | RInt64 _ ->
6917            pr "  rv = caml_copy_int64 (r);\n"
6918        | RBool _ -> pr "  rv = Val_bool (r);\n"
6919        | RConstString _ ->
6920            pr "  rv = caml_copy_string (r);\n"
6921        | RConstOptString _ ->
6922            pr "  if (r) { /* Some string */\n";
6923            pr "    v = caml_alloc (1, 0);\n";
6924            pr "    v2 = caml_copy_string (r);\n";
6925            pr "    Store_field (v, 0, v2);\n";
6926            pr "  } else /* None */\n";
6927            pr "    v = Val_int (0);\n";
6928        | RString _ ->
6929            pr "  rv = caml_copy_string (r);\n";
6930            pr "  free (r);\n"
6931        | RStringList _ ->
6932            pr "  rv = caml_copy_string_array ((const char **) r);\n";
6933            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
6934            pr "  free (r);\n"
6935        | RStruct (_, typ) ->
6936            pr "  rv = copy_%s (r);\n" typ;
6937            pr "  guestfs_free_%s (r);\n" typ;
6938        | RStructList (_, typ) ->
6939            pr "  rv = copy_%s_list (r);\n" typ;
6940            pr "  guestfs_free_%s_list (r);\n" typ;
6941        | RHashtable _ ->
6942            pr "  rv = copy_table (r);\n";
6943            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
6944            pr "  free (r);\n";
6945        | RBufferOut _ ->
6946            pr "  rv = caml_alloc_string (size);\n";
6947            pr "  memcpy (String_val (rv), r, size);\n";
6948       );
6949
6950       pr "  CAMLreturn (rv);\n";
6951       pr "}\n";
6952       pr "\n";
6953
6954       if List.length params > 5 then (
6955         pr "/* Emit prototype to appease gcc's -Wmissing-prototypes. */\n";
6956         pr "CAMLprim value ";
6957         pr "ocaml_guestfs_%s_byte (value *argv, int argn);\n" name;
6958         pr "CAMLprim value\n";
6959         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
6960         pr "{\n";
6961         pr "  return ocaml_guestfs_%s (argv[0]" name;
6962         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
6963         pr ");\n";
6964         pr "}\n";
6965         pr "\n"
6966       )
6967   ) all_functions
6968
6969 and generate_ocaml_structure_decls () =
6970   List.iter (
6971     fun (typ, cols) ->
6972       pr "type %s = {\n" typ;
6973       List.iter (
6974         function
6975         | name, FString -> pr "  %s : string;\n" name
6976         | name, FBuffer -> pr "  %s : string;\n" name
6977         | name, FUUID -> pr "  %s : string;\n" name
6978         | name, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
6979         | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
6980         | name, FChar -> pr "  %s : char;\n" name
6981         | name, FOptPercent -> pr "  %s : float option;\n" name
6982       ) cols;
6983       pr "}\n";
6984       pr "\n"
6985   ) structs
6986
6987 and generate_ocaml_prototype ?(is_external = false) name style =
6988   if is_external then pr "external " else pr "val ";
6989   pr "%s : t -> " name;
6990   List.iter (
6991     function
6992     | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "string -> "
6993     | OptString _ -> pr "string option -> "
6994     | StringList _ | DeviceList _ -> pr "string array -> "
6995     | Bool _ -> pr "bool -> "
6996     | Int _ -> pr "int -> "
6997   ) (snd style);
6998   (match fst style with
6999    | RErr -> pr "unit" (* all errors are turned into exceptions *)
7000    | RInt _ -> pr "int"
7001    | RInt64 _ -> pr "int64"
7002    | RBool _ -> pr "bool"
7003    | RConstString _ -> pr "string"
7004    | RConstOptString _ -> pr "string option"
7005    | RString _ | RBufferOut _ -> pr "string"
7006    | RStringList _ -> pr "string array"
7007    | RStruct (_, typ) -> pr "%s" typ
7008    | RStructList (_, typ) -> pr "%s array" typ
7009    | RHashtable _ -> pr "(string * string) list"
7010   );
7011   if is_external then (
7012     pr " = ";
7013     if List.length (snd style) + 1 > 5 then
7014       pr "\"ocaml_guestfs_%s_byte\" " name;
7015     pr "\"ocaml_guestfs_%s\"" name
7016   );
7017   pr "\n"
7018
7019 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
7020 and generate_perl_xs () =
7021   generate_header CStyle LGPLv2;
7022
7023   pr "\
7024 #include \"EXTERN.h\"
7025 #include \"perl.h\"
7026 #include \"XSUB.h\"
7027
7028 #include <guestfs.h>
7029
7030 #ifndef PRId64
7031 #define PRId64 \"lld\"
7032 #endif
7033
7034 static SV *
7035 my_newSVll(long long val) {
7036 #ifdef USE_64_BIT_ALL
7037   return newSViv(val);
7038 #else
7039   char buf[100];
7040   int len;
7041   len = snprintf(buf, 100, \"%%\" PRId64, val);
7042   return newSVpv(buf, len);
7043 #endif
7044 }
7045
7046 #ifndef PRIu64
7047 #define PRIu64 \"llu\"
7048 #endif
7049
7050 static SV *
7051 my_newSVull(unsigned long long val) {
7052 #ifdef USE_64_BIT_ALL
7053   return newSVuv(val);
7054 #else
7055   char buf[100];
7056   int len;
7057   len = snprintf(buf, 100, \"%%\" PRIu64, val);
7058   return newSVpv(buf, len);
7059 #endif
7060 }
7061
7062 /* http://www.perlmonks.org/?node_id=680842 */
7063 static char **
7064 XS_unpack_charPtrPtr (SV *arg) {
7065   char **ret;
7066   AV *av;
7067   I32 i;
7068
7069   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
7070     croak (\"array reference expected\");
7071
7072   av = (AV *)SvRV (arg);
7073   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
7074   if (!ret)
7075     croak (\"malloc failed\");
7076
7077   for (i = 0; i <= av_len (av); i++) {
7078     SV **elem = av_fetch (av, i, 0);
7079
7080     if (!elem || !*elem)
7081       croak (\"missing element in list\");
7082
7083     ret[i] = SvPV_nolen (*elem);
7084   }
7085
7086   ret[i] = NULL;
7087
7088   return ret;
7089 }
7090
7091 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
7092
7093 PROTOTYPES: ENABLE
7094
7095 guestfs_h *
7096 _create ()
7097    CODE:
7098       RETVAL = guestfs_create ();
7099       if (!RETVAL)
7100         croak (\"could not create guestfs handle\");
7101       guestfs_set_error_handler (RETVAL, NULL, NULL);
7102  OUTPUT:
7103       RETVAL
7104
7105 void
7106 DESTROY (g)
7107       guestfs_h *g;
7108  PPCODE:
7109       guestfs_close (g);
7110
7111 ";
7112
7113   List.iter (
7114     fun (name, style, _, _, _, _, _) ->
7115       (match fst style with
7116        | RErr -> pr "void\n"
7117        | RInt _ -> pr "SV *\n"
7118        | RInt64 _ -> pr "SV *\n"
7119        | RBool _ -> pr "SV *\n"
7120        | RConstString _ -> pr "SV *\n"
7121        | RConstOptString _ -> pr "SV *\n"
7122        | RString _ -> pr "SV *\n"
7123        | RBufferOut _ -> pr "SV *\n"
7124        | RStringList _
7125        | RStruct _ | RStructList _
7126        | RHashtable _ ->
7127            pr "void\n" (* all lists returned implictly on the stack *)
7128       );
7129       (* Call and arguments. *)
7130       pr "%s " name;
7131       generate_c_call_args ~handle:"g" ~decl:true style;
7132       pr "\n";
7133       pr "      guestfs_h *g;\n";
7134       iteri (
7135         fun i ->
7136           function
7137           | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
7138               pr "      char *%s;\n" n
7139           | OptString n ->
7140               (* http://www.perlmonks.org/?node_id=554277
7141                * Note that the implicit handle argument means we have
7142                * to add 1 to the ST(x) operator.
7143                *)
7144               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
7145           | StringList n | DeviceList n -> pr "      char **%s;\n" n
7146           | Bool n -> pr "      int %s;\n" n
7147           | Int n -> pr "      int %s;\n" n
7148       ) (snd style);
7149
7150       let do_cleanups () =
7151         List.iter (
7152           function
7153           | Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _ | Bool _ | Int _
7154           | FileIn _ | FileOut _ -> ()
7155           | StringList n | DeviceList n -> pr "      free (%s);\n" n
7156         ) (snd style)
7157       in
7158
7159       (* Code. *)
7160       (match fst style with
7161        | RErr ->
7162            pr "PREINIT:\n";
7163            pr "      int r;\n";
7164            pr " PPCODE:\n";
7165            pr "      r = guestfs_%s " name;
7166            generate_c_call_args ~handle:"g" style;
7167            pr ";\n";
7168            do_cleanups ();
7169            pr "      if (r == -1)\n";
7170            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
7171        | RInt n
7172        | RBool n ->
7173            pr "PREINIT:\n";
7174            pr "      int %s;\n" n;
7175            pr "   CODE:\n";
7176            pr "      %s = guestfs_%s " n name;
7177            generate_c_call_args ~handle:"g" style;
7178            pr ";\n";
7179            do_cleanups ();
7180            pr "      if (%s == -1)\n" n;
7181            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
7182            pr "      RETVAL = newSViv (%s);\n" n;
7183            pr " OUTPUT:\n";
7184            pr "      RETVAL\n"
7185        | RInt64 n ->
7186            pr "PREINIT:\n";
7187            pr "      int64_t %s;\n" n;
7188            pr "   CODE:\n";
7189            pr "      %s = guestfs_%s " n name;
7190            generate_c_call_args ~handle:"g" style;
7191            pr ";\n";
7192            do_cleanups ();
7193            pr "      if (%s == -1)\n" n;
7194            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
7195            pr "      RETVAL = my_newSVll (%s);\n" n;
7196            pr " OUTPUT:\n";
7197            pr "      RETVAL\n"
7198        | RConstString n ->
7199            pr "PREINIT:\n";
7200            pr "      const char *%s;\n" n;
7201            pr "   CODE:\n";
7202            pr "      %s = guestfs_%s " n name;
7203            generate_c_call_args ~handle:"g" style;
7204            pr ";\n";
7205            do_cleanups ();
7206            pr "      if (%s == NULL)\n" n;
7207            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
7208            pr "      RETVAL = newSVpv (%s, 0);\n" n;
7209            pr " OUTPUT:\n";
7210            pr "      RETVAL\n"
7211        | RConstOptString n ->
7212            pr "PREINIT:\n";
7213            pr "      const char *%s;\n" n;
7214            pr "   CODE:\n";
7215            pr "      %s = guestfs_%s " n name;
7216            generate_c_call_args ~handle:"g" style;
7217            pr ";\n";
7218            do_cleanups ();
7219            pr "      if (%s == NULL)\n" n;
7220            pr "        RETVAL = &PL_sv_undef;\n";
7221            pr "      else\n";
7222            pr "        RETVAL = newSVpv (%s, 0);\n" n;
7223            pr " OUTPUT:\n";
7224            pr "      RETVAL\n"
7225        | RString n ->
7226            pr "PREINIT:\n";
7227            pr "      char *%s;\n" n;
7228            pr "   CODE:\n";
7229            pr "      %s = guestfs_%s " n name;
7230            generate_c_call_args ~handle:"g" style;
7231            pr ";\n";
7232            do_cleanups ();
7233            pr "      if (%s == NULL)\n" n;
7234            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
7235            pr "      RETVAL = newSVpv (%s, 0);\n" n;
7236            pr "      free (%s);\n" n;
7237            pr " OUTPUT:\n";
7238            pr "      RETVAL\n"
7239        | RStringList n | RHashtable n ->
7240            pr "PREINIT:\n";
7241            pr "      char **%s;\n" n;
7242            pr "      int i, n;\n";
7243            pr " PPCODE:\n";
7244            pr "      %s = guestfs_%s " n name;
7245            generate_c_call_args ~handle:"g" style;
7246            pr ";\n";
7247            do_cleanups ();
7248            pr "      if (%s == NULL)\n" n;
7249            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
7250            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
7251            pr "      EXTEND (SP, n);\n";
7252            pr "      for (i = 0; i < n; ++i) {\n";
7253            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
7254            pr "        free (%s[i]);\n" n;
7255            pr "      }\n";
7256            pr "      free (%s);\n" n;
7257        | RStruct (n, typ) ->
7258            let cols = cols_of_struct typ in
7259            generate_perl_struct_code typ cols name style n do_cleanups
7260        | RStructList (n, typ) ->
7261            let cols = cols_of_struct typ in
7262            generate_perl_struct_list_code typ cols name style n do_cleanups
7263        | RBufferOut n ->
7264            pr "PREINIT:\n";
7265            pr "      char *%s;\n" n;
7266            pr "      size_t size;\n";
7267            pr "   CODE:\n";
7268            pr "      %s = guestfs_%s " n name;
7269            generate_c_call_args ~handle:"g" style;
7270            pr ";\n";
7271            do_cleanups ();
7272            pr "      if (%s == NULL)\n" n;
7273            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
7274            pr "      RETVAL = newSVpv (%s, size);\n" n;
7275            pr "      free (%s);\n" n;
7276            pr " OUTPUT:\n";
7277            pr "      RETVAL\n"
7278       );
7279
7280       pr "\n"
7281   ) all_functions
7282
7283 and generate_perl_struct_list_code typ cols name style n do_cleanups =
7284   pr "PREINIT:\n";
7285   pr "      struct guestfs_%s_list *%s;\n" typ n;
7286   pr "      int i;\n";
7287   pr "      HV *hv;\n";
7288   pr " PPCODE:\n";
7289   pr "      %s = guestfs_%s " n name;
7290   generate_c_call_args ~handle:"g" style;
7291   pr ";\n";
7292   do_cleanups ();
7293   pr "      if (%s == NULL)\n" n;
7294   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
7295   pr "      EXTEND (SP, %s->len);\n" n;
7296   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
7297   pr "        hv = newHV ();\n";
7298   List.iter (
7299     function
7300     | name, FString ->
7301         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
7302           name (String.length name) n name
7303     | name, FUUID ->
7304         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
7305           name (String.length name) n name
7306     | name, FBuffer ->
7307         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
7308           name (String.length name) n name n name
7309     | name, (FBytes|FUInt64) ->
7310         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
7311           name (String.length name) n name
7312     | name, FInt64 ->
7313         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
7314           name (String.length name) n name
7315     | name, (FInt32|FUInt32) ->
7316         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
7317           name (String.length name) n name
7318     | name, FChar ->
7319         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
7320           name (String.length name) n name
7321     | name, FOptPercent ->
7322         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
7323           name (String.length name) n name
7324   ) cols;
7325   pr "        PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
7326   pr "      }\n";
7327   pr "      guestfs_free_%s_list (%s);\n" typ n
7328
7329 and generate_perl_struct_code typ cols name style n do_cleanups =
7330   pr "PREINIT:\n";
7331   pr "      struct guestfs_%s *%s;\n" typ n;
7332   pr " PPCODE:\n";
7333   pr "      %s = guestfs_%s " n name;
7334   generate_c_call_args ~handle:"g" style;
7335   pr ";\n";
7336   do_cleanups ();
7337   pr "      if (%s == NULL)\n" n;
7338   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
7339   pr "      EXTEND (SP, 2 * %d);\n" (List.length cols);
7340   List.iter (
7341     fun ((name, _) as col) ->
7342       pr "      PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
7343
7344       match col with
7345       | name, FString ->
7346           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
7347             n name
7348       | name, FBuffer ->
7349           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, %s->%s_len)));\n"
7350             n name n name
7351       | name, FUUID ->
7352           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
7353             n name
7354       | name, (FBytes|FUInt64) ->
7355           pr "      PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
7356             n name
7357       | name, FInt64 ->
7358           pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
7359             n name
7360       | name, (FInt32|FUInt32) ->
7361           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
7362             n name
7363       | name, FChar ->
7364           pr "      PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
7365             n name
7366       | name, FOptPercent ->
7367           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
7368             n name
7369   ) cols;
7370   pr "      free (%s);\n" n
7371
7372 (* Generate Sys/Guestfs.pm. *)
7373 and generate_perl_pm () =
7374   generate_header HashStyle LGPLv2;
7375
7376   pr "\
7377 =pod
7378
7379 =head1 NAME
7380
7381 Sys::Guestfs - Perl bindings for libguestfs
7382
7383 =head1 SYNOPSIS
7384
7385  use Sys::Guestfs;
7386
7387  my $h = Sys::Guestfs->new ();
7388  $h->add_drive ('guest.img');
7389  $h->launch ();
7390  $h->mount ('/dev/sda1', '/');
7391  $h->touch ('/hello');
7392  $h->sync ();
7393
7394 =head1 DESCRIPTION
7395
7396 The C<Sys::Guestfs> module provides a Perl XS binding to the
7397 libguestfs API for examining and modifying virtual machine
7398 disk images.
7399
7400 Amongst the things this is good for: making batch configuration
7401 changes to guests, getting disk used/free statistics (see also:
7402 virt-df), migrating between virtualization systems (see also:
7403 virt-p2v), performing partial backups, performing partial guest
7404 clones, cloning guests and changing registry/UUID/hostname info, and
7405 much else besides.
7406
7407 Libguestfs uses Linux kernel and qemu code, and can access any type of
7408 guest filesystem that Linux and qemu can, including but not limited
7409 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
7410 schemes, qcow, qcow2, vmdk.
7411
7412 Libguestfs provides ways to enumerate guest storage (eg. partitions,
7413 LVs, what filesystem is in each LV, etc.).  It can also run commands
7414 in the context of the guest.  Also you can access filesystems over FTP.
7415
7416 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
7417 functions for using libguestfs from Perl, including integration
7418 with libvirt.
7419
7420 =head1 ERRORS
7421
7422 All errors turn into calls to C<croak> (see L<Carp(3)>).
7423
7424 =head1 METHODS
7425
7426 =over 4
7427
7428 =cut
7429
7430 package Sys::Guestfs;
7431
7432 use strict;
7433 use warnings;
7434
7435 require XSLoader;
7436 XSLoader::load ('Sys::Guestfs');
7437
7438 =item $h = Sys::Guestfs->new ();
7439
7440 Create a new guestfs handle.
7441
7442 =cut
7443
7444 sub new {
7445   my $proto = shift;
7446   my $class = ref ($proto) || $proto;
7447
7448   my $self = Sys::Guestfs::_create ();
7449   bless $self, $class;
7450   return $self;
7451 }
7452
7453 ";
7454
7455   (* Actions.  We only need to print documentation for these as
7456    * they are pulled in from the XS code automatically.
7457    *)
7458   List.iter (
7459     fun (name, style, _, flags, _, _, longdesc) ->
7460       if not (List.mem NotInDocs flags) then (
7461         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
7462         pr "=item ";
7463         generate_perl_prototype name style;
7464         pr "\n\n";
7465         pr "%s\n\n" longdesc;
7466         if List.mem ProtocolLimitWarning flags then
7467           pr "%s\n\n" protocol_limit_warning;
7468         if List.mem DangerWillRobinson flags then
7469           pr "%s\n\n" danger_will_robinson;
7470         match deprecation_notice flags with
7471         | None -> ()
7472         | Some txt -> pr "%s\n\n" txt
7473       )
7474   ) all_functions_sorted;
7475
7476   (* End of file. *)
7477   pr "\
7478 =cut
7479
7480 1;
7481
7482 =back
7483
7484 =head1 COPYRIGHT
7485
7486 Copyright (C) 2009 Red Hat Inc.
7487
7488 =head1 LICENSE
7489
7490 Please see the file COPYING.LIB for the full license.
7491
7492 =head1 SEE ALSO
7493
7494 L<guestfs(3)>,
7495 L<guestfish(1)>,
7496 L<http://libguestfs.org>,
7497 L<Sys::Guestfs::Lib(3)>.
7498
7499 =cut
7500 "
7501
7502 and generate_perl_prototype name style =
7503   (match fst style with
7504    | RErr -> ()
7505    | RBool n
7506    | RInt n
7507    | RInt64 n
7508    | RConstString n
7509    | RConstOptString n
7510    | RString n
7511    | RBufferOut n -> pr "$%s = " n
7512    | RStruct (n,_)
7513    | RHashtable n -> pr "%%%s = " n
7514    | RStringList n
7515    | RStructList (n,_) -> pr "@%s = " n
7516   );
7517   pr "$h->%s (" name;
7518   let comma = ref false in
7519   List.iter (
7520     fun arg ->
7521       if !comma then pr ", ";
7522       comma := true;
7523       match arg with
7524       | Pathname n | Device n | Dev_or_Path n | String n
7525       | OptString n | Bool n | Int n | FileIn n | FileOut n ->
7526           pr "$%s" n
7527       | StringList n | DeviceList n ->
7528           pr "\\@%s" n
7529   ) (snd style);
7530   pr ");"
7531
7532 (* Generate Python C module. *)
7533 and generate_python_c () =
7534   generate_header CStyle LGPLv2;
7535
7536   pr "\
7537 #include <Python.h>
7538
7539 #include <stdio.h>
7540 #include <stdlib.h>
7541 #include <assert.h>
7542
7543 #include \"guestfs.h\"
7544
7545 typedef struct {
7546   PyObject_HEAD
7547   guestfs_h *g;
7548 } Pyguestfs_Object;
7549
7550 static guestfs_h *
7551 get_handle (PyObject *obj)
7552 {
7553   assert (obj);
7554   assert (obj != Py_None);
7555   return ((Pyguestfs_Object *) obj)->g;
7556 }
7557
7558 static PyObject *
7559 put_handle (guestfs_h *g)
7560 {
7561   assert (g);
7562   return
7563     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
7564 }
7565
7566 /* This list should be freed (but not the strings) after use. */
7567 static char **
7568 get_string_list (PyObject *obj)
7569 {
7570   int i, len;
7571   char **r;
7572
7573   assert (obj);
7574
7575   if (!PyList_Check (obj)) {
7576     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
7577     return NULL;
7578   }
7579
7580   len = PyList_Size (obj);
7581   r = malloc (sizeof (char *) * (len+1));
7582   if (r == NULL) {
7583     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
7584     return NULL;
7585   }
7586
7587   for (i = 0; i < len; ++i)
7588     r[i] = PyString_AsString (PyList_GetItem (obj, i));
7589   r[len] = NULL;
7590
7591   return r;
7592 }
7593
7594 static PyObject *
7595 put_string_list (char * const * const argv)
7596 {
7597   PyObject *list;
7598   int argc, i;
7599
7600   for (argc = 0; argv[argc] != NULL; ++argc)
7601     ;
7602
7603   list = PyList_New (argc);
7604   for (i = 0; i < argc; ++i)
7605     PyList_SetItem (list, i, PyString_FromString (argv[i]));
7606
7607   return list;
7608 }
7609
7610 static PyObject *
7611 put_table (char * const * const argv)
7612 {
7613   PyObject *list, *item;
7614   int argc, i;
7615
7616   for (argc = 0; argv[argc] != NULL; ++argc)
7617     ;
7618
7619   list = PyList_New (argc >> 1);
7620   for (i = 0; i < argc; i += 2) {
7621     item = PyTuple_New (2);
7622     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
7623     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
7624     PyList_SetItem (list, i >> 1, item);
7625   }
7626
7627   return list;
7628 }
7629
7630 static void
7631 free_strings (char **argv)
7632 {
7633   int argc;
7634
7635   for (argc = 0; argv[argc] != NULL; ++argc)
7636     free (argv[argc]);
7637   free (argv);
7638 }
7639
7640 static PyObject *
7641 py_guestfs_create (PyObject *self, PyObject *args)
7642 {
7643   guestfs_h *g;
7644
7645   g = guestfs_create ();
7646   if (g == NULL) {
7647     PyErr_SetString (PyExc_RuntimeError,
7648                      \"guestfs.create: failed to allocate handle\");
7649     return NULL;
7650   }
7651   guestfs_set_error_handler (g, NULL, NULL);
7652   return put_handle (g);
7653 }
7654
7655 static PyObject *
7656 py_guestfs_close (PyObject *self, PyObject *args)
7657 {
7658   PyObject *py_g;
7659   guestfs_h *g;
7660
7661   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
7662     return NULL;
7663   g = get_handle (py_g);
7664
7665   guestfs_close (g);
7666
7667   Py_INCREF (Py_None);
7668   return Py_None;
7669 }
7670
7671 ";
7672
7673   let emit_put_list_function typ =
7674     pr "static PyObject *\n";
7675     pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
7676     pr "{\n";
7677     pr "  PyObject *list;\n";
7678     pr "  int i;\n";
7679     pr "\n";
7680     pr "  list = PyList_New (%ss->len);\n" typ;
7681     pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
7682     pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
7683     pr "  return list;\n";
7684     pr "};\n";
7685     pr "\n"
7686   in
7687
7688   (* Structures, turned into Python dictionaries. *)
7689   List.iter (
7690     fun (typ, cols) ->
7691       pr "static PyObject *\n";
7692       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
7693       pr "{\n";
7694       pr "  PyObject *dict;\n";
7695       pr "\n";
7696       pr "  dict = PyDict_New ();\n";
7697       List.iter (
7698         function
7699         | name, FString ->
7700             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7701             pr "                        PyString_FromString (%s->%s));\n"
7702               typ name
7703         | name, FBuffer ->
7704             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7705             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
7706               typ name typ name
7707         | name, FUUID ->
7708             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7709             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
7710               typ name
7711         | name, (FBytes|FUInt64) ->
7712             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7713             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
7714               typ name
7715         | name, FInt64 ->
7716             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7717             pr "                        PyLong_FromLongLong (%s->%s));\n"
7718               typ name
7719         | name, FUInt32 ->
7720             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7721             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
7722               typ name
7723         | name, FInt32 ->
7724             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7725             pr "                        PyLong_FromLong (%s->%s));\n"
7726               typ name
7727         | name, FOptPercent ->
7728             pr "  if (%s->%s >= 0)\n" typ name;
7729             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
7730             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
7731               typ name;
7732             pr "  else {\n";
7733             pr "    Py_INCREF (Py_None);\n";
7734             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);\n" name;
7735             pr "  }\n"
7736         | name, FChar ->
7737             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7738             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
7739       ) cols;
7740       pr "  return dict;\n";
7741       pr "};\n";
7742       pr "\n";
7743
7744   ) structs;
7745
7746   (* Emit a put_TYPE_list function definition only if that function is used. *)
7747   List.iter (
7748     function
7749     | typ, (RStructListOnly | RStructAndList) ->
7750         (* generate the function for typ *)
7751         emit_put_list_function typ
7752     | typ, _ -> () (* empty *)
7753   ) rstructs_used;
7754
7755   (* Python wrapper functions. *)
7756   List.iter (
7757     fun (name, style, _, _, _, _, _) ->
7758       pr "static PyObject *\n";
7759       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
7760       pr "{\n";
7761
7762       pr "  PyObject *py_g;\n";
7763       pr "  guestfs_h *g;\n";
7764       pr "  PyObject *py_r;\n";
7765
7766       let error_code =
7767         match fst style with
7768         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
7769         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
7770         | RConstString _ | RConstOptString _ ->
7771             pr "  const char *r;\n"; "NULL"
7772         | RString _ -> pr "  char *r;\n"; "NULL"
7773         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
7774         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
7775         | RStructList (_, typ) ->
7776             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
7777         | RBufferOut _ ->
7778             pr "  char *r;\n";
7779             pr "  size_t size;\n";
7780             "NULL" in
7781
7782       List.iter (
7783         function
7784         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
7785             pr "  const char *%s;\n" n
7786         | OptString n -> pr "  const char *%s;\n" n
7787         | StringList n | DeviceList n ->
7788             pr "  PyObject *py_%s;\n" n;
7789             pr "  char **%s;\n" n
7790         | Bool n -> pr "  int %s;\n" n
7791         | Int n -> pr "  int %s;\n" n
7792       ) (snd style);
7793
7794       pr "\n";
7795
7796       (* Convert the parameters. *)
7797       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
7798       List.iter (
7799         function
7800         | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "s"
7801         | OptString _ -> pr "z"
7802         | StringList _ | DeviceList _ -> pr "O"
7803         | Bool _ -> pr "i" (* XXX Python has booleans? *)
7804         | Int _ -> pr "i"
7805       ) (snd style);
7806       pr ":guestfs_%s\",\n" name;
7807       pr "                         &py_g";
7808       List.iter (
7809         function
7810         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n -> pr ", &%s" n
7811         | OptString n -> pr ", &%s" n
7812         | StringList n | DeviceList n -> pr ", &py_%s" n
7813         | Bool n -> pr ", &%s" n
7814         | Int n -> pr ", &%s" n
7815       ) (snd style);
7816
7817       pr "))\n";
7818       pr "    return NULL;\n";
7819
7820       pr "  g = get_handle (py_g);\n";
7821       List.iter (
7822         function
7823         | Pathname _ | Device _ | Dev_or_Path _ | String _
7824         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
7825         | StringList n | DeviceList n ->
7826             pr "  %s = get_string_list (py_%s);\n" n n;
7827             pr "  if (!%s) return NULL;\n" n
7828       ) (snd style);
7829
7830       pr "\n";
7831
7832       pr "  r = guestfs_%s " name;
7833       generate_c_call_args ~handle:"g" style;
7834       pr ";\n";
7835
7836       List.iter (
7837         function
7838         | Pathname _ | Device _ | Dev_or_Path _ | String _
7839         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
7840         | StringList n | DeviceList n ->
7841             pr "  free (%s);\n" n
7842       ) (snd style);
7843
7844       pr "  if (r == %s) {\n" error_code;
7845       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
7846       pr "    return NULL;\n";
7847       pr "  }\n";
7848       pr "\n";
7849
7850       (match fst style with
7851        | RErr ->
7852            pr "  Py_INCREF (Py_None);\n";
7853            pr "  py_r = Py_None;\n"
7854        | RInt _
7855        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
7856        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
7857        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
7858        | RConstOptString _ ->
7859            pr "  if (r)\n";
7860            pr "    py_r = PyString_FromString (r);\n";
7861            pr "  else {\n";
7862            pr "    Py_INCREF (Py_None);\n";
7863            pr "    py_r = Py_None;\n";
7864            pr "  }\n"
7865        | RString _ ->
7866            pr "  py_r = PyString_FromString (r);\n";
7867            pr "  free (r);\n"
7868        | RStringList _ ->
7869            pr "  py_r = put_string_list (r);\n";
7870            pr "  free_strings (r);\n"
7871        | RStruct (_, typ) ->
7872            pr "  py_r = put_%s (r);\n" typ;
7873            pr "  guestfs_free_%s (r);\n" typ
7874        | RStructList (_, typ) ->
7875            pr "  py_r = put_%s_list (r);\n" typ;
7876            pr "  guestfs_free_%s_list (r);\n" typ
7877        | RHashtable n ->
7878            pr "  py_r = put_table (r);\n";
7879            pr "  free_strings (r);\n"
7880        | RBufferOut _ ->
7881            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
7882            pr "  free (r);\n"
7883       );
7884
7885       pr "  return py_r;\n";
7886       pr "}\n";
7887       pr "\n"
7888   ) all_functions;
7889
7890   (* Table of functions. *)
7891   pr "static PyMethodDef methods[] = {\n";
7892   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
7893   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
7894   List.iter (
7895     fun (name, _, _, _, _, _, _) ->
7896       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
7897         name name
7898   ) all_functions;
7899   pr "  { NULL, NULL, 0, NULL }\n";
7900   pr "};\n";
7901   pr "\n";
7902
7903   (* Init function. *)
7904   pr "\
7905 void
7906 initlibguestfsmod (void)
7907 {
7908   static int initialized = 0;
7909
7910   if (initialized) return;
7911   Py_InitModule ((char *) \"libguestfsmod\", methods);
7912   initialized = 1;
7913 }
7914 "
7915
7916 (* Generate Python module. *)
7917 and generate_python_py () =
7918   generate_header HashStyle LGPLv2;
7919
7920   pr "\
7921 u\"\"\"Python bindings for libguestfs
7922
7923 import guestfs
7924 g = guestfs.GuestFS ()
7925 g.add_drive (\"guest.img\")
7926 g.launch ()
7927 parts = g.list_partitions ()
7928
7929 The guestfs module provides a Python binding to the libguestfs API
7930 for examining and modifying virtual machine disk images.
7931
7932 Amongst the things this is good for: making batch configuration
7933 changes to guests, getting disk used/free statistics (see also:
7934 virt-df), migrating between virtualization systems (see also:
7935 virt-p2v), performing partial backups, performing partial guest
7936 clones, cloning guests and changing registry/UUID/hostname info, and
7937 much else besides.
7938
7939 Libguestfs uses Linux kernel and qemu code, and can access any type of
7940 guest filesystem that Linux and qemu can, including but not limited
7941 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
7942 schemes, qcow, qcow2, vmdk.
7943
7944 Libguestfs provides ways to enumerate guest storage (eg. partitions,
7945 LVs, what filesystem is in each LV, etc.).  It can also run commands
7946 in the context of the guest.  Also you can access filesystems over FTP.
7947
7948 Errors which happen while using the API are turned into Python
7949 RuntimeError exceptions.
7950
7951 To create a guestfs handle you usually have to perform the following
7952 sequence of calls:
7953
7954 # Create the handle, call add_drive at least once, and possibly
7955 # several times if the guest has multiple block devices:
7956 g = guestfs.GuestFS ()
7957 g.add_drive (\"guest.img\")
7958
7959 # Launch the qemu subprocess and wait for it to become ready:
7960 g.launch ()
7961
7962 # Now you can issue commands, for example:
7963 logvols = g.lvs ()
7964
7965 \"\"\"
7966
7967 import libguestfsmod
7968
7969 class GuestFS:
7970     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
7971
7972     def __init__ (self):
7973         \"\"\"Create a new libguestfs handle.\"\"\"
7974         self._o = libguestfsmod.create ()
7975
7976     def __del__ (self):
7977         libguestfsmod.close (self._o)
7978
7979 ";
7980
7981   List.iter (
7982     fun (name, style, _, flags, _, _, longdesc) ->
7983       pr "    def %s " name;
7984       generate_py_call_args ~handle:"self" (snd style);
7985       pr ":\n";
7986
7987       if not (List.mem NotInDocs flags) then (
7988         let doc = replace_str longdesc "C<guestfs_" "C<g." in
7989         let doc =
7990           match fst style with
7991           | RErr | RInt _ | RInt64 _ | RBool _
7992           | RConstOptString _ | RConstString _
7993           | RString _ | RBufferOut _ -> doc
7994           | RStringList _ ->
7995               doc ^ "\n\nThis function returns a list of strings."
7996           | RStruct (_, typ) ->
7997               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
7998           | RStructList (_, typ) ->
7999               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
8000           | RHashtable _ ->
8001               doc ^ "\n\nThis function returns a dictionary." in
8002         let doc =
8003           if List.mem ProtocolLimitWarning flags then
8004             doc ^ "\n\n" ^ protocol_limit_warning
8005           else doc in
8006         let doc =
8007           if List.mem DangerWillRobinson flags then
8008             doc ^ "\n\n" ^ danger_will_robinson
8009           else doc in
8010         let doc =
8011           match deprecation_notice flags with
8012           | None -> doc
8013           | Some txt -> doc ^ "\n\n" ^ txt in
8014         let doc = pod2text ~width:60 name doc in
8015         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
8016         let doc = String.concat "\n        " doc in
8017         pr "        u\"\"\"%s\"\"\"\n" doc;
8018       );
8019       pr "        return libguestfsmod.%s " name;
8020       generate_py_call_args ~handle:"self._o" (snd style);
8021       pr "\n";
8022       pr "\n";
8023   ) all_functions
8024
8025 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
8026 and generate_py_call_args ~handle args =
8027   pr "(%s" handle;
8028   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
8029   pr ")"
8030
8031 (* Useful if you need the longdesc POD text as plain text.  Returns a
8032  * list of lines.
8033  *
8034  * Because this is very slow (the slowest part of autogeneration),
8035  * we memoize the results.
8036  *)
8037 and pod2text ~width name longdesc =
8038   let key = width, name, longdesc in
8039   try Hashtbl.find pod2text_memo key
8040   with Not_found ->
8041     let filename, chan = Filename.open_temp_file "gen" ".tmp" in
8042     fprintf chan "=head1 %s\n\n%s\n" name longdesc;
8043     close_out chan;
8044     let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
8045     let chan = Unix.open_process_in cmd in
8046     let lines = ref [] in
8047     let rec loop i =
8048       let line = input_line chan in
8049       if i = 1 then             (* discard the first line of output *)
8050         loop (i+1)
8051       else (
8052         let line = triml line in
8053         lines := line :: !lines;
8054         loop (i+1)
8055       ) in
8056     let lines = try loop 1 with End_of_file -> List.rev !lines in
8057     Unix.unlink filename;
8058     (match Unix.close_process_in chan with
8059      | Unix.WEXITED 0 -> ()
8060      | Unix.WEXITED i ->
8061          failwithf "pod2text: process exited with non-zero status (%d)" i
8062      | Unix.WSIGNALED i | Unix.WSTOPPED i ->
8063          failwithf "pod2text: process signalled or stopped by signal %d" i
8064     );
8065     Hashtbl.add pod2text_memo key lines;
8066     pod2text_memo_updated ();
8067     lines
8068
8069 (* Generate ruby bindings. *)
8070 and generate_ruby_c () =
8071   generate_header CStyle LGPLv2;
8072
8073   pr "\
8074 #include <stdio.h>
8075 #include <stdlib.h>
8076
8077 #include <ruby.h>
8078
8079 #include \"guestfs.h\"
8080
8081 #include \"extconf.h\"
8082
8083 /* For Ruby < 1.9 */
8084 #ifndef RARRAY_LEN
8085 #define RARRAY_LEN(r) (RARRAY((r))->len)
8086 #endif
8087
8088 static VALUE m_guestfs;                 /* guestfs module */
8089 static VALUE c_guestfs;                 /* guestfs_h handle */
8090 static VALUE e_Error;                   /* used for all errors */
8091
8092 static void ruby_guestfs_free (void *p)
8093 {
8094   if (!p) return;
8095   guestfs_close ((guestfs_h *) p);
8096 }
8097
8098 static VALUE ruby_guestfs_create (VALUE m)
8099 {
8100   guestfs_h *g;
8101
8102   g = guestfs_create ();
8103   if (!g)
8104     rb_raise (e_Error, \"failed to create guestfs handle\");
8105
8106   /* Don't print error messages to stderr by default. */
8107   guestfs_set_error_handler (g, NULL, NULL);
8108
8109   /* Wrap it, and make sure the close function is called when the
8110    * handle goes away.
8111    */
8112   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
8113 }
8114
8115 static VALUE ruby_guestfs_close (VALUE gv)
8116 {
8117   guestfs_h *g;
8118   Data_Get_Struct (gv, guestfs_h, g);
8119
8120   ruby_guestfs_free (g);
8121   DATA_PTR (gv) = NULL;
8122
8123   return Qnil;
8124 }
8125
8126 ";
8127
8128   List.iter (
8129     fun (name, style, _, _, _, _, _) ->
8130       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
8131       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
8132       pr ")\n";
8133       pr "{\n";
8134       pr "  guestfs_h *g;\n";
8135       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
8136       pr "  if (!g)\n";
8137       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
8138         name;
8139       pr "\n";
8140
8141       List.iter (
8142         function
8143         | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
8144             pr "  Check_Type (%sv, T_STRING);\n" n;
8145             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
8146             pr "  if (!%s)\n" n;
8147             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
8148             pr "              \"%s\", \"%s\");\n" n name
8149         | OptString n ->
8150             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
8151         | StringList n | DeviceList n ->
8152             pr "  char **%s;\n" n;
8153             pr "  Check_Type (%sv, T_ARRAY);\n" n;
8154             pr "  {\n";
8155             pr "    int i, len;\n";
8156             pr "    len = RARRAY_LEN (%sv);\n" n;
8157             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
8158               n;
8159             pr "    for (i = 0; i < len; ++i) {\n";
8160             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
8161             pr "      %s[i] = StringValueCStr (v);\n" n;
8162             pr "    }\n";
8163             pr "    %s[len] = NULL;\n" n;
8164             pr "  }\n";
8165         | Bool n ->
8166             pr "  int %s = RTEST (%sv);\n" n n
8167         | Int n ->
8168             pr "  int %s = NUM2INT (%sv);\n" n n
8169       ) (snd style);
8170       pr "\n";
8171
8172       let error_code =
8173         match fst style with
8174         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
8175         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
8176         | RConstString _ | RConstOptString _ ->
8177             pr "  const char *r;\n"; "NULL"
8178         | RString _ -> pr "  char *r;\n"; "NULL"
8179         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
8180         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
8181         | RStructList (_, typ) ->
8182             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
8183         | RBufferOut _ ->
8184             pr "  char *r;\n";
8185             pr "  size_t size;\n";
8186             "NULL" in
8187       pr "\n";
8188
8189       pr "  r = guestfs_%s " name;
8190       generate_c_call_args ~handle:"g" style;
8191       pr ";\n";
8192
8193       List.iter (
8194         function
8195         | Pathname _ | Device _ | Dev_or_Path _ | String _
8196         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
8197         | StringList n | DeviceList n ->
8198             pr "  free (%s);\n" n
8199       ) (snd style);
8200
8201       pr "  if (r == %s)\n" error_code;
8202       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
8203       pr "\n";
8204
8205       (match fst style with
8206        | RErr ->
8207            pr "  return Qnil;\n"
8208        | RInt _ | RBool _ ->
8209            pr "  return INT2NUM (r);\n"
8210        | RInt64 _ ->
8211            pr "  return ULL2NUM (r);\n"
8212        | RConstString _ ->
8213            pr "  return rb_str_new2 (r);\n";
8214        | RConstOptString _ ->
8215            pr "  if (r)\n";
8216            pr "    return rb_str_new2 (r);\n";
8217            pr "  else\n";
8218            pr "    return Qnil;\n";
8219        | RString _ ->
8220            pr "  VALUE rv = rb_str_new2 (r);\n";
8221            pr "  free (r);\n";
8222            pr "  return rv;\n";
8223        | RStringList _ ->
8224            pr "  int i, len = 0;\n";
8225            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
8226            pr "  VALUE rv = rb_ary_new2 (len);\n";
8227            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
8228            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
8229            pr "    free (r[i]);\n";
8230            pr "  }\n";
8231            pr "  free (r);\n";
8232            pr "  return rv;\n"
8233        | RStruct (_, typ) ->
8234            let cols = cols_of_struct typ in
8235            generate_ruby_struct_code typ cols
8236        | RStructList (_, typ) ->
8237            let cols = cols_of_struct typ in
8238            generate_ruby_struct_list_code typ cols
8239        | RHashtable _ ->
8240            pr "  VALUE rv = rb_hash_new ();\n";
8241            pr "  int i;\n";
8242            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
8243            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
8244            pr "    free (r[i]);\n";
8245            pr "    free (r[i+1]);\n";
8246            pr "  }\n";
8247            pr "  free (r);\n";
8248            pr "  return rv;\n"
8249        | RBufferOut _ ->
8250            pr "  VALUE rv = rb_str_new (r, size);\n";
8251            pr "  free (r);\n";
8252            pr "  return rv;\n";
8253       );
8254
8255       pr "}\n";
8256       pr "\n"
8257   ) all_functions;
8258
8259   pr "\
8260 /* Initialize the module. */
8261 void Init__guestfs ()
8262 {
8263   m_guestfs = rb_define_module (\"Guestfs\");
8264   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
8265   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
8266
8267   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
8268   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
8269
8270 ";
8271   (* Define the rest of the methods. *)
8272   List.iter (
8273     fun (name, style, _, _, _, _, _) ->
8274       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
8275       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
8276   ) all_functions;
8277
8278   pr "}\n"
8279
8280 (* Ruby code to return a struct. *)
8281 and generate_ruby_struct_code typ cols =
8282   pr "  VALUE rv = rb_hash_new ();\n";
8283   List.iter (
8284     function
8285     | name, FString ->
8286         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
8287     | name, FBuffer ->
8288         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
8289     | name, FUUID ->
8290         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
8291     | name, (FBytes|FUInt64) ->
8292         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
8293     | name, FInt64 ->
8294         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
8295     | name, FUInt32 ->
8296         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
8297     | name, FInt32 ->
8298         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
8299     | name, FOptPercent ->
8300         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
8301     | name, FChar -> (* XXX wrong? *)
8302         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
8303   ) cols;
8304   pr "  guestfs_free_%s (r);\n" typ;
8305   pr "  return rv;\n"
8306
8307 (* Ruby code to return a struct list. *)
8308 and generate_ruby_struct_list_code typ cols =
8309   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
8310   pr "  int i;\n";
8311   pr "  for (i = 0; i < r->len; ++i) {\n";
8312   pr "    VALUE hv = rb_hash_new ();\n";
8313   List.iter (
8314     function
8315     | name, FString ->
8316         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
8317     | name, FBuffer ->
8318         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
8319     | name, FUUID ->
8320         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
8321     | name, (FBytes|FUInt64) ->
8322         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
8323     | name, FInt64 ->
8324         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
8325     | name, FUInt32 ->
8326         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
8327     | name, FInt32 ->
8328         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
8329     | name, FOptPercent ->
8330         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
8331     | name, FChar -> (* XXX wrong? *)
8332         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
8333   ) cols;
8334   pr "    rb_ary_push (rv, hv);\n";
8335   pr "  }\n";
8336   pr "  guestfs_free_%s_list (r);\n" typ;
8337   pr "  return rv;\n"
8338
8339 (* Generate Java bindings GuestFS.java file. *)
8340 and generate_java_java () =
8341   generate_header CStyle LGPLv2;
8342
8343   pr "\
8344 package com.redhat.et.libguestfs;
8345
8346 import java.util.HashMap;
8347 import com.redhat.et.libguestfs.LibGuestFSException;
8348 import com.redhat.et.libguestfs.PV;
8349 import com.redhat.et.libguestfs.VG;
8350 import com.redhat.et.libguestfs.LV;
8351 import com.redhat.et.libguestfs.Stat;
8352 import com.redhat.et.libguestfs.StatVFS;
8353 import com.redhat.et.libguestfs.IntBool;
8354 import com.redhat.et.libguestfs.Dirent;
8355
8356 /**
8357  * The GuestFS object is a libguestfs handle.
8358  *
8359  * @author rjones
8360  */
8361 public class GuestFS {
8362   // Load the native code.
8363   static {
8364     System.loadLibrary (\"guestfs_jni\");
8365   }
8366
8367   /**
8368    * The native guestfs_h pointer.
8369    */
8370   long g;
8371
8372   /**
8373    * Create a libguestfs handle.
8374    *
8375    * @throws LibGuestFSException
8376    */
8377   public GuestFS () throws LibGuestFSException
8378   {
8379     g = _create ();
8380   }
8381   private native long _create () throws LibGuestFSException;
8382
8383   /**
8384    * Close a libguestfs handle.
8385    *
8386    * You can also leave handles to be collected by the garbage
8387    * collector, but this method ensures that the resources used
8388    * by the handle are freed up immediately.  If you call any
8389    * other methods after closing the handle, you will get an
8390    * exception.
8391    *
8392    * @throws LibGuestFSException
8393    */
8394   public void close () throws LibGuestFSException
8395   {
8396     if (g != 0)
8397       _close (g);
8398     g = 0;
8399   }
8400   private native void _close (long g) throws LibGuestFSException;
8401
8402   public void finalize () throws LibGuestFSException
8403   {
8404     close ();
8405   }
8406
8407 ";
8408
8409   List.iter (
8410     fun (name, style, _, flags, _, shortdesc, longdesc) ->
8411       if not (List.mem NotInDocs flags); then (
8412         let doc = replace_str longdesc "C<guestfs_" "C<g." in
8413         let doc =
8414           if List.mem ProtocolLimitWarning flags then
8415             doc ^ "\n\n" ^ protocol_limit_warning
8416           else doc in
8417         let doc =
8418           if List.mem DangerWillRobinson flags then
8419             doc ^ "\n\n" ^ danger_will_robinson
8420           else doc in
8421         let doc =
8422           match deprecation_notice flags with
8423           | None -> doc
8424           | Some txt -> doc ^ "\n\n" ^ txt in
8425         let doc = pod2text ~width:60 name doc in
8426         let doc = List.map (            (* RHBZ#501883 *)
8427           function
8428           | "" -> "<p>"
8429           | nonempty -> nonempty
8430         ) doc in
8431         let doc = String.concat "\n   * " doc in
8432
8433         pr "  /**\n";
8434         pr "   * %s\n" shortdesc;
8435         pr "   * <p>\n";
8436         pr "   * %s\n" doc;
8437         pr "   * @throws LibGuestFSException\n";
8438         pr "   */\n";
8439         pr "  ";
8440       );
8441       generate_java_prototype ~public:true ~semicolon:false name style;
8442       pr "\n";
8443       pr "  {\n";
8444       pr "    if (g == 0)\n";
8445       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
8446         name;
8447       pr "    ";
8448       if fst style <> RErr then pr "return ";
8449       pr "_%s " name;
8450       generate_java_call_args ~handle:"g" (snd style);
8451       pr ";\n";
8452       pr "  }\n";
8453       pr "  ";
8454       generate_java_prototype ~privat:true ~native:true name style;
8455       pr "\n";
8456       pr "\n";
8457   ) all_functions;
8458
8459   pr "}\n"
8460
8461 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
8462 and generate_java_call_args ~handle args =
8463   pr "(%s" handle;
8464   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
8465   pr ")"
8466
8467 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
8468     ?(semicolon=true) name style =
8469   if privat then pr "private ";
8470   if public then pr "public ";
8471   if native then pr "native ";
8472
8473   (* return type *)
8474   (match fst style with
8475    | RErr -> pr "void ";
8476    | RInt _ -> pr "int ";
8477    | RInt64 _ -> pr "long ";
8478    | RBool _ -> pr "boolean ";
8479    | RConstString _ | RConstOptString _ | RString _
8480    | RBufferOut _ -> pr "String ";
8481    | RStringList _ -> pr "String[] ";
8482    | RStruct (_, typ) ->
8483        let name = java_name_of_struct typ in
8484        pr "%s " name;
8485    | RStructList (_, typ) ->
8486        let name = java_name_of_struct typ in
8487        pr "%s[] " name;
8488    | RHashtable _ -> pr "HashMap<String,String> ";
8489   );
8490
8491   if native then pr "_%s " name else pr "%s " name;
8492   pr "(";
8493   let needs_comma = ref false in
8494   if native then (
8495     pr "long g";
8496     needs_comma := true
8497   );
8498
8499   (* args *)
8500   List.iter (
8501     fun arg ->
8502       if !needs_comma then pr ", ";
8503       needs_comma := true;
8504
8505       match arg with
8506       | Pathname n
8507       | Device n | Dev_or_Path n
8508       | String n
8509       | OptString n
8510       | FileIn n
8511       | FileOut n ->
8512           pr "String %s" n
8513       | StringList n | DeviceList n ->
8514           pr "String[] %s" n
8515       | Bool n ->
8516           pr "boolean %s" n
8517       | Int n ->
8518           pr "int %s" n
8519   ) (snd style);
8520
8521   pr ")\n";
8522   pr "    throws LibGuestFSException";
8523   if semicolon then pr ";"
8524
8525 and generate_java_struct jtyp cols =
8526   generate_header CStyle LGPLv2;
8527
8528   pr "\
8529 package com.redhat.et.libguestfs;
8530
8531 /**
8532  * Libguestfs %s structure.
8533  *
8534  * @author rjones
8535  * @see GuestFS
8536  */
8537 public class %s {
8538 " jtyp jtyp;
8539
8540   List.iter (
8541     function
8542     | name, FString
8543     | name, FUUID
8544     | name, FBuffer -> pr "  public String %s;\n" name
8545     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
8546     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
8547     | name, FChar -> pr "  public char %s;\n" name
8548     | name, FOptPercent ->
8549         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
8550         pr "  public float %s;\n" name
8551   ) cols;
8552
8553   pr "}\n"
8554
8555 and generate_java_c () =
8556   generate_header CStyle LGPLv2;
8557
8558   pr "\
8559 #include <stdio.h>
8560 #include <stdlib.h>
8561 #include <string.h>
8562
8563 #include \"com_redhat_et_libguestfs_GuestFS.h\"
8564 #include \"guestfs.h\"
8565
8566 /* Note that this function returns.  The exception is not thrown
8567  * until after the wrapper function returns.
8568  */
8569 static void
8570 throw_exception (JNIEnv *env, const char *msg)
8571 {
8572   jclass cl;
8573   cl = (*env)->FindClass (env,
8574                           \"com/redhat/et/libguestfs/LibGuestFSException\");
8575   (*env)->ThrowNew (env, cl, msg);
8576 }
8577
8578 JNIEXPORT jlong JNICALL
8579 Java_com_redhat_et_libguestfs_GuestFS__1create
8580   (JNIEnv *env, jobject obj)
8581 {
8582   guestfs_h *g;
8583
8584   g = guestfs_create ();
8585   if (g == NULL) {
8586     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
8587     return 0;
8588   }
8589   guestfs_set_error_handler (g, NULL, NULL);
8590   return (jlong) (long) g;
8591 }
8592
8593 JNIEXPORT void JNICALL
8594 Java_com_redhat_et_libguestfs_GuestFS__1close
8595   (JNIEnv *env, jobject obj, jlong jg)
8596 {
8597   guestfs_h *g = (guestfs_h *) (long) jg;
8598   guestfs_close (g);
8599 }
8600
8601 ";
8602
8603   List.iter (
8604     fun (name, style, _, _, _, _, _) ->
8605       pr "JNIEXPORT ";
8606       (match fst style with
8607        | RErr -> pr "void ";
8608        | RInt _ -> pr "jint ";
8609        | RInt64 _ -> pr "jlong ";
8610        | RBool _ -> pr "jboolean ";
8611        | RConstString _ | RConstOptString _ | RString _
8612        | RBufferOut _ -> pr "jstring ";
8613        | RStruct _ | RHashtable _ ->
8614            pr "jobject ";
8615        | RStringList _ | RStructList _ ->
8616            pr "jobjectArray ";
8617       );
8618       pr "JNICALL\n";
8619       pr "Java_com_redhat_et_libguestfs_GuestFS_";
8620       pr "%s" (replace_str ("_" ^ name) "_" "_1");
8621       pr "\n";
8622       pr "  (JNIEnv *env, jobject obj, jlong jg";
8623       List.iter (
8624         function
8625         | Pathname n
8626         | Device n | Dev_or_Path n
8627         | String n
8628         | OptString n
8629         | FileIn n
8630         | FileOut n ->
8631             pr ", jstring j%s" n
8632         | StringList n | DeviceList n ->
8633             pr ", jobjectArray j%s" n
8634         | Bool n ->
8635             pr ", jboolean j%s" n
8636         | Int n ->
8637             pr ", jint j%s" n
8638       ) (snd style);
8639       pr ")\n";
8640       pr "{\n";
8641       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
8642       let error_code, no_ret =
8643         match fst style with
8644         | RErr -> pr "  int r;\n"; "-1", ""
8645         | RBool _
8646         | RInt _ -> pr "  int r;\n"; "-1", "0"
8647         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
8648         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
8649         | RConstOptString _ -> pr "  const char *r;\n"; "NULL", "NULL"
8650         | RString _ ->
8651             pr "  jstring jr;\n";
8652             pr "  char *r;\n"; "NULL", "NULL"
8653         | RStringList _ ->
8654             pr "  jobjectArray jr;\n";
8655             pr "  int r_len;\n";
8656             pr "  jclass cl;\n";
8657             pr "  jstring jstr;\n";
8658             pr "  char **r;\n"; "NULL", "NULL"
8659         | RStruct (_, typ) ->
8660             pr "  jobject jr;\n";
8661             pr "  jclass cl;\n";
8662             pr "  jfieldID fl;\n";
8663             pr "  struct guestfs_%s *r;\n" typ; "NULL", "NULL"
8664         | RStructList (_, typ) ->
8665             pr "  jobjectArray jr;\n";
8666             pr "  jclass cl;\n";
8667             pr "  jfieldID fl;\n";
8668             pr "  jobject jfl;\n";
8669             pr "  struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
8670         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL"
8671         | RBufferOut _ ->
8672             pr "  jstring jr;\n";
8673             pr "  char *r;\n";
8674             pr "  size_t size;\n";
8675             "NULL", "NULL" in
8676       List.iter (
8677         function
8678         | Pathname n
8679         | Device n | Dev_or_Path n
8680         | String n
8681         | OptString n
8682         | FileIn n
8683         | FileOut n ->
8684             pr "  const char *%s;\n" n
8685         | StringList n | DeviceList n ->
8686             pr "  int %s_len;\n" n;
8687             pr "  const char **%s;\n" n
8688         | Bool n
8689         | Int n ->
8690             pr "  int %s;\n" n
8691       ) (snd style);
8692
8693       let needs_i =
8694         (match fst style with
8695          | RStringList _ | RStructList _ -> true
8696          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
8697          | RConstOptString _
8698          | RString _ | RBufferOut _ | RStruct _ | RHashtable _ -> false) ||
8699           List.exists (function
8700                        | StringList _ -> true
8701                        | DeviceList _ -> true
8702                        | _ -> false) (snd style) in
8703       if needs_i then
8704         pr "  int i;\n";
8705
8706       pr "\n";
8707
8708       (* Get the parameters. *)
8709       List.iter (
8710         function
8711         | Pathname n
8712         | Device n | Dev_or_Path n
8713         | String n
8714         | FileIn n
8715         | FileOut n ->
8716             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
8717         | OptString n ->
8718             (* This is completely undocumented, but Java null becomes
8719              * a NULL parameter.
8720              *)
8721             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
8722         | StringList n | DeviceList n ->
8723             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
8724             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
8725             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
8726             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
8727               n;
8728             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
8729             pr "  }\n";
8730             pr "  %s[%s_len] = NULL;\n" n n;
8731         | Bool n
8732         | Int n ->
8733             pr "  %s = j%s;\n" n n
8734       ) (snd style);
8735
8736       (* Make the call. *)
8737       pr "  r = guestfs_%s " name;
8738       generate_c_call_args ~handle:"g" style;
8739       pr ";\n";
8740
8741       (* Release the parameters. *)
8742       List.iter (
8743         function
8744         | Pathname n
8745         | Device n | Dev_or_Path n
8746         | String n
8747         | FileIn n
8748         | FileOut n ->
8749             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
8750         | OptString n ->
8751             pr "  if (j%s)\n" n;
8752             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
8753         | StringList n | DeviceList n ->
8754             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
8755             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
8756               n;
8757             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
8758             pr "  }\n";
8759             pr "  free (%s);\n" n
8760         | Bool n
8761         | Int n -> ()
8762       ) (snd style);
8763
8764       (* Check for errors. *)
8765       pr "  if (r == %s) {\n" error_code;
8766       pr "    throw_exception (env, guestfs_last_error (g));\n";
8767       pr "    return %s;\n" no_ret;
8768       pr "  }\n";
8769
8770       (* Return value. *)
8771       (match fst style with
8772        | RErr -> ()
8773        | RInt _ -> pr "  return (jint) r;\n"
8774        | RBool _ -> pr "  return (jboolean) r;\n"
8775        | RInt64 _ -> pr "  return (jlong) r;\n"
8776        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
8777        | RConstOptString _ ->
8778            pr "  return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
8779        | RString _ ->
8780            pr "  jr = (*env)->NewStringUTF (env, r);\n";
8781            pr "  free (r);\n";
8782            pr "  return jr;\n"
8783        | RStringList _ ->
8784            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
8785            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
8786            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
8787            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
8788            pr "  for (i = 0; i < r_len; ++i) {\n";
8789            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
8790            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
8791            pr "    free (r[i]);\n";
8792            pr "  }\n";
8793            pr "  free (r);\n";
8794            pr "  return jr;\n"
8795        | RStruct (_, typ) ->
8796            let jtyp = java_name_of_struct typ in
8797            let cols = cols_of_struct typ in
8798            generate_java_struct_return typ jtyp cols
8799        | RStructList (_, typ) ->
8800            let jtyp = java_name_of_struct typ in
8801            let cols = cols_of_struct typ in
8802            generate_java_struct_list_return typ jtyp cols
8803        | RHashtable _ ->
8804            (* XXX *)
8805            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
8806            pr "  return NULL;\n"
8807        | RBufferOut _ ->
8808            pr "  jr = (*env)->NewStringUTF (env, r); /* XXX size */\n";
8809            pr "  free (r);\n";
8810            pr "  return jr;\n"
8811       );
8812
8813       pr "}\n";
8814       pr "\n"
8815   ) all_functions
8816
8817 and generate_java_struct_return typ jtyp cols =
8818   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
8819   pr "  jr = (*env)->AllocObject (env, cl);\n";
8820   List.iter (
8821     function
8822     | name, FString ->
8823         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8824         pr "  (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
8825     | name, FUUID ->
8826         pr "  {\n";
8827         pr "    char s[33];\n";
8828         pr "    memcpy (s, r->%s, 32);\n" name;
8829         pr "    s[32] = 0;\n";
8830         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8831         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
8832         pr "  }\n";
8833     | name, FBuffer ->
8834         pr "  {\n";
8835         pr "    int len = r->%s_len;\n" name;
8836         pr "    char s[len+1];\n";
8837         pr "    memcpy (s, r->%s, len);\n" name;
8838         pr "    s[len] = 0;\n";
8839         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8840         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
8841         pr "  }\n";
8842     | name, (FBytes|FUInt64|FInt64) ->
8843         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
8844         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
8845     | name, (FUInt32|FInt32) ->
8846         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
8847         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
8848     | name, FOptPercent ->
8849         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
8850         pr "  (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
8851     | name, FChar ->
8852         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
8853         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
8854   ) cols;
8855   pr "  free (r);\n";
8856   pr "  return jr;\n"
8857
8858 and generate_java_struct_list_return typ jtyp cols =
8859   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
8860   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
8861   pr "  for (i = 0; i < r->len; ++i) {\n";
8862   pr "    jfl = (*env)->AllocObject (env, cl);\n";
8863   List.iter (
8864     function
8865     | name, FString ->
8866         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8867         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
8868     | name, FUUID ->
8869         pr "    {\n";
8870         pr "      char s[33];\n";
8871         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
8872         pr "      s[32] = 0;\n";
8873         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8874         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
8875         pr "    }\n";
8876     | name, FBuffer ->
8877         pr "    {\n";
8878         pr "      int len = r->val[i].%s_len;\n" name;
8879         pr "      char s[len+1];\n";
8880         pr "      memcpy (s, r->val[i].%s, len);\n" name;
8881         pr "      s[len] = 0;\n";
8882         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8883         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
8884         pr "    }\n";
8885     | name, (FBytes|FUInt64|FInt64) ->
8886         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
8887         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
8888     | name, (FUInt32|FInt32) ->
8889         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
8890         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
8891     | name, FOptPercent ->
8892         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
8893         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
8894     | name, FChar ->
8895         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
8896         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
8897   ) cols;
8898   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
8899   pr "  }\n";
8900   pr "  guestfs_free_%s_list (r);\n" typ;
8901   pr "  return jr;\n"
8902
8903 and generate_java_makefile_inc () =
8904   generate_header HashStyle GPLv2;
8905
8906   pr "java_built_sources = \\\n";
8907   List.iter (
8908     fun (typ, jtyp) ->
8909         pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp;
8910   ) java_structs;
8911   pr "\tcom/redhat/et/libguestfs/GuestFS.java\n"
8912
8913 and generate_haskell_hs () =
8914   generate_header HaskellStyle LGPLv2;
8915
8916   (* XXX We only know how to generate partial FFI for Haskell
8917    * at the moment.  Please help out!
8918    *)
8919   let can_generate style =
8920     match style with
8921     | RErr, _
8922     | RInt _, _
8923     | RInt64 _, _ -> true
8924     | RBool _, _
8925     | RConstString _, _
8926     | RConstOptString _, _
8927     | RString _, _
8928     | RStringList _, _
8929     | RStruct _, _
8930     | RStructList _, _
8931     | RHashtable _, _
8932     | RBufferOut _, _ -> false in
8933
8934   pr "\
8935 {-# INCLUDE <guestfs.h> #-}
8936 {-# LANGUAGE ForeignFunctionInterface #-}
8937
8938 module Guestfs (
8939   create";
8940
8941   (* List out the names of the actions we want to export. *)
8942   List.iter (
8943     fun (name, style, _, _, _, _, _) ->
8944       if can_generate style then pr ",\n  %s" name
8945   ) all_functions;
8946
8947   pr "
8948   ) where
8949 import Foreign
8950 import Foreign.C
8951 import Foreign.C.Types
8952 import IO
8953 import Control.Exception
8954 import Data.Typeable
8955
8956 data GuestfsS = GuestfsS            -- represents the opaque C struct
8957 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
8958 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
8959
8960 -- XXX define properly later XXX
8961 data PV = PV
8962 data VG = VG
8963 data LV = LV
8964 data IntBool = IntBool
8965 data Stat = Stat
8966 data StatVFS = StatVFS
8967 data Hashtable = Hashtable
8968
8969 foreign import ccall unsafe \"guestfs_create\" c_create
8970   :: IO GuestfsP
8971 foreign import ccall unsafe \"&guestfs_close\" c_close
8972   :: FunPtr (GuestfsP -> IO ())
8973 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
8974   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
8975
8976 create :: IO GuestfsH
8977 create = do
8978   p <- c_create
8979   c_set_error_handler p nullPtr nullPtr
8980   h <- newForeignPtr c_close p
8981   return h
8982
8983 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
8984   :: GuestfsP -> IO CString
8985
8986 -- last_error :: GuestfsH -> IO (Maybe String)
8987 -- last_error h = do
8988 --   str <- withForeignPtr h (\\p -> c_last_error p)
8989 --   maybePeek peekCString str
8990
8991 last_error :: GuestfsH -> IO (String)
8992 last_error h = do
8993   str <- withForeignPtr h (\\p -> c_last_error p)
8994   if (str == nullPtr)
8995     then return \"no error\"
8996     else peekCString str
8997
8998 ";
8999
9000   (* Generate wrappers for each foreign function. *)
9001   List.iter (
9002     fun (name, style, _, _, _, _, _) ->
9003       if can_generate style then (
9004         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
9005         pr "  :: ";
9006         generate_haskell_prototype ~handle:"GuestfsP" style;
9007         pr "\n";
9008         pr "\n";
9009         pr "%s :: " name;
9010         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
9011         pr "\n";
9012         pr "%s %s = do\n" name
9013           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
9014         pr "  r <- ";
9015         (* Convert pointer arguments using with* functions. *)
9016         List.iter (
9017           function
9018           | FileIn n
9019           | FileOut n
9020           | Pathname n | Device n | Dev_or_Path n | String n -> pr "withCString %s $ \\%s -> " n n
9021           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
9022           | StringList n | DeviceList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
9023           | Bool _ | Int _ -> ()
9024         ) (snd style);
9025         (* Convert integer arguments. *)
9026         let args =
9027           List.map (
9028             function
9029             | Bool n -> sprintf "(fromBool %s)" n
9030             | Int n -> sprintf "(fromIntegral %s)" n
9031             | FileIn n | FileOut n
9032             | Pathname n | Device n | Dev_or_Path n | String n | OptString n | StringList n | DeviceList n -> n
9033           ) (snd style) in
9034         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
9035           (String.concat " " ("p" :: args));
9036         (match fst style with
9037          | RErr | RInt _ | RInt64 _ | RBool _ ->
9038              pr "  if (r == -1)\n";
9039              pr "    then do\n";
9040              pr "      err <- last_error h\n";
9041              pr "      fail err\n";
9042          | RConstString _ | RConstOptString _ | RString _
9043          | RStringList _ | RStruct _
9044          | RStructList _ | RHashtable _ | RBufferOut _ ->
9045              pr "  if (r == nullPtr)\n";
9046              pr "    then do\n";
9047              pr "      err <- last_error h\n";
9048              pr "      fail err\n";
9049         );
9050         (match fst style with
9051          | RErr ->
9052              pr "    else return ()\n"
9053          | RInt _ ->
9054              pr "    else return (fromIntegral r)\n"
9055          | RInt64 _ ->
9056              pr "    else return (fromIntegral r)\n"
9057          | RBool _ ->
9058              pr "    else return (toBool r)\n"
9059          | RConstString _
9060          | RConstOptString _
9061          | RString _
9062          | RStringList _
9063          | RStruct _
9064          | RStructList _
9065          | RHashtable _
9066          | RBufferOut _ ->
9067              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
9068         );
9069         pr "\n";
9070       )
9071   ) all_functions
9072
9073 and generate_haskell_prototype ~handle ?(hs = false) style =
9074   pr "%s -> " handle;
9075   let string = if hs then "String" else "CString" in
9076   let int = if hs then "Int" else "CInt" in
9077   let bool = if hs then "Bool" else "CInt" in
9078   let int64 = if hs then "Integer" else "Int64" in
9079   List.iter (
9080     fun arg ->
9081       (match arg with
9082        | Pathname _ | Device _ | Dev_or_Path _ | String _ -> pr "%s" string
9083        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
9084        | StringList _ | DeviceList _ -> if hs then pr "[String]" else pr "Ptr CString"
9085        | Bool _ -> pr "%s" bool
9086        | Int _ -> pr "%s" int
9087        | FileIn _ -> pr "%s" string
9088        | FileOut _ -> pr "%s" string
9089       );
9090       pr " -> ";
9091   ) (snd style);
9092   pr "IO (";
9093   (match fst style with
9094    | RErr -> if not hs then pr "CInt"
9095    | RInt _ -> pr "%s" int
9096    | RInt64 _ -> pr "%s" int64
9097    | RBool _ -> pr "%s" bool
9098    | RConstString _ -> pr "%s" string
9099    | RConstOptString _ -> pr "Maybe %s" string
9100    | RString _ -> pr "%s" string
9101    | RStringList _ -> pr "[%s]" string
9102    | RStruct (_, typ) ->
9103        let name = java_name_of_struct typ in
9104        pr "%s" name
9105    | RStructList (_, typ) ->
9106        let name = java_name_of_struct typ in
9107        pr "[%s]" name
9108    | RHashtable _ -> pr "Hashtable"
9109    | RBufferOut _ -> pr "%s" string
9110   );
9111   pr ")"
9112
9113 and generate_bindtests () =
9114   generate_header CStyle LGPLv2;
9115
9116   pr "\
9117 #include <stdio.h>
9118 #include <stdlib.h>
9119 #include <inttypes.h>
9120 #include <string.h>
9121
9122 #include \"guestfs.h\"
9123 #include \"guestfs-internal-actions.h\"
9124 #include \"guestfs_protocol.h\"
9125
9126 #define error guestfs_error
9127 #define safe_calloc guestfs_safe_calloc
9128 #define safe_malloc guestfs_safe_malloc
9129
9130 static void
9131 print_strings (char *const *argv)
9132 {
9133   int argc;
9134
9135   printf (\"[\");
9136   for (argc = 0; argv[argc] != NULL; ++argc) {
9137     if (argc > 0) printf (\", \");
9138     printf (\"\\\"%%s\\\"\", argv[argc]);
9139   }
9140   printf (\"]\\n\");
9141 }
9142
9143 /* The test0 function prints its parameters to stdout. */
9144 ";
9145
9146   let test0, tests =
9147     match test_functions with
9148     | [] -> assert false
9149     | test0 :: tests -> test0, tests in
9150
9151   let () =
9152     let (name, style, _, _, _, _, _) = test0 in
9153     generate_prototype ~extern:false ~semicolon:false ~newline:true
9154       ~handle:"g" ~prefix:"guestfs__" name style;
9155     pr "{\n";
9156     List.iter (
9157       function
9158       | Pathname n
9159       | Device n | Dev_or_Path n
9160       | String n
9161       | FileIn n
9162       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
9163       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
9164       | StringList n | DeviceList n -> pr "  print_strings (%s);\n" n
9165       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
9166       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
9167     ) (snd style);
9168     pr "  /* Java changes stdout line buffering so we need this: */\n";
9169     pr "  fflush (stdout);\n";
9170     pr "  return 0;\n";
9171     pr "}\n";
9172     pr "\n" in
9173
9174   List.iter (
9175     fun (name, style, _, _, _, _, _) ->
9176       if String.sub name (String.length name - 3) 3 <> "err" then (
9177         pr "/* Test normal return. */\n";
9178         generate_prototype ~extern:false ~semicolon:false ~newline:true
9179           ~handle:"g" ~prefix:"guestfs__" name style;
9180         pr "{\n";
9181         (match fst style with
9182          | RErr ->
9183              pr "  return 0;\n"
9184          | RInt _ ->
9185              pr "  int r;\n";
9186              pr "  sscanf (val, \"%%d\", &r);\n";
9187              pr "  return r;\n"
9188          | RInt64 _ ->
9189              pr "  int64_t r;\n";
9190              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
9191              pr "  return r;\n"
9192          | RBool _ ->
9193              pr "  return strcmp (val, \"true\") == 0;\n"
9194          | RConstString _
9195          | RConstOptString _ ->
9196              (* Can't return the input string here.  Return a static
9197               * string so we ensure we get a segfault if the caller
9198               * tries to free it.
9199               *)
9200              pr "  return \"static string\";\n"
9201          | RString _ ->
9202              pr "  return strdup (val);\n"
9203          | RStringList _ ->
9204              pr "  char **strs;\n";
9205              pr "  int n, i;\n";
9206              pr "  sscanf (val, \"%%d\", &n);\n";
9207              pr "  strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
9208              pr "  for (i = 0; i < n; ++i) {\n";
9209              pr "    strs[i] = safe_malloc (g, 16);\n";
9210              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
9211              pr "  }\n";
9212              pr "  strs[n] = NULL;\n";
9213              pr "  return strs;\n"
9214          | RStruct (_, typ) ->
9215              pr "  struct guestfs_%s *r;\n" typ;
9216              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
9217              pr "  return r;\n"
9218          | RStructList (_, typ) ->
9219              pr "  struct guestfs_%s_list *r;\n" typ;
9220              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
9221              pr "  sscanf (val, \"%%d\", &r->len);\n";
9222              pr "  r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
9223              pr "  return r;\n"
9224          | RHashtable _ ->
9225              pr "  char **strs;\n";
9226              pr "  int n, i;\n";
9227              pr "  sscanf (val, \"%%d\", &n);\n";
9228              pr "  strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
9229              pr "  for (i = 0; i < n; ++i) {\n";
9230              pr "    strs[i*2] = safe_malloc (g, 16);\n";
9231              pr "    strs[i*2+1] = safe_malloc (g, 16);\n";
9232              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
9233              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
9234              pr "  }\n";
9235              pr "  strs[n*2] = NULL;\n";
9236              pr "  return strs;\n"
9237          | RBufferOut _ ->
9238              pr "  return strdup (val);\n"
9239         );
9240         pr "}\n";
9241         pr "\n"
9242       ) else (
9243         pr "/* Test error return. */\n";
9244         generate_prototype ~extern:false ~semicolon:false ~newline:true
9245           ~handle:"g" ~prefix:"guestfs__" name style;
9246         pr "{\n";
9247         pr "  error (g, \"error\");\n";
9248         (match fst style with
9249          | RErr | RInt _ | RInt64 _ | RBool _ ->
9250              pr "  return -1;\n"
9251          | RConstString _ | RConstOptString _
9252          | RString _ | RStringList _ | RStruct _
9253          | RStructList _
9254          | RHashtable _
9255          | RBufferOut _ ->
9256              pr "  return NULL;\n"
9257         );
9258         pr "}\n";
9259         pr "\n"
9260       )
9261   ) tests
9262
9263 and generate_ocaml_bindtests () =
9264   generate_header OCamlStyle GPLv2;
9265
9266   pr "\
9267 let () =
9268   let g = Guestfs.create () in
9269 ";
9270
9271   let mkargs args =
9272     String.concat " " (
9273       List.map (
9274         function
9275         | CallString s -> "\"" ^ s ^ "\""
9276         | CallOptString None -> "None"
9277         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
9278         | CallStringList xs ->
9279             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
9280         | CallInt i when i >= 0 -> string_of_int i
9281         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
9282         | CallBool b -> string_of_bool b
9283       ) args
9284     )
9285   in
9286
9287   generate_lang_bindtests (
9288     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
9289   );
9290
9291   pr "print_endline \"EOF\"\n"
9292
9293 and generate_perl_bindtests () =
9294   pr "#!/usr/bin/perl -w\n";
9295   generate_header HashStyle GPLv2;
9296
9297   pr "\
9298 use strict;
9299
9300 use Sys::Guestfs;
9301
9302 my $g = Sys::Guestfs->new ();
9303 ";
9304
9305   let mkargs args =
9306     String.concat ", " (
9307       List.map (
9308         function
9309         | CallString s -> "\"" ^ s ^ "\""
9310         | CallOptString None -> "undef"
9311         | CallOptString (Some s) -> sprintf "\"%s\"" s
9312         | CallStringList xs ->
9313             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
9314         | CallInt i -> string_of_int i
9315         | CallBool b -> if b then "1" else "0"
9316       ) args
9317     )
9318   in
9319
9320   generate_lang_bindtests (
9321     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
9322   );
9323
9324   pr "print \"EOF\\n\"\n"
9325
9326 and generate_python_bindtests () =
9327   generate_header HashStyle GPLv2;
9328
9329   pr "\
9330 import guestfs
9331
9332 g = guestfs.GuestFS ()
9333 ";
9334
9335   let mkargs args =
9336     String.concat ", " (
9337       List.map (
9338         function
9339         | CallString s -> "\"" ^ s ^ "\""
9340         | CallOptString None -> "None"
9341         | CallOptString (Some s) -> sprintf "\"%s\"" s
9342         | CallStringList xs ->
9343             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
9344         | CallInt i -> string_of_int i
9345         | CallBool b -> if b then "1" else "0"
9346       ) args
9347     )
9348   in
9349
9350   generate_lang_bindtests (
9351     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
9352   );
9353
9354   pr "print \"EOF\"\n"
9355
9356 and generate_ruby_bindtests () =
9357   generate_header HashStyle GPLv2;
9358
9359   pr "\
9360 require 'guestfs'
9361
9362 g = Guestfs::create()
9363 ";
9364
9365   let mkargs args =
9366     String.concat ", " (
9367       List.map (
9368         function
9369         | CallString s -> "\"" ^ s ^ "\""
9370         | CallOptString None -> "nil"
9371         | CallOptString (Some s) -> sprintf "\"%s\"" s
9372         | CallStringList xs ->
9373             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
9374         | CallInt i -> string_of_int i
9375         | CallBool b -> string_of_bool b
9376       ) args
9377     )
9378   in
9379
9380   generate_lang_bindtests (
9381     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
9382   );
9383
9384   pr "print \"EOF\\n\"\n"
9385
9386 and generate_java_bindtests () =
9387   generate_header CStyle GPLv2;
9388
9389   pr "\
9390 import com.redhat.et.libguestfs.*;
9391
9392 public class Bindtests {
9393     public static void main (String[] argv)
9394     {
9395         try {
9396             GuestFS g = new GuestFS ();
9397 ";
9398
9399   let mkargs args =
9400     String.concat ", " (
9401       List.map (
9402         function
9403         | CallString s -> "\"" ^ s ^ "\""
9404         | CallOptString None -> "null"
9405         | CallOptString (Some s) -> sprintf "\"%s\"" s
9406         | CallStringList xs ->
9407             "new String[]{" ^
9408               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
9409         | CallInt i -> string_of_int i
9410         | CallBool b -> string_of_bool b
9411       ) args
9412     )
9413   in
9414
9415   generate_lang_bindtests (
9416     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
9417   );
9418
9419   pr "
9420             System.out.println (\"EOF\");
9421         }
9422         catch (Exception exn) {
9423             System.err.println (exn);
9424             System.exit (1);
9425         }
9426     }
9427 }
9428 "
9429
9430 and generate_haskell_bindtests () =
9431   generate_header HaskellStyle GPLv2;
9432
9433   pr "\
9434 module Bindtests where
9435 import qualified Guestfs
9436
9437 main = do
9438   g <- Guestfs.create
9439 ";
9440
9441   let mkargs args =
9442     String.concat " " (
9443       List.map (
9444         function
9445         | CallString s -> "\"" ^ s ^ "\""
9446         | CallOptString None -> "Nothing"
9447         | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
9448         | CallStringList xs ->
9449             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
9450         | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
9451         | CallInt i -> string_of_int i
9452         | CallBool true -> "True"
9453         | CallBool false -> "False"
9454       ) args
9455     )
9456   in
9457
9458   generate_lang_bindtests (
9459     fun f args -> pr "  Guestfs.%s g %s\n" f (mkargs args)
9460   );
9461
9462   pr "  putStrLn \"EOF\"\n"
9463
9464 (* Language-independent bindings tests - we do it this way to
9465  * ensure there is parity in testing bindings across all languages.
9466  *)
9467 and generate_lang_bindtests call =
9468   call "test0" [CallString "abc"; CallOptString (Some "def");
9469                 CallStringList []; CallBool false;
9470                 CallInt 0; CallString "123"; CallString "456"];
9471   call "test0" [CallString "abc"; CallOptString None;
9472                 CallStringList []; CallBool false;
9473                 CallInt 0; CallString "123"; CallString "456"];
9474   call "test0" [CallString ""; CallOptString (Some "def");
9475                 CallStringList []; CallBool false;
9476                 CallInt 0; CallString "123"; CallString "456"];
9477   call "test0" [CallString ""; CallOptString (Some "");
9478                 CallStringList []; CallBool false;
9479                 CallInt 0; CallString "123"; CallString "456"];
9480   call "test0" [CallString "abc"; CallOptString (Some "def");
9481                 CallStringList ["1"]; CallBool false;
9482                 CallInt 0; CallString "123"; CallString "456"];
9483   call "test0" [CallString "abc"; CallOptString (Some "def");
9484                 CallStringList ["1"; "2"]; CallBool false;
9485                 CallInt 0; CallString "123"; CallString "456"];
9486   call "test0" [CallString "abc"; CallOptString (Some "def");
9487                 CallStringList ["1"]; CallBool true;
9488                 CallInt 0; CallString "123"; CallString "456"];
9489   call "test0" [CallString "abc"; CallOptString (Some "def");
9490                 CallStringList ["1"]; CallBool false;
9491                 CallInt (-1); CallString "123"; CallString "456"];
9492   call "test0" [CallString "abc"; CallOptString (Some "def");
9493                 CallStringList ["1"]; CallBool false;
9494                 CallInt (-2); CallString "123"; CallString "456"];
9495   call "test0" [CallString "abc"; CallOptString (Some "def");
9496                 CallStringList ["1"]; CallBool false;
9497                 CallInt 1; CallString "123"; CallString "456"];
9498   call "test0" [CallString "abc"; CallOptString (Some "def");
9499                 CallStringList ["1"]; CallBool false;
9500                 CallInt 2; CallString "123"; CallString "456"];
9501   call "test0" [CallString "abc"; CallOptString (Some "def");
9502                 CallStringList ["1"]; CallBool false;
9503                 CallInt 4095; CallString "123"; CallString "456"];
9504   call "test0" [CallString "abc"; CallOptString (Some "def");
9505                 CallStringList ["1"]; CallBool false;
9506                 CallInt 0; CallString ""; CallString ""]
9507
9508 (* XXX Add here tests of the return and error functions. *)
9509
9510 (* This is used to generate the src/MAX_PROC_NR file which
9511  * contains the maximum procedure number, a surrogate for the
9512  * ABI version number.  See src/Makefile.am for the details.
9513  *)
9514 and generate_max_proc_nr () =
9515   let proc_nrs = List.map (
9516     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
9517   ) daemon_functions in
9518
9519   let max_proc_nr = List.fold_left max 0 proc_nrs in
9520
9521   pr "%d\n" max_proc_nr
9522
9523 let output_to filename =
9524   let filename_new = filename ^ ".new" in
9525   chan := open_out filename_new;
9526   let close () =
9527     close_out !chan;
9528     chan := stdout;
9529
9530     (* Is the new file different from the current file? *)
9531     if Sys.file_exists filename && files_equal filename filename_new then
9532       Unix.unlink filename_new          (* same, so skip it *)
9533     else (
9534       (* different, overwrite old one *)
9535       (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
9536       Unix.rename filename_new filename;
9537       Unix.chmod filename 0o444;
9538       printf "written %s\n%!" filename;
9539     )
9540   in
9541   close
9542
9543 (* Main program. *)
9544 let () =
9545   check_functions ();
9546
9547   if not (Sys.file_exists "HACKING") then (
9548     eprintf "\
9549 You are probably running this from the wrong directory.
9550 Run it from the top source directory using the command
9551   src/generator.ml
9552 ";
9553     exit 1
9554   );
9555
9556   let close = output_to "src/guestfs_protocol.x" in
9557   generate_xdr ();
9558   close ();
9559
9560   let close = output_to "src/guestfs-structs.h" in
9561   generate_structs_h ();
9562   close ();
9563
9564   let close = output_to "src/guestfs-actions.h" in
9565   generate_actions_h ();
9566   close ();
9567
9568   let close = output_to "src/guestfs-internal-actions.h" in
9569   generate_internal_actions_h ();
9570   close ();
9571
9572   let close = output_to "src/guestfs-actions.c" in
9573   generate_client_actions ();
9574   close ();
9575
9576   let close = output_to "daemon/actions.h" in
9577   generate_daemon_actions_h ();
9578   close ();
9579
9580   let close = output_to "daemon/stubs.c" in
9581   generate_daemon_actions ();
9582   close ();
9583
9584   let close = output_to "daemon/names.c" in
9585   generate_daemon_names ();
9586   close ();
9587
9588   let close = output_to "capitests/tests.c" in
9589   generate_tests ();
9590   close ();
9591
9592   let close = output_to "src/guestfs-bindtests.c" in
9593   generate_bindtests ();
9594   close ();
9595
9596   let close = output_to "fish/cmds.c" in
9597   generate_fish_cmds ();
9598   close ();
9599
9600   let close = output_to "fish/completion.c" in
9601   generate_fish_completion ();
9602   close ();
9603
9604   let close = output_to "guestfs-structs.pod" in
9605   generate_structs_pod ();
9606   close ();
9607
9608   let close = output_to "guestfs-actions.pod" in
9609   generate_actions_pod ();
9610   close ();
9611
9612   let close = output_to "guestfish-actions.pod" in
9613   generate_fish_actions_pod ();
9614   close ();
9615
9616   let close = output_to "ocaml/guestfs.mli" in
9617   generate_ocaml_mli ();
9618   close ();
9619
9620   let close = output_to "ocaml/guestfs.ml" in
9621   generate_ocaml_ml ();
9622   close ();
9623
9624   let close = output_to "ocaml/guestfs_c_actions.c" in
9625   generate_ocaml_c ();
9626   close ();
9627
9628   let close = output_to "ocaml/bindtests.ml" in
9629   generate_ocaml_bindtests ();
9630   close ();
9631
9632   let close = output_to "perl/Guestfs.xs" in
9633   generate_perl_xs ();
9634   close ();
9635
9636   let close = output_to "perl/lib/Sys/Guestfs.pm" in
9637   generate_perl_pm ();
9638   close ();
9639
9640   let close = output_to "perl/bindtests.pl" in
9641   generate_perl_bindtests ();
9642   close ();
9643
9644   let close = output_to "python/guestfs-py.c" in
9645   generate_python_c ();
9646   close ();
9647
9648   let close = output_to "python/guestfs.py" in
9649   generate_python_py ();
9650   close ();
9651
9652   let close = output_to "python/bindtests.py" in
9653   generate_python_bindtests ();
9654   close ();
9655
9656   let close = output_to "ruby/ext/guestfs/_guestfs.c" in
9657   generate_ruby_c ();
9658   close ();
9659
9660   let close = output_to "ruby/bindtests.rb" in
9661   generate_ruby_bindtests ();
9662   close ();
9663
9664   let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
9665   generate_java_java ();
9666   close ();
9667
9668   List.iter (
9669     fun (typ, jtyp) ->
9670       let cols = cols_of_struct typ in
9671       let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
9672       let close = output_to filename in
9673       generate_java_struct jtyp cols;
9674       close ();
9675   ) java_structs;
9676
9677   let close = output_to "java/Makefile.inc" in
9678   generate_java_makefile_inc ();
9679   close ();
9680
9681   let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
9682   generate_java_c ();
9683   close ();
9684
9685   let close = output_to "java/Bindtests.java" in
9686   generate_java_bindtests ();
9687   close ();
9688
9689   let close = output_to "haskell/Guestfs.hs" in
9690   generate_haskell_hs ();
9691   close ();
9692
9693   let close = output_to "haskell/Bindtests.hs" in
9694   generate_haskell_bindtests ();
9695   close ();
9696
9697   let close = output_to "src/MAX_PROC_NR" in
9698   generate_max_proc_nr ();
9699   close ();
9700
9701   (* Always generate this file last, and unconditionally.  It's used
9702    * by the Makefile to know when we must re-run the generator.
9703    *)
9704   let chan = open_out "src/stamp-generator" in
9705   fprintf chan "1\n";
9706   close_out chan