e30f5ebfdfc1219f4450a651e74a629e0b2ec81d
[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   | OptString of string (* const char *name, may be NULL *)
138   | StringList of string(* list of strings (each string cannot be NULL) *)
139   | Bool of string      (* boolean *)
140   | Int of string       (* int (smallish ints, signed, <= 31 bits) *)
141     (* These are treated as filenames (simple string parameters) in
142      * the C API and bindings.  But in the RPC protocol, we transfer
143      * the actual file content up to or down from the daemon.
144      * FileIn: local machine -> daemon (in request)
145      * FileOut: daemon -> local machine (in reply)
146      * In guestfish (only), the special name "-" means read from
147      * stdin or write to stdout.
148      *)
149   | FileIn of string
150   | FileOut of string
151 (* Not implemented:
152     (* Opaque buffer which can contain arbitrary 8 bit data.
153      * In the C API, this is expressed as <char *, int> pair.
154      * Most other languages have a string type which can contain
155      * ASCII NUL.  We use whatever type is appropriate for each
156      * language.
157      * Buffers are limited by the total message size.  To transfer
158      * large blocks of data, use FileIn/FileOut parameters instead.
159      * To return an arbitrary buffer, use RBufferOut.
160      *)
161   | BufferIn of string
162 *)
163
164 type flags =
165   | ProtocolLimitWarning  (* display warning about protocol size limits *)
166   | DangerWillRobinson    (* flags particularly dangerous commands *)
167   | FishAlias of string   (* provide an alias for this cmd in guestfish *)
168   | FishAction of string  (* call this function in guestfish *)
169   | NotInFish             (* do not export via guestfish *)
170   | NotInDocs             (* do not add this function to documentation *)
171   | DeprecatedBy of string (* function is deprecated, use .. instead *)
172
173 (* You can supply zero or as many tests as you want per API call.
174  *
175  * Note that the test environment has 3 block devices, of size 500MB,
176  * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
177  * a fourth squashfs block device with some known files on it (/dev/sdd).
178  *
179  * Note for partitioning purposes, the 500MB device has 1015 cylinders.
180  * Number of cylinders was 63 for IDE emulated disks with precisely
181  * the same size.  How exactly this is calculated is a mystery.
182  *
183  * The squashfs block device (/dev/sdd) comes from images/test.sqsh.
184  *
185  * To be able to run the tests in a reasonable amount of time,
186  * the virtual machine and block devices are reused between tests.
187  * So don't try testing kill_subprocess :-x
188  *
189  * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
190  *
191  * Don't assume anything about the previous contents of the block
192  * devices.  Use 'Init*' to create some initial scenarios.
193  *
194  * You can add a prerequisite clause to any individual test.  This
195  * is a run-time check, which, if it fails, causes the test to be
196  * skipped.  Useful if testing a command which might not work on
197  * all variations of libguestfs builds.  A test that has prerequisite
198  * of 'Always' is run unconditionally.
199  *
200  * In addition, packagers can skip individual tests by setting the
201  * environment variables:     eg:
202  *   SKIP_TEST_<CMD>_<NUM>=1  SKIP_TEST_COMMAND_3=1  (skips test #3 of command)
203  *   SKIP_TEST_<CMD>=1        SKIP_TEST_ZEROFREE=1   (skips all zerofree tests)
204  *)
205 type tests = (test_init * test_prereq * test) list
206 and test =
207     (* Run the command sequence and just expect nothing to fail. *)
208   | TestRun of seq
209
210     (* Run the command sequence and expect the output of the final
211      * command to be the string.
212      *)
213   | TestOutput of seq * string
214
215     (* Run the command sequence and expect the output of the final
216      * command to be the list of strings.
217      *)
218   | TestOutputList of seq * string list
219
220     (* Run the command sequence and expect the output of the final
221      * command to be the list of block devices (could be either
222      * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
223      * character of each string).
224      *)
225   | TestOutputListOfDevices of seq * string list
226
227     (* Run the command sequence and expect the output of the final
228      * command to be the integer.
229      *)
230   | TestOutputInt of seq * int
231
232     (* Run the command sequence and expect the output of the final
233      * command to be <op> <int>, eg. ">=", "1".
234      *)
235   | TestOutputIntOp of seq * string * int
236
237     (* Run the command sequence and expect the output of the final
238      * command to be a true value (!= 0 or != NULL).
239      *)
240   | TestOutputTrue of seq
241
242     (* Run the command sequence and expect the output of the final
243      * command to be a false value (== 0 or == NULL, but not an error).
244      *)
245   | TestOutputFalse of seq
246
247     (* Run the command sequence and expect the output of the final
248      * command to be a list of the given length (but don't care about
249      * content).
250      *)
251   | TestOutputLength of seq * int
252
253     (* Run the command sequence and expect the output of the final
254      * command to be a buffer (RBufferOut), ie. string + size.
255      *)
256   | TestOutputBuffer of seq * string
257
258     (* Run the command sequence and expect the output of the final
259      * command to be a structure.
260      *)
261   | TestOutputStruct of seq * test_field_compare list
262
263     (* Run the command sequence and expect the final command (only)
264      * to fail.
265      *)
266   | TestLastFail of seq
267
268 and test_field_compare =
269   | CompareWithInt of string * int
270   | CompareWithIntOp of string * string * int
271   | CompareWithString of string * string
272   | CompareFieldsIntEq of string * string
273   | CompareFieldsStrEq of string * string
274
275 (* Test prerequisites. *)
276 and test_prereq =
277     (* Test always runs. *)
278   | Always
279
280     (* Test is currently disabled - eg. it fails, or it tests some
281      * unimplemented feature.
282      *)
283   | Disabled
284
285     (* 'string' is some C code (a function body) that should return
286      * true or false.  The test will run if the code returns true.
287      *)
288   | If of string
289
290     (* As for 'If' but the test runs _unless_ the code returns true. *)
291   | Unless of string
292
293 (* Some initial scenarios for testing. *)
294 and test_init =
295     (* Do nothing, block devices could contain random stuff including
296      * LVM PVs, and some filesystems might be mounted.  This is usually
297      * a bad idea.
298      *)
299   | InitNone
300
301     (* Block devices are empty and no filesystems are mounted. *)
302   | InitEmpty
303
304     (* /dev/sda contains a single partition /dev/sda1, which is formatted
305      * as ext2, empty [except for lost+found] and mounted on /.
306      * /dev/sdb and /dev/sdc may have random content.
307      * No LVM.
308      *)
309   | InitBasicFS
310
311     (* /dev/sda:
312      *   /dev/sda1 (is a PV):
313      *     /dev/VG/LV (size 8MB):
314      *       formatted as ext2, empty [except for lost+found], mounted on /
315      * /dev/sdb and /dev/sdc may have random content.
316      *)
317   | InitBasicFSonLVM
318
319     (* /dev/sdd (the squashfs, see images/ directory in source)
320      * is mounted on /
321      *)
322   | InitSquashFS
323
324 (* Sequence of commands for testing. *)
325 and seq = cmd list
326 and cmd = string list
327
328 (* Note about long descriptions: When referring to another
329  * action, use the format C<guestfs_other> (ie. the full name of
330  * the C function).  This will be replaced as appropriate in other
331  * language bindings.
332  *
333  * Apart from that, long descriptions are just perldoc paragraphs.
334  *)
335
336 (* These test functions are used in the language binding tests. *)
337
338 let test_all_args = [
339   String "str";
340   OptString "optstr";
341   StringList "strlist";
342   Bool "b";
343   Int "integer";
344   FileIn "filein";
345   FileOut "fileout";
346 ]
347
348 let test_all_rets = [
349   (* except for RErr, which is tested thoroughly elsewhere *)
350   "test0rint",         RInt "valout";
351   "test0rint64",       RInt64 "valout";
352   "test0rbool",        RBool "valout";
353   "test0rconststring", RConstString "valout";
354   "test0rconstoptstring", RConstOptString "valout";
355   "test0rstring",      RString "valout";
356   "test0rstringlist",  RStringList "valout";
357   "test0rstruct",      RStruct ("valout", "lvm_pv");
358   "test0rstructlist",  RStructList ("valout", "lvm_pv");
359   "test0rhashtable",   RHashtable "valout";
360 ]
361
362 let test_functions = [
363   ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
364    [],
365    "internal test function - do not use",
366    "\
367 This is an internal test function which is used to test whether
368 the automatically generated bindings can handle every possible
369 parameter type correctly.
370
371 It echos the contents of each parameter to stdout.
372
373 You probably don't want to call this function.");
374 ] @ List.flatten (
375   List.map (
376     fun (name, ret) ->
377       [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
378         [],
379         "internal test function - do not use",
380         "\
381 This is an internal test function which is used to test whether
382 the automatically generated bindings can handle every possible
383 return type correctly.
384
385 It converts string C<val> to the return type.
386
387 You probably don't want to call this function.");
388        (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
389         [],
390         "internal test function - do not use",
391         "\
392 This is an internal test function which is used to test whether
393 the automatically generated bindings can handle every possible
394 return type correctly.
395
396 This function always returns an error.
397
398 You probably don't want to call this function.")]
399   ) test_all_rets
400 )
401
402 (* non_daemon_functions are any functions which don't get processed
403  * in the daemon, eg. functions for setting and getting local
404  * configuration values.
405  *)
406
407 let non_daemon_functions = test_functions @ [
408   ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
409    [],
410    "launch the qemu subprocess",
411    "\
412 Internally libguestfs is implemented by running a virtual machine
413 using L<qemu(1)>.
414
415 You should call this after configuring the handle
416 (eg. adding drives) but before performing any actions.");
417
418   ("wait_ready", (RErr, []), -1, [NotInFish],
419    [],
420    "wait until the qemu subprocess launches",
421    "\
422 Internally libguestfs is implemented by running a virtual machine
423 using L<qemu(1)>.
424
425 You should call this after C<guestfs_launch> to wait for the launch
426 to complete.");
427
428   ("kill_subprocess", (RErr, []), -1, [],
429    [],
430    "kill the qemu subprocess",
431    "\
432 This kills the qemu subprocess.  You should never need to call this.");
433
434   ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
435    [],
436    "add an image to examine or modify",
437    "\
438 This function adds a virtual machine disk image C<filename> to the
439 guest.  The first time you call this function, the disk appears as IDE
440 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
441 so on.
442
443 You don't necessarily need to be root when using libguestfs.  However
444 you obviously do need sufficient permissions to access the filename
445 for whatever operations you want to perform (ie. read access if you
446 just want to read the image or write access if you want to modify the
447 image).
448
449 This is equivalent to the qemu parameter
450 C<-drive file=filename,cache=off,if=...>.
451
452 Note that this call checks for the existence of C<filename>.  This
453 stops you from specifying other types of drive which are supported
454 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
455 the general C<guestfs_config> call instead.");
456
457   ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
458    [],
459    "add a CD-ROM disk image to examine",
460    "\
461 This function adds a virtual CD-ROM disk image to the guest.
462
463 This is equivalent to the qemu parameter C<-cdrom filename>.
464
465 Note that this call checks for the existence of C<filename>.  This
466 stops you from specifying other types of drive which are supported
467 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
468 the general C<guestfs_config> call instead.");
469
470   ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
471    [],
472    "add a drive in snapshot mode (read-only)",
473    "\
474 This adds a drive in snapshot mode, making it effectively
475 read-only.
476
477 Note that writes to the device are allowed, and will be seen for
478 the duration of the guestfs handle, but they are written
479 to a temporary file which is discarded as soon as the guestfs
480 handle is closed.  We don't currently have any method to enable
481 changes to be committed, although qemu can support this.
482
483 This is equivalent to the qemu parameter
484 C<-drive file=filename,snapshot=on,if=...>.
485
486 Note that this call checks for the existence of C<filename>.  This
487 stops you from specifying other types of drive which are supported
488 by qemu such as C<nbd:> and C<http:> URLs.  To specify those, use
489 the general C<guestfs_config> call instead.");
490
491   ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
492    [],
493    "add qemu parameters",
494    "\
495 This can be used to add arbitrary qemu command line parameters
496 of the form C<-param value>.  Actually it's not quite arbitrary - we
497 prevent you from setting some parameters which would interfere with
498 parameters that we use.
499
500 The first character of C<param> string must be a C<-> (dash).
501
502 C<value> can be NULL.");
503
504   ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
505    [],
506    "set the qemu binary",
507    "\
508 Set the qemu binary that we will use.
509
510 The default is chosen when the library was compiled by the
511 configure script.
512
513 You can also override this by setting the C<LIBGUESTFS_QEMU>
514 environment variable.
515
516 Setting C<qemu> to C<NULL> restores the default qemu binary.");
517
518   ("get_qemu", (RConstString "qemu", []), -1, [],
519    [InitNone, Always, TestRun (
520       [["get_qemu"]])],
521    "get the qemu binary",
522    "\
523 Return the current qemu binary.
524
525 This is always non-NULL.  If it wasn't set already, then this will
526 return the default qemu binary name.");
527
528   ("set_path", (RErr, [String "path"]), -1, [FishAlias "path"],
529    [],
530    "set the search path",
531    "\
532 Set the path that libguestfs searches for kernel and initrd.img.
533
534 The default is C<$libdir/guestfs> unless overridden by setting
535 C<LIBGUESTFS_PATH> environment variable.
536
537 Setting C<path> to C<NULL> restores the default path.");
538
539   ("get_path", (RConstString "path", []), -1, [],
540    [InitNone, Always, TestRun (
541       [["get_path"]])],
542    "get the search path",
543    "\
544 Return the current search path.
545
546 This is always non-NULL.  If it wasn't set already, then this will
547 return the default path.");
548
549   ("set_append", (RErr, [OptString "append"]), -1, [FishAlias "append"],
550    [],
551    "add options to kernel command line",
552    "\
553 This function is used to add additional options to the
554 guest kernel command line.
555
556 The default is C<NULL> unless overridden by setting
557 C<LIBGUESTFS_APPEND> environment variable.
558
559 Setting C<append> to C<NULL> means I<no> additional options
560 are passed (libguestfs always adds a few of its own).");
561
562   ("get_append", (RConstOptString "append", []), -1, [],
563    (* This cannot be tested with the current framework.  The
564     * function can return NULL in normal operations, which the
565     * test framework interprets as an error.
566     *)
567    [],
568    "get the additional kernel options",
569    "\
570 Return the additional kernel options which are added to the
571 guest kernel command line.
572
573 If C<NULL> then no options are added.");
574
575   ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
576    [],
577    "set autosync mode",
578    "\
579 If C<autosync> is true, this enables autosync.  Libguestfs will make a
580 best effort attempt to run C<guestfs_umount_all> followed by
581 C<guestfs_sync> when the handle is closed
582 (also if the program exits without closing handles).
583
584 This is disabled by default (except in guestfish where it is
585 enabled by default).");
586
587   ("get_autosync", (RBool "autosync", []), -1, [],
588    [InitNone, Always, TestRun (
589       [["get_autosync"]])],
590    "get autosync mode",
591    "\
592 Get the autosync flag.");
593
594   ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
595    [],
596    "set verbose mode",
597    "\
598 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
599
600 Verbose messages are disabled unless the environment variable
601 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
602
603   ("get_verbose", (RBool "verbose", []), -1, [],
604    [],
605    "get verbose mode",
606    "\
607 This returns the verbose messages flag.");
608
609   ("is_ready", (RBool "ready", []), -1, [],
610    [InitNone, Always, TestOutputTrue (
611       [["is_ready"]])],
612    "is ready to accept commands",
613    "\
614 This returns true iff this handle is ready to accept commands
615 (in the C<READY> state).
616
617 For more information on states, see L<guestfs(3)>.");
618
619   ("is_config", (RBool "config", []), -1, [],
620    [InitNone, Always, TestOutputFalse (
621       [["is_config"]])],
622    "is in configuration state",
623    "\
624 This returns true iff this handle is being configured
625 (in the C<CONFIG> state).
626
627 For more information on states, see L<guestfs(3)>.");
628
629   ("is_launching", (RBool "launching", []), -1, [],
630    [InitNone, Always, TestOutputFalse (
631       [["is_launching"]])],
632    "is launching subprocess",
633    "\
634 This returns true iff this handle is launching the subprocess
635 (in the C<LAUNCHING> state).
636
637 For more information on states, see L<guestfs(3)>.");
638
639   ("is_busy", (RBool "busy", []), -1, [],
640    [InitNone, Always, TestOutputFalse (
641       [["is_busy"]])],
642    "is busy processing a command",
643    "\
644 This returns true iff this handle is busy processing a command
645 (in the C<BUSY> state).
646
647 For more information on states, see L<guestfs(3)>.");
648
649   ("get_state", (RInt "state", []), -1, [],
650    [],
651    "get the current state",
652    "\
653 This returns the current state as an opaque integer.  This is
654 only useful for printing debug and internal error messages.
655
656 For more information on states, see L<guestfs(3)>.");
657
658   ("set_busy", (RErr, []), -1, [NotInFish],
659    [],
660    "set state to busy",
661    "\
662 This sets the state to C<BUSY>.  This is only used when implementing
663 actions using the low-level API.
664
665 For more information on states, see L<guestfs(3)>.");
666
667   ("set_ready", (RErr, []), -1, [NotInFish],
668    [],
669    "set state to ready",
670    "\
671 This sets the state to C<READY>.  This is only used when implementing
672 actions using the low-level API.
673
674 For more information on states, see L<guestfs(3)>.");
675
676   ("end_busy", (RErr, []), -1, [NotInFish],
677    [],
678    "leave the busy state",
679    "\
680 This sets the state to C<READY>, or if in C<CONFIG> then it leaves the
681 state as is.  This is only used when implementing
682 actions using the low-level API.
683
684 For more information on states, see L<guestfs(3)>.");
685
686   ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
687    [InitNone, Always, TestOutputInt (
688       [["set_memsize"; "500"];
689        ["get_memsize"]], 500)],
690    "set memory allocated to the qemu subprocess",
691    "\
692 This sets the memory size in megabytes allocated to the
693 qemu subprocess.  This only has any effect if called before
694 C<guestfs_launch>.
695
696 You can also change this by setting the environment
697 variable C<LIBGUESTFS_MEMSIZE> before the handle is
698 created.
699
700 For more information on the architecture of libguestfs,
701 see L<guestfs(3)>.");
702
703   ("get_memsize", (RInt "memsize", []), -1, [],
704    [InitNone, Always, TestOutputIntOp (
705       [["get_memsize"]], ">=", 256)],
706    "get memory allocated to the qemu subprocess",
707    "\
708 This gets the memory size in megabytes allocated to the
709 qemu subprocess.
710
711 If C<guestfs_set_memsize> was not called
712 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
713 then this returns the compiled-in default value for memsize.
714
715 For more information on the architecture of libguestfs,
716 see L<guestfs(3)>.");
717
718   ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"],
719    [InitNone, Always, TestOutputIntOp (
720       [["get_pid"]], ">=", 1)],
721    "get PID of qemu subprocess",
722    "\
723 Return the process ID of the qemu subprocess.  If there is no
724 qemu subprocess, then this will return an error.
725
726 This is an internal call used for debugging and testing.");
727
728   ("version", (RStruct ("version", "version"), []), -1, [],
729    [InitNone, Always, TestOutputStruct (
730       [["version"]], [CompareWithInt ("major", 1)])],
731    "get the library version number",
732    "\
733 Return the libguestfs version number that the program is linked
734 against.
735
736 Note that because of dynamic linking this is not necessarily
737 the version of libguestfs that you compiled against.  You can
738 compile the program, and then at runtime dynamically link
739 against a completely different C<libguestfs.so> library.
740
741 This call was added in version C<1.0.58>.  In previous
742 versions of libguestfs there was no way to get the version
743 number.  From C code you can use ELF weak linking tricks to find out if
744 this symbol exists (if it doesn't, then it's an earlier version).
745
746 The call returns a structure with four elements.  The first
747 three (C<major>, C<minor> and C<release>) are numbers and
748 correspond to the usual version triplet.  The fourth element
749 (C<extra>) is a string and is normally empty, but may be
750 used for distro-specific information.
751
752 To construct the original version string:
753 C<$major.$minor.$release$extra>
754
755 I<Note:> Don't use this call to test for availability
756 of features.  Distro backports makes this unreliable.");
757
758 ]
759
760 (* daemon_functions are any functions which cause some action
761  * to take place in the daemon.
762  *)
763
764 let daemon_functions = [
765   ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [],
766    [InitEmpty, Always, TestOutput (
767       [["sfdiskM"; "/dev/sda"; ","];
768        ["mkfs"; "ext2"; "/dev/sda1"];
769        ["mount"; "/dev/sda1"; "/"];
770        ["write_file"; "/new"; "new file contents"; "0"];
771        ["cat"; "/new"]], "new file contents")],
772    "mount a guest disk at a position in the filesystem",
773    "\
774 Mount a guest disk at a position in the filesystem.  Block devices
775 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
776 the guest.  If those block devices contain partitions, they will have
777 the usual names (eg. C</dev/sda1>).  Also LVM C</dev/VG/LV>-style
778 names can be used.
779
780 The rules are the same as for L<mount(2)>:  A filesystem must
781 first be mounted on C</> before others can be mounted.  Other
782 filesystems can only be mounted on directories which already
783 exist.
784
785 The mounted filesystem is writable, if we have sufficient permissions
786 on the underlying device.
787
788 The filesystem options C<sync> and C<noatime> are set with this
789 call, in order to improve reliability.");
790
791   ("sync", (RErr, []), 2, [],
792    [ InitEmpty, Always, TestRun [["sync"]]],
793    "sync disks, writes are flushed through to the disk image",
794    "\
795 This syncs the disk, so that any writes are flushed through to the
796 underlying disk image.
797
798 You should always call this if you have modified a disk image, before
799 closing the handle.");
800
801   ("touch", (RErr, [String "path"]), 3, [],
802    [InitBasicFS, Always, TestOutputTrue (
803       [["touch"; "/new"];
804        ["exists"; "/new"]])],
805    "update file timestamps or create a new file",
806    "\
807 Touch acts like the L<touch(1)> command.  It can be used to
808 update the timestamps on a file, or, if the file does not exist,
809 to create a new zero-length file.");
810
811   ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning],
812    [InitSquashFS, Always, TestOutput (
813       [["cat"; "/known-2"]], "abcdef\n")],
814    "list the contents of a file",
815    "\
816 Return the contents of the file named C<path>.
817
818 Note that this function cannot correctly handle binary files
819 (specifically, files containing C<\\0> character which is treated
820 as end of string).  For those you need to use the C<guestfs_read_file>
821 or C<guestfs_download> functions which have a more complex interface.");
822
823   ("ll", (RString "listing", [String "directory"]), 5, [],
824    [], (* XXX Tricky to test because it depends on the exact format
825         * of the 'ls -l' command, which changes between F10 and F11.
826         *)
827    "list the files in a directory (long format)",
828    "\
829 List the files in C<directory> (relative to the root directory,
830 there is no cwd) in the format of 'ls -la'.
831
832 This command is mostly useful for interactive sessions.  It
833 is I<not> intended that you try to parse the output string.");
834
835   ("ls", (RStringList "listing", [String "directory"]), 6, [],
836    [InitBasicFS, Always, TestOutputList (
837       [["touch"; "/new"];
838        ["touch"; "/newer"];
839        ["touch"; "/newest"];
840        ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
841    "list the files in a directory",
842    "\
843 List the files in C<directory> (relative to the root directory,
844 there is no cwd).  The '.' and '..' entries are not returned, but
845 hidden files are shown.
846
847 This command is mostly useful for interactive sessions.  Programs
848 should probably use C<guestfs_readdir> instead.");
849
850   ("list_devices", (RStringList "devices", []), 7, [],
851    [InitEmpty, Always, TestOutputListOfDevices (
852       [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
853    "list the block devices",
854    "\
855 List all the block devices.
856
857 The full block device names are returned, eg. C</dev/sda>");
858
859   ("list_partitions", (RStringList "partitions", []), 8, [],
860    [InitBasicFS, Always, TestOutputListOfDevices (
861       [["list_partitions"]], ["/dev/sda1"]);
862     InitEmpty, Always, TestOutputListOfDevices (
863       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
864        ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
865    "list the partitions",
866    "\
867 List all the partitions detected on all block devices.
868
869 The full partition device names are returned, eg. C</dev/sda1>
870
871 This does not return logical volumes.  For that you will need to
872 call C<guestfs_lvs>.");
873
874   ("pvs", (RStringList "physvols", []), 9, [],
875    [InitBasicFSonLVM, Always, TestOutputListOfDevices (
876       [["pvs"]], ["/dev/sda1"]);
877     InitEmpty, Always, TestOutputListOfDevices (
878       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
879        ["pvcreate"; "/dev/sda1"];
880        ["pvcreate"; "/dev/sda2"];
881        ["pvcreate"; "/dev/sda3"];
882        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
883    "list the LVM physical volumes (PVs)",
884    "\
885 List all the physical volumes detected.  This is the equivalent
886 of the L<pvs(8)> command.
887
888 This returns a list of just the device names that contain
889 PVs (eg. C</dev/sda2>).
890
891 See also C<guestfs_pvs_full>.");
892
893   ("vgs", (RStringList "volgroups", []), 10, [],
894    [InitBasicFSonLVM, Always, TestOutputList (
895       [["vgs"]], ["VG"]);
896     InitEmpty, Always, TestOutputList (
897       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
898        ["pvcreate"; "/dev/sda1"];
899        ["pvcreate"; "/dev/sda2"];
900        ["pvcreate"; "/dev/sda3"];
901        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
902        ["vgcreate"; "VG2"; "/dev/sda3"];
903        ["vgs"]], ["VG1"; "VG2"])],
904    "list the LVM volume groups (VGs)",
905    "\
906 List all the volumes groups detected.  This is the equivalent
907 of the L<vgs(8)> command.
908
909 This returns a list of just the volume group names that were
910 detected (eg. C<VolGroup00>).
911
912 See also C<guestfs_vgs_full>.");
913
914   ("lvs", (RStringList "logvols", []), 11, [],
915    [InitBasicFSonLVM, Always, TestOutputList (
916       [["lvs"]], ["/dev/VG/LV"]);
917     InitEmpty, Always, TestOutputList (
918       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
919        ["pvcreate"; "/dev/sda1"];
920        ["pvcreate"; "/dev/sda2"];
921        ["pvcreate"; "/dev/sda3"];
922        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
923        ["vgcreate"; "VG2"; "/dev/sda3"];
924        ["lvcreate"; "LV1"; "VG1"; "50"];
925        ["lvcreate"; "LV2"; "VG1"; "50"];
926        ["lvcreate"; "LV3"; "VG2"; "50"];
927        ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
928    "list the LVM logical volumes (LVs)",
929    "\
930 List all the logical volumes detected.  This is the equivalent
931 of the L<lvs(8)> command.
932
933 This returns a list of the logical volume device names
934 (eg. C</dev/VolGroup00/LogVol00>).
935
936 See also C<guestfs_lvs_full>.");
937
938   ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [],
939    [], (* XXX how to test? *)
940    "list the LVM physical volumes (PVs)",
941    "\
942 List all the physical volumes detected.  This is the equivalent
943 of the L<pvs(8)> command.  The \"full\" version includes all fields.");
944
945   ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [],
946    [], (* XXX how to test? *)
947    "list the LVM volume groups (VGs)",
948    "\
949 List all the volumes groups detected.  This is the equivalent
950 of the L<vgs(8)> command.  The \"full\" version includes all fields.");
951
952   ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [],
953    [], (* XXX how to test? *)
954    "list the LVM logical volumes (LVs)",
955    "\
956 List all the logical volumes detected.  This is the equivalent
957 of the L<lvs(8)> command.  The \"full\" version includes all fields.");
958
959   ("read_lines", (RStringList "lines", [String "path"]), 15, [],
960    [InitSquashFS, Always, TestOutputList (
961       [["read_lines"; "/known-4"]], ["abc"; "def"; "ghi"]);
962     InitSquashFS, Always, TestOutputList (
963       [["read_lines"; "/empty"]], [])],
964    "read file as lines",
965    "\
966 Return the contents of the file named C<path>.
967
968 The file contents are returned as a list of lines.  Trailing
969 C<LF> and C<CRLF> character sequences are I<not> returned.
970
971 Note that this function cannot correctly handle binary files
972 (specifically, files containing C<\\0> character which is treated
973 as end of line).  For those you need to use the C<guestfs_read_file>
974 function which has a more complex interface.");
975
976   ("aug_init", (RErr, [String "root"; Int "flags"]), 16, [],
977    [], (* XXX Augeas code needs tests. *)
978    "create a new Augeas handle",
979    "\
980 Create a new Augeas handle for editing configuration files.
981 If there was any previous Augeas handle associated with this
982 guestfs session, then it is closed.
983
984 You must call this before using any other C<guestfs_aug_*>
985 commands.
986
987 C<root> is the filesystem root.  C<root> must not be NULL,
988 use C</> instead.
989
990 The flags are the same as the flags defined in
991 E<lt>augeas.hE<gt>, the logical I<or> of the following
992 integers:
993
994 =over 4
995
996 =item C<AUG_SAVE_BACKUP> = 1
997
998 Keep the original file with a C<.augsave> extension.
999
1000 =item C<AUG_SAVE_NEWFILE> = 2
1001
1002 Save changes into a file with extension C<.augnew>, and
1003 do not overwrite original.  Overrides C<AUG_SAVE_BACKUP>.
1004
1005 =item C<AUG_TYPE_CHECK> = 4
1006
1007 Typecheck lenses (can be expensive).
1008
1009 =item C<AUG_NO_STDINC> = 8
1010
1011 Do not use standard load path for modules.
1012
1013 =item C<AUG_SAVE_NOOP> = 16
1014
1015 Make save a no-op, just record what would have been changed.
1016
1017 =item C<AUG_NO_LOAD> = 32
1018
1019 Do not load the tree in C<guestfs_aug_init>.
1020
1021 =back
1022
1023 To close the handle, you can call C<guestfs_aug_close>.
1024
1025 To find out more about Augeas, see L<http://augeas.net/>.");
1026
1027   ("aug_close", (RErr, []), 26, [],
1028    [], (* XXX Augeas code needs tests. *)
1029    "close the current Augeas handle",
1030    "\
1031 Close the current Augeas handle and free up any resources
1032 used by it.  After calling this, you have to call
1033 C<guestfs_aug_init> again before you can use any other
1034 Augeas functions.");
1035
1036   ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
1037    [], (* XXX Augeas code needs tests. *)
1038    "define an Augeas variable",
1039    "\
1040 Defines an Augeas variable C<name> whose value is the result
1041 of evaluating C<expr>.  If C<expr> is NULL, then C<name> is
1042 undefined.
1043
1044 On success this returns the number of nodes in C<expr>, or
1045 C<0> if C<expr> evaluates to something which is not a nodeset.");
1046
1047   ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [],
1048    [], (* XXX Augeas code needs tests. *)
1049    "define an Augeas node",
1050    "\
1051 Defines a variable C<name> whose value is the result of
1052 evaluating C<expr>.
1053
1054 If C<expr> evaluates to an empty nodeset, a node is created,
1055 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
1056 C<name> will be the nodeset containing that single node.
1057
1058 On success this returns a pair containing the
1059 number of nodes in the nodeset, and a boolean flag
1060 if a node was created.");
1061
1062   ("aug_get", (RString "val", [String "path"]), 19, [],
1063    [], (* XXX Augeas code needs tests. *)
1064    "look up the value of an Augeas path",
1065    "\
1066 Look up the value associated with C<path>.  If C<path>
1067 matches exactly one node, the C<value> is returned.");
1068
1069   ("aug_set", (RErr, [String "path"; String "val"]), 20, [],
1070    [], (* XXX Augeas code needs tests. *)
1071    "set Augeas path to value",
1072    "\
1073 Set the value associated with C<path> to C<value>.");
1074
1075   ("aug_insert", (RErr, [String "path"; String "label"; Bool "before"]), 21, [],
1076    [], (* XXX Augeas code needs tests. *)
1077    "insert a sibling Augeas node",
1078    "\
1079 Create a new sibling C<label> for C<path>, inserting it into
1080 the tree before or after C<path> (depending on the boolean
1081 flag C<before>).
1082
1083 C<path> must match exactly one existing node in the tree, and
1084 C<label> must be a label, ie. not contain C</>, C<*> or end
1085 with a bracketed index C<[N]>.");
1086
1087   ("aug_rm", (RInt "nrnodes", [String "path"]), 22, [],
1088    [], (* XXX Augeas code needs tests. *)
1089    "remove an Augeas path",
1090    "\
1091 Remove C<path> and all of its children.
1092
1093 On success this returns the number of entries which were removed.");
1094
1095   ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
1096    [], (* XXX Augeas code needs tests. *)
1097    "move Augeas node",
1098    "\
1099 Move the node C<src> to C<dest>.  C<src> must match exactly
1100 one node.  C<dest> is overwritten if it exists.");
1101
1102   ("aug_match", (RStringList "matches", [String "path"]), 24, [],
1103    [], (* XXX Augeas code needs tests. *)
1104    "return Augeas nodes which match path",
1105    "\
1106 Returns a list of paths which match the path expression C<path>.
1107 The returned paths are sufficiently qualified so that they match
1108 exactly one node in the current tree.");
1109
1110   ("aug_save", (RErr, []), 25, [],
1111    [], (* XXX Augeas code needs tests. *)
1112    "write all pending Augeas changes to disk",
1113    "\
1114 This writes all pending changes to disk.
1115
1116 The flags which were passed to C<guestfs_aug_init> affect exactly
1117 how files are saved.");
1118
1119   ("aug_load", (RErr, []), 27, [],
1120    [], (* XXX Augeas code needs tests. *)
1121    "load files into the tree",
1122    "\
1123 Load files into the tree.
1124
1125 See C<aug_load> in the Augeas documentation for the full gory
1126 details.");
1127
1128   ("aug_ls", (RStringList "matches", [String "path"]), 28, [],
1129    [], (* XXX Augeas code needs tests. *)
1130    "list Augeas nodes under a path",
1131    "\
1132 This is just a shortcut for listing C<guestfs_aug_match>
1133 C<path/*> and sorting the resulting nodes into alphabetical order.");
1134
1135   ("rm", (RErr, [String "path"]), 29, [],
1136    [InitBasicFS, Always, TestRun
1137       [["touch"; "/new"];
1138        ["rm"; "/new"]];
1139     InitBasicFS, Always, TestLastFail
1140       [["rm"; "/new"]];
1141     InitBasicFS, Always, TestLastFail
1142       [["mkdir"; "/new"];
1143        ["rm"; "/new"]]],
1144    "remove a file",
1145    "\
1146 Remove the single file C<path>.");
1147
1148   ("rmdir", (RErr, [String "path"]), 30, [],
1149    [InitBasicFS, Always, TestRun
1150       [["mkdir"; "/new"];
1151        ["rmdir"; "/new"]];
1152     InitBasicFS, Always, TestLastFail
1153       [["rmdir"; "/new"]];
1154     InitBasicFS, Always, TestLastFail
1155       [["touch"; "/new"];
1156        ["rmdir"; "/new"]]],
1157    "remove a directory",
1158    "\
1159 Remove the single directory C<path>.");
1160
1161   ("rm_rf", (RErr, [String "path"]), 31, [],
1162    [InitBasicFS, Always, TestOutputFalse
1163       [["mkdir"; "/new"];
1164        ["mkdir"; "/new/foo"];
1165        ["touch"; "/new/foo/bar"];
1166        ["rm_rf"; "/new"];
1167        ["exists"; "/new"]]],
1168    "remove a file or directory recursively",
1169    "\
1170 Remove the file or directory C<path>, recursively removing the
1171 contents if its a directory.  This is like the C<rm -rf> shell
1172 command.");
1173
1174   ("mkdir", (RErr, [String "path"]), 32, [],
1175    [InitBasicFS, Always, TestOutputTrue
1176       [["mkdir"; "/new"];
1177        ["is_dir"; "/new"]];
1178     InitBasicFS, Always, TestLastFail
1179       [["mkdir"; "/new/foo/bar"]]],
1180    "create a directory",
1181    "\
1182 Create a directory named C<path>.");
1183
1184   ("mkdir_p", (RErr, [String "path"]), 33, [],
1185    [InitBasicFS, Always, TestOutputTrue
1186       [["mkdir_p"; "/new/foo/bar"];
1187        ["is_dir"; "/new/foo/bar"]];
1188     InitBasicFS, Always, TestOutputTrue
1189       [["mkdir_p"; "/new/foo/bar"];
1190        ["is_dir"; "/new/foo"]];
1191     InitBasicFS, Always, TestOutputTrue
1192       [["mkdir_p"; "/new/foo/bar"];
1193        ["is_dir"; "/new"]];
1194     (* Regression tests for RHBZ#503133: *)
1195     InitBasicFS, Always, TestRun
1196       [["mkdir"; "/new"];
1197        ["mkdir_p"; "/new"]];
1198     InitBasicFS, Always, TestLastFail
1199       [["touch"; "/new"];
1200        ["mkdir_p"; "/new"]]],
1201    "create a directory and parents",
1202    "\
1203 Create a directory named C<path>, creating any parent directories
1204 as necessary.  This is like the C<mkdir -p> shell command.");
1205
1206   ("chmod", (RErr, [Int "mode"; String "path"]), 34, [],
1207    [], (* XXX Need stat command to test *)
1208    "change file mode",
1209    "\
1210 Change the mode (permissions) of C<path> to C<mode>.  Only
1211 numeric modes are supported.");
1212
1213   ("chown", (RErr, [Int "owner"; Int "group"; String "path"]), 35, [],
1214    [], (* XXX Need stat command to test *)
1215    "change file owner and group",
1216    "\
1217 Change the file owner to C<owner> and group to C<group>.
1218
1219 Only numeric uid and gid are supported.  If you want to use
1220 names, you will need to locate and parse the password file
1221 yourself (Augeas support makes this relatively easy).");
1222
1223   ("exists", (RBool "existsflag", [String "path"]), 36, [],
1224    [InitSquashFS, Always, TestOutputTrue (
1225       [["exists"; "/empty"]]);
1226     InitSquashFS, Always, TestOutputTrue (
1227       [["exists"; "/directory"]])],
1228    "test if file or directory exists",
1229    "\
1230 This returns C<true> if and only if there is a file, directory
1231 (or anything) with the given C<path> name.
1232
1233 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1234
1235   ("is_file", (RBool "fileflag", [String "path"]), 37, [],
1236    [InitSquashFS, Always, TestOutputTrue (
1237       [["is_file"; "/known-1"]]);
1238     InitSquashFS, Always, TestOutputFalse (
1239       [["is_file"; "/directory"]])],
1240    "test if file exists",
1241    "\
1242 This returns C<true> if and only if there is a file
1243 with the given C<path> name.  Note that it returns false for
1244 other objects like directories.
1245
1246 See also C<guestfs_stat>.");
1247
1248   ("is_dir", (RBool "dirflag", [String "path"]), 38, [],
1249    [InitSquashFS, Always, TestOutputFalse (
1250       [["is_dir"; "/known-3"]]);
1251     InitSquashFS, Always, TestOutputTrue (
1252       [["is_dir"; "/directory"]])],
1253    "test if file exists",
1254    "\
1255 This returns C<true> if and only if there is a directory
1256 with the given C<path> name.  Note that it returns false for
1257 other objects like files.
1258
1259 See also C<guestfs_stat>.");
1260
1261   ("pvcreate", (RErr, [String "device"]), 39, [],
1262    [InitEmpty, Always, TestOutputListOfDevices (
1263       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1264        ["pvcreate"; "/dev/sda1"];
1265        ["pvcreate"; "/dev/sda2"];
1266        ["pvcreate"; "/dev/sda3"];
1267        ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1268    "create an LVM physical volume",
1269    "\
1270 This creates an LVM physical volume on the named C<device>,
1271 where C<device> should usually be a partition name such
1272 as C</dev/sda1>.");
1273
1274   ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
1275    [InitEmpty, Always, TestOutputList (
1276       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1277        ["pvcreate"; "/dev/sda1"];
1278        ["pvcreate"; "/dev/sda2"];
1279        ["pvcreate"; "/dev/sda3"];
1280        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1281        ["vgcreate"; "VG2"; "/dev/sda3"];
1282        ["vgs"]], ["VG1"; "VG2"])],
1283    "create an LVM volume group",
1284    "\
1285 This creates an LVM volume group called C<volgroup>
1286 from the non-empty list of physical volumes C<physvols>.");
1287
1288   ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
1289    [InitEmpty, Always, TestOutputList (
1290       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1291        ["pvcreate"; "/dev/sda1"];
1292        ["pvcreate"; "/dev/sda2"];
1293        ["pvcreate"; "/dev/sda3"];
1294        ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1295        ["vgcreate"; "VG2"; "/dev/sda3"];
1296        ["lvcreate"; "LV1"; "VG1"; "50"];
1297        ["lvcreate"; "LV2"; "VG1"; "50"];
1298        ["lvcreate"; "LV3"; "VG2"; "50"];
1299        ["lvcreate"; "LV4"; "VG2"; "50"];
1300        ["lvcreate"; "LV5"; "VG2"; "50"];
1301        ["lvs"]],
1302       ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1303        "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1304    "create an LVM volume group",
1305    "\
1306 This creates an LVM volume group called C<logvol>
1307 on the volume group C<volgroup>, with C<size> megabytes.");
1308
1309   ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [],
1310    [InitEmpty, Always, TestOutput (
1311       [["sfdiskM"; "/dev/sda"; ","];
1312        ["mkfs"; "ext2"; "/dev/sda1"];
1313        ["mount"; "/dev/sda1"; "/"];
1314        ["write_file"; "/new"; "new file contents"; "0"];
1315        ["cat"; "/new"]], "new file contents")],
1316    "make a filesystem",
1317    "\
1318 This creates a filesystem on C<device> (usually a partition
1319 or LVM logical volume).  The filesystem type is C<fstype>, for
1320 example C<ext3>.");
1321
1322   ("sfdisk", (RErr, [String "device";
1323                      Int "cyls"; Int "heads"; Int "sectors";
1324                      StringList "lines"]), 43, [DangerWillRobinson],
1325    [],
1326    "create partitions on a block device",
1327    "\
1328 This is a direct interface to the L<sfdisk(8)> program for creating
1329 partitions on block devices.
1330
1331 C<device> should be a block device, for example C</dev/sda>.
1332
1333 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1334 and sectors on the device, which are passed directly to sfdisk as
1335 the I<-C>, I<-H> and I<-S> parameters.  If you pass C<0> for any
1336 of these, then the corresponding parameter is omitted.  Usually for
1337 'large' disks, you can just pass C<0> for these, but for small
1338 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1339 out the right geometry and you will need to tell it.
1340
1341 C<lines> is a list of lines that we feed to C<sfdisk>.  For more
1342 information refer to the L<sfdisk(8)> manpage.
1343
1344 To create a single partition occupying the whole disk, you would
1345 pass C<lines> as a single element list, when the single element being
1346 the string C<,> (comma).
1347
1348 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>");
1349
1350   ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1351    [InitBasicFS, Always, TestOutput (
1352       [["write_file"; "/new"; "new file contents"; "0"];
1353        ["cat"; "/new"]], "new file contents");
1354     InitBasicFS, Always, TestOutput (
1355       [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1356        ["cat"; "/new"]], "\nnew file contents\n");
1357     InitBasicFS, Always, TestOutput (
1358       [["write_file"; "/new"; "\n\n"; "0"];
1359        ["cat"; "/new"]], "\n\n");
1360     InitBasicFS, Always, TestOutput (
1361       [["write_file"; "/new"; ""; "0"];
1362        ["cat"; "/new"]], "");
1363     InitBasicFS, Always, TestOutput (
1364       [["write_file"; "/new"; "\n\n\n"; "0"];
1365        ["cat"; "/new"]], "\n\n\n");
1366     InitBasicFS, Always, TestOutput (
1367       [["write_file"; "/new"; "\n"; "0"];
1368        ["cat"; "/new"]], "\n")],
1369    "create a file",
1370    "\
1371 This call creates a file called C<path>.  The contents of the
1372 file is the string C<content> (which can contain any 8 bit data),
1373 with length C<size>.
1374
1375 As a special case, if C<size> is C<0>
1376 then the length is calculated using C<strlen> (so in this case
1377 the content cannot contain embedded ASCII NULs).
1378
1379 I<NB.> Owing to a bug, writing content containing ASCII NUL
1380 characters does I<not> work, even if the length is specified.
1381 We hope to resolve this bug in a future version.  In the meantime
1382 use C<guestfs_upload>.");
1383
1384   ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1385    [InitEmpty, Always, TestOutputListOfDevices (
1386       [["sfdiskM"; "/dev/sda"; ","];
1387        ["mkfs"; "ext2"; "/dev/sda1"];
1388        ["mount"; "/dev/sda1"; "/"];
1389        ["mounts"]], ["/dev/sda1"]);
1390     InitEmpty, Always, TestOutputList (
1391       [["sfdiskM"; "/dev/sda"; ","];
1392        ["mkfs"; "ext2"; "/dev/sda1"];
1393        ["mount"; "/dev/sda1"; "/"];
1394        ["umount"; "/"];
1395        ["mounts"]], [])],
1396    "unmount a filesystem",
1397    "\
1398 This unmounts the given filesystem.  The filesystem may be
1399 specified either by its mountpoint (path) or the device which
1400 contains the filesystem.");
1401
1402   ("mounts", (RStringList "devices", []), 46, [],
1403    [InitBasicFS, Always, TestOutputListOfDevices (
1404       [["mounts"]], ["/dev/sda1"])],
1405    "show mounted filesystems",
1406    "\
1407 This returns the list of currently mounted filesystems.  It returns
1408 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1409
1410 Some internal mounts are not shown.
1411
1412 See also: C<guestfs_mountpoints>");
1413
1414   ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1415    [InitBasicFS, Always, TestOutputList (
1416       [["umount_all"];
1417        ["mounts"]], []);
1418     (* check that umount_all can unmount nested mounts correctly: *)
1419     InitEmpty, Always, TestOutputList (
1420       [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1421        ["mkfs"; "ext2"; "/dev/sda1"];
1422        ["mkfs"; "ext2"; "/dev/sda2"];
1423        ["mkfs"; "ext2"; "/dev/sda3"];
1424        ["mount"; "/dev/sda1"; "/"];
1425        ["mkdir"; "/mp1"];
1426        ["mount"; "/dev/sda2"; "/mp1"];
1427        ["mkdir"; "/mp1/mp2"];
1428        ["mount"; "/dev/sda3"; "/mp1/mp2"];
1429        ["mkdir"; "/mp1/mp2/mp3"];
1430        ["umount_all"];
1431        ["mounts"]], [])],
1432    "unmount all filesystems",
1433    "\
1434 This unmounts all mounted filesystems.
1435
1436 Some internal mounts are not unmounted by this call.");
1437
1438   ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
1439    [],
1440    "remove all LVM LVs, VGs and PVs",
1441    "\
1442 This command removes all LVM logical volumes, volume groups
1443 and physical volumes.");
1444
1445   ("file", (RString "description", [String "path"]), 49, [],
1446    [InitSquashFS, Always, TestOutput (
1447       [["file"; "/empty"]], "empty");
1448     InitSquashFS, Always, TestOutput (
1449       [["file"; "/known-1"]], "ASCII text");
1450     InitSquashFS, Always, TestLastFail (
1451       [["file"; "/notexists"]])],
1452    "determine file type",
1453    "\
1454 This call uses the standard L<file(1)> command to determine
1455 the type or contents of the file.  This also works on devices,
1456 for example to find out whether a partition contains a filesystem.
1457
1458 This call will also transparently look inside various types
1459 of compressed file.
1460
1461 The exact command which runs is C<file -zbsL path>.  Note in
1462 particular that the filename is not prepended to the output
1463 (the C<-b> option).");
1464
1465   ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1466    [InitBasicFS, Always, TestOutput (
1467       [["upload"; "test-command"; "/test-command"];
1468        ["chmod"; "0o755"; "/test-command"];
1469        ["command"; "/test-command 1"]], "Result1");
1470     InitBasicFS, Always, TestOutput (
1471       [["upload"; "test-command"; "/test-command"];
1472        ["chmod"; "0o755"; "/test-command"];
1473        ["command"; "/test-command 2"]], "Result2\n");
1474     InitBasicFS, Always, TestOutput (
1475       [["upload"; "test-command"; "/test-command"];
1476        ["chmod"; "0o755"; "/test-command"];
1477        ["command"; "/test-command 3"]], "\nResult3");
1478     InitBasicFS, Always, TestOutput (
1479       [["upload"; "test-command"; "/test-command"];
1480        ["chmod"; "0o755"; "/test-command"];
1481        ["command"; "/test-command 4"]], "\nResult4\n");
1482     InitBasicFS, Always, TestOutput (
1483       [["upload"; "test-command"; "/test-command"];
1484        ["chmod"; "0o755"; "/test-command"];
1485        ["command"; "/test-command 5"]], "\nResult5\n\n");
1486     InitBasicFS, Always, TestOutput (
1487       [["upload"; "test-command"; "/test-command"];
1488        ["chmod"; "0o755"; "/test-command"];
1489        ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1490     InitBasicFS, Always, TestOutput (
1491       [["upload"; "test-command"; "/test-command"];
1492        ["chmod"; "0o755"; "/test-command"];
1493        ["command"; "/test-command 7"]], "");
1494     InitBasicFS, Always, TestOutput (
1495       [["upload"; "test-command"; "/test-command"];
1496        ["chmod"; "0o755"; "/test-command"];
1497        ["command"; "/test-command 8"]], "\n");
1498     InitBasicFS, Always, TestOutput (
1499       [["upload"; "test-command"; "/test-command"];
1500        ["chmod"; "0o755"; "/test-command"];
1501        ["command"; "/test-command 9"]], "\n\n");
1502     InitBasicFS, Always, TestOutput (
1503       [["upload"; "test-command"; "/test-command"];
1504        ["chmod"; "0o755"; "/test-command"];
1505        ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1506     InitBasicFS, Always, TestOutput (
1507       [["upload"; "test-command"; "/test-command"];
1508        ["chmod"; "0o755"; "/test-command"];
1509        ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1510     InitBasicFS, Always, TestLastFail (
1511       [["upload"; "test-command"; "/test-command"];
1512        ["chmod"; "0o755"; "/test-command"];
1513        ["command"; "/test-command"]])],
1514    "run a command from the guest filesystem",
1515    "\
1516 This call runs a command from the guest filesystem.  The
1517 filesystem must be mounted, and must contain a compatible
1518 operating system (ie. something Linux, with the same
1519 or compatible processor architecture).
1520
1521 The single parameter is an argv-style list of arguments.
1522 The first element is the name of the program to run.
1523 Subsequent elements are parameters.  The list must be
1524 non-empty (ie. must contain a program name).  Note that
1525 the command runs directly, and is I<not> invoked via
1526 the shell (see C<guestfs_sh>).
1527
1528 The return value is anything printed to I<stdout> by
1529 the command.
1530
1531 If the command returns a non-zero exit status, then
1532 this function returns an error message.  The error message
1533 string is the content of I<stderr> from the command.
1534
1535 The C<$PATH> environment variable will contain at least
1536 C</usr/bin> and C</bin>.  If you require a program from
1537 another location, you should provide the full path in the
1538 first parameter.
1539
1540 Shared libraries and data files required by the program
1541 must be available on filesystems which are mounted in the
1542 correct places.  It is the caller's responsibility to ensure
1543 all filesystems that are needed are mounted at the right
1544 locations.");
1545
1546   ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1547    [InitBasicFS, Always, TestOutputList (
1548       [["upload"; "test-command"; "/test-command"];
1549        ["chmod"; "0o755"; "/test-command"];
1550        ["command_lines"; "/test-command 1"]], ["Result1"]);
1551     InitBasicFS, Always, TestOutputList (
1552       [["upload"; "test-command"; "/test-command"];
1553        ["chmod"; "0o755"; "/test-command"];
1554        ["command_lines"; "/test-command 2"]], ["Result2"]);
1555     InitBasicFS, Always, TestOutputList (
1556       [["upload"; "test-command"; "/test-command"];
1557        ["chmod"; "0o755"; "/test-command"];
1558        ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1559     InitBasicFS, Always, TestOutputList (
1560       [["upload"; "test-command"; "/test-command"];
1561        ["chmod"; "0o755"; "/test-command"];
1562        ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1563     InitBasicFS, Always, TestOutputList (
1564       [["upload"; "test-command"; "/test-command"];
1565        ["chmod"; "0o755"; "/test-command"];
1566        ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1567     InitBasicFS, Always, TestOutputList (
1568       [["upload"; "test-command"; "/test-command"];
1569        ["chmod"; "0o755"; "/test-command"];
1570        ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1571     InitBasicFS, Always, TestOutputList (
1572       [["upload"; "test-command"; "/test-command"];
1573        ["chmod"; "0o755"; "/test-command"];
1574        ["command_lines"; "/test-command 7"]], []);
1575     InitBasicFS, Always, TestOutputList (
1576       [["upload"; "test-command"; "/test-command"];
1577        ["chmod"; "0o755"; "/test-command"];
1578        ["command_lines"; "/test-command 8"]], [""]);
1579     InitBasicFS, Always, TestOutputList (
1580       [["upload"; "test-command"; "/test-command"];
1581        ["chmod"; "0o755"; "/test-command"];
1582        ["command_lines"; "/test-command 9"]], ["";""]);
1583     InitBasicFS, Always, TestOutputList (
1584       [["upload"; "test-command"; "/test-command"];
1585        ["chmod"; "0o755"; "/test-command"];
1586        ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1587     InitBasicFS, Always, TestOutputList (
1588       [["upload"; "test-command"; "/test-command"];
1589        ["chmod"; "0o755"; "/test-command"];
1590        ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1591    "run a command, returning lines",
1592    "\
1593 This is the same as C<guestfs_command>, but splits the
1594 result into a list of lines.
1595
1596 See also: C<guestfs_sh_lines>");
1597
1598   ("stat", (RStruct ("statbuf", "stat"), [String "path"]), 52, [],
1599    [InitSquashFS, Always, TestOutputStruct (
1600       [["stat"; "/empty"]], [CompareWithInt ("size", 0)])],
1601    "get file information",
1602    "\
1603 Returns file information for the given C<path>.
1604
1605 This is the same as the C<stat(2)> system call.");
1606
1607   ("lstat", (RStruct ("statbuf", "stat"), [String "path"]), 53, [],
1608    [InitSquashFS, Always, TestOutputStruct (
1609       [["lstat"; "/empty"]], [CompareWithInt ("size", 0)])],
1610    "get file information for a symbolic link",
1611    "\
1612 Returns file information for the given C<path>.
1613
1614 This is the same as C<guestfs_stat> except that if C<path>
1615 is a symbolic link, then the link is stat-ed, not the file it
1616 refers to.
1617
1618 This is the same as the C<lstat(2)> system call.");
1619
1620   ("statvfs", (RStruct ("statbuf", "statvfs"), [String "path"]), 54, [],
1621    [InitSquashFS, Always, TestOutputStruct (
1622       [["statvfs"; "/"]], [CompareWithInt ("namemax", 256);
1623                            CompareWithInt ("bsize", 131072)])],
1624    "get file system statistics",
1625    "\
1626 Returns file system statistics for any mounted file system.
1627 C<path> should be a file or directory in the mounted file system
1628 (typically it is the mount point itself, but it doesn't need to be).
1629
1630 This is the same as the C<statvfs(2)> system call.");
1631
1632   ("tune2fs_l", (RHashtable "superblock", [String "device"]), 55, [],
1633    [], (* XXX test *)
1634    "get ext2/ext3/ext4 superblock details",
1635    "\
1636 This returns the contents of the ext2, ext3 or ext4 filesystem
1637 superblock on C<device>.
1638
1639 It is the same as running C<tune2fs -l device>.  See L<tune2fs(8)>
1640 manpage for more details.  The list of fields returned isn't
1641 clearly defined, and depends on both the version of C<tune2fs>
1642 that libguestfs was built against, and the filesystem itself.");
1643
1644   ("blockdev_setro", (RErr, [String "device"]), 56, [],
1645    [InitEmpty, Always, TestOutputTrue (
1646       [["blockdev_setro"; "/dev/sda"];
1647        ["blockdev_getro"; "/dev/sda"]])],
1648    "set block device to read-only",
1649    "\
1650 Sets the block device named C<device> to read-only.
1651
1652 This uses the L<blockdev(8)> command.");
1653
1654   ("blockdev_setrw", (RErr, [String "device"]), 57, [],
1655    [InitEmpty, Always, TestOutputFalse (
1656       [["blockdev_setrw"; "/dev/sda"];
1657        ["blockdev_getro"; "/dev/sda"]])],
1658    "set block device to read-write",
1659    "\
1660 Sets the block device named C<device> to read-write.
1661
1662 This uses the L<blockdev(8)> command.");
1663
1664   ("blockdev_getro", (RBool "ro", [String "device"]), 58, [],
1665    [InitEmpty, Always, TestOutputTrue (
1666       [["blockdev_setro"; "/dev/sda"];
1667        ["blockdev_getro"; "/dev/sda"]])],
1668    "is block device set to read-only",
1669    "\
1670 Returns a boolean indicating if the block device is read-only
1671 (true if read-only, false if not).
1672
1673 This uses the L<blockdev(8)> command.");
1674
1675   ("blockdev_getss", (RInt "sectorsize", [String "device"]), 59, [],
1676    [InitEmpty, Always, TestOutputInt (
1677       [["blockdev_getss"; "/dev/sda"]], 512)],
1678    "get sectorsize of block device",
1679    "\
1680 This returns the size of sectors on a block device.
1681 Usually 512, but can be larger for modern devices.
1682
1683 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1684 for that).
1685
1686 This uses the L<blockdev(8)> command.");
1687
1688   ("blockdev_getbsz", (RInt "blocksize", [String "device"]), 60, [],
1689    [InitEmpty, Always, TestOutputInt (
1690       [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1691    "get blocksize of block device",
1692    "\
1693 This returns the block size of a device.
1694
1695 (Note this is different from both I<size in blocks> and
1696 I<filesystem block size>).
1697
1698 This uses the L<blockdev(8)> command.");
1699
1700   ("blockdev_setbsz", (RErr, [String "device"; Int "blocksize"]), 61, [],
1701    [], (* XXX test *)
1702    "set blocksize of block device",
1703    "\
1704 This sets the block size of a device.
1705
1706 (Note this is different from both I<size in blocks> and
1707 I<filesystem block size>).
1708
1709 This uses the L<blockdev(8)> command.");
1710
1711   ("blockdev_getsz", (RInt64 "sizeinsectors", [String "device"]), 62, [],
1712    [InitEmpty, Always, TestOutputInt (
1713       [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1714    "get total size of device in 512-byte sectors",
1715    "\
1716 This returns the size of the device in units of 512-byte sectors
1717 (even if the sectorsize isn't 512 bytes ... weird).
1718
1719 See also C<guestfs_blockdev_getss> for the real sector size of
1720 the device, and C<guestfs_blockdev_getsize64> for the more
1721 useful I<size in bytes>.
1722
1723 This uses the L<blockdev(8)> command.");
1724
1725   ("blockdev_getsize64", (RInt64 "sizeinbytes", [String "device"]), 63, [],
1726    [InitEmpty, Always, TestOutputInt (
1727       [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1728    "get total size of device in bytes",
1729    "\
1730 This returns the size of the device in bytes.
1731
1732 See also C<guestfs_blockdev_getsz>.
1733
1734 This uses the L<blockdev(8)> command.");
1735
1736   ("blockdev_flushbufs", (RErr, [String "device"]), 64, [],
1737    [InitEmpty, Always, TestRun
1738       [["blockdev_flushbufs"; "/dev/sda"]]],
1739    "flush device buffers",
1740    "\
1741 This tells the kernel to flush internal buffers associated
1742 with C<device>.
1743
1744 This uses the L<blockdev(8)> command.");
1745
1746   ("blockdev_rereadpt", (RErr, [String "device"]), 65, [],
1747    [InitEmpty, Always, TestRun
1748       [["blockdev_rereadpt"; "/dev/sda"]]],
1749    "reread partition table",
1750    "\
1751 Reread the partition table on C<device>.
1752
1753 This uses the L<blockdev(8)> command.");
1754
1755   ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
1756    [InitBasicFS, Always, TestOutput (
1757       (* Pick a file from cwd which isn't likely to change. *)
1758       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1759        ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1760    "upload a file from the local machine",
1761    "\
1762 Upload local file C<filename> to C<remotefilename> on the
1763 filesystem.
1764
1765 C<filename> can also be a named pipe.
1766
1767 See also C<guestfs_download>.");
1768
1769   ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
1770    [InitBasicFS, Always, TestOutput (
1771       (* Pick a file from cwd which isn't likely to change. *)
1772       [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1773        ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1774        ["upload"; "testdownload.tmp"; "/upload"];
1775        ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
1776    "download a file to the local machine",
1777    "\
1778 Download file C<remotefilename> and save it as C<filename>
1779 on the local machine.
1780
1781 C<filename> can also be a named pipe.
1782
1783 See also C<guestfs_upload>, C<guestfs_cat>.");
1784
1785   ("checksum", (RString "checksum", [String "csumtype"; String "path"]), 68, [],
1786    [InitSquashFS, Always, TestOutput (
1787       [["checksum"; "crc"; "/known-3"]], "2891671662");
1788     InitSquashFS, Always, TestLastFail (
1789       [["checksum"; "crc"; "/notexists"]]);
1790     InitSquashFS, Always, TestOutput (
1791       [["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c");
1792     InitSquashFS, Always, TestOutput (
1793       [["checksum"; "sha1"; "/known-3"]], "b7ebccc3ee418311091c3eda0a45b83c0a770f15");
1794     InitSquashFS, Always, TestOutput (
1795       [["checksum"; "sha224"; "/known-3"]], "d2cd1774b28f3659c14116be0a6dc2bb5c4b350ce9cd5defac707741");
1796     InitSquashFS, Always, TestOutput (
1797       [["checksum"; "sha256"; "/known-3"]], "75bb71b90cd20cb13f86d2bea8dad63ac7194e7517c3b52b8d06ff52d3487d30");
1798     InitSquashFS, Always, TestOutput (
1799       [["checksum"; "sha384"; "/known-3"]], "5fa7883430f357b5d7b7271d3a1d2872b51d73cba72731de6863d3dea55f30646af2799bef44d5ea776a5ec7941ac640");
1800     InitSquashFS, Always, TestOutput (
1801       [["checksum"; "sha512"; "/known-3"]], "2794062c328c6b216dca90443b7f7134c5f40e56bd0ed7853123275a09982a6f992e6ca682f9d2fba34a4c5e870d8fe077694ff831e3032a004ee077e00603f6")],
1802    "compute MD5, SHAx or CRC checksum of file",
1803    "\
1804 This call computes the MD5, SHAx or CRC checksum of the
1805 file named C<path>.
1806
1807 The type of checksum to compute is given by the C<csumtype>
1808 parameter which must have one of the following values:
1809
1810 =over 4
1811
1812 =item C<crc>
1813
1814 Compute the cyclic redundancy check (CRC) specified by POSIX
1815 for the C<cksum> command.
1816
1817 =item C<md5>
1818
1819 Compute the MD5 hash (using the C<md5sum> program).
1820
1821 =item C<sha1>
1822
1823 Compute the SHA1 hash (using the C<sha1sum> program).
1824
1825 =item C<sha224>
1826
1827 Compute the SHA224 hash (using the C<sha224sum> program).
1828
1829 =item C<sha256>
1830
1831 Compute the SHA256 hash (using the C<sha256sum> program).
1832
1833 =item C<sha384>
1834
1835 Compute the SHA384 hash (using the C<sha384sum> program).
1836
1837 =item C<sha512>
1838
1839 Compute the SHA512 hash (using the C<sha512sum> program).
1840
1841 =back
1842
1843 The checksum is returned as a printable string.");
1844
1845   ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1846    [InitBasicFS, Always, TestOutput (
1847       [["tar_in"; "../images/helloworld.tar"; "/"];
1848        ["cat"; "/hello"]], "hello\n")],
1849    "unpack tarfile to directory",
1850    "\
1851 This command uploads and unpacks local file C<tarfile> (an
1852 I<uncompressed> tar file) into C<directory>.
1853
1854 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1855
1856   ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1857    [],
1858    "pack directory into tarfile",
1859    "\
1860 This command packs the contents of C<directory> and downloads
1861 it to local file C<tarfile>.
1862
1863 To download a compressed tarball, use C<guestfs_tgz_out>.");
1864
1865   ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1866    [InitBasicFS, Always, TestOutput (
1867       [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
1868        ["cat"; "/hello"]], "hello\n")],
1869    "unpack compressed tarball to directory",
1870    "\
1871 This command uploads and unpacks local file C<tarball> (a
1872 I<gzip compressed> tar file) into C<directory>.
1873
1874 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1875
1876   ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
1877    [],
1878    "pack directory into compressed tarball",
1879    "\
1880 This command packs the contents of C<directory> and downloads
1881 it to local file C<tarball>.
1882
1883 To download an uncompressed tarball, use C<guestfs_tar_out>.");
1884
1885   ("mount_ro", (RErr, [String "device"; String "mountpoint"]), 73, [],
1886    [InitBasicFS, Always, TestLastFail (
1887       [["umount"; "/"];
1888        ["mount_ro"; "/dev/sda1"; "/"];
1889        ["touch"; "/new"]]);
1890     InitBasicFS, Always, TestOutput (
1891       [["write_file"; "/new"; "data"; "0"];
1892        ["umount"; "/"];
1893        ["mount_ro"; "/dev/sda1"; "/"];
1894        ["cat"; "/new"]], "data")],
1895    "mount a guest disk, read-only",
1896    "\
1897 This is the same as the C<guestfs_mount> command, but it
1898 mounts the filesystem with the read-only (I<-o ro>) flag.");
1899
1900   ("mount_options", (RErr, [String "options"; String "device"; String "mountpoint"]), 74, [],
1901    [],
1902    "mount a guest disk with mount options",
1903    "\
1904 This is the same as the C<guestfs_mount> command, but it
1905 allows you to set the mount options as for the
1906 L<mount(8)> I<-o> flag.");
1907
1908   ("mount_vfs", (RErr, [String "options"; String "vfstype"; String "device"; String "mountpoint"]), 75, [],
1909    [],
1910    "mount a guest disk with mount options and vfstype",
1911    "\
1912 This is the same as the C<guestfs_mount> command, but it
1913 allows you to set both the mount options and the vfstype
1914 as for the L<mount(8)> I<-o> and I<-t> flags.");
1915
1916   ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
1917    [],
1918    "debugging and internals",
1919    "\
1920 The C<guestfs_debug> command exposes some internals of
1921 C<guestfsd> (the guestfs daemon) that runs inside the
1922 qemu subprocess.
1923
1924 There is no comprehensive help for this command.  You have
1925 to look at the file C<daemon/debug.c> in the libguestfs source
1926 to find out what you can do.");
1927
1928   ("lvremove", (RErr, [String "device"]), 77, [],
1929    [InitEmpty, Always, TestOutputList (
1930       [["sfdiskM"; "/dev/sda"; ","];
1931        ["pvcreate"; "/dev/sda1"];
1932        ["vgcreate"; "VG"; "/dev/sda1"];
1933        ["lvcreate"; "LV1"; "VG"; "50"];
1934        ["lvcreate"; "LV2"; "VG"; "50"];
1935        ["lvremove"; "/dev/VG/LV1"];
1936        ["lvs"]], ["/dev/VG/LV2"]);
1937     InitEmpty, Always, TestOutputList (
1938       [["sfdiskM"; "/dev/sda"; ","];
1939        ["pvcreate"; "/dev/sda1"];
1940        ["vgcreate"; "VG"; "/dev/sda1"];
1941        ["lvcreate"; "LV1"; "VG"; "50"];
1942        ["lvcreate"; "LV2"; "VG"; "50"];
1943        ["lvremove"; "/dev/VG"];
1944        ["lvs"]], []);
1945     InitEmpty, Always, TestOutputList (
1946       [["sfdiskM"; "/dev/sda"; ","];
1947        ["pvcreate"; "/dev/sda1"];
1948        ["vgcreate"; "VG"; "/dev/sda1"];
1949        ["lvcreate"; "LV1"; "VG"; "50"];
1950        ["lvcreate"; "LV2"; "VG"; "50"];
1951        ["lvremove"; "/dev/VG"];
1952        ["vgs"]], ["VG"])],
1953    "remove an LVM logical volume",
1954    "\
1955 Remove an LVM logical volume C<device>, where C<device> is
1956 the path to the LV, such as C</dev/VG/LV>.
1957
1958 You can also remove all LVs in a volume group by specifying
1959 the VG name, C</dev/VG>.");
1960
1961   ("vgremove", (RErr, [String "vgname"]), 78, [],
1962    [InitEmpty, Always, TestOutputList (
1963       [["sfdiskM"; "/dev/sda"; ","];
1964        ["pvcreate"; "/dev/sda1"];
1965        ["vgcreate"; "VG"; "/dev/sda1"];
1966        ["lvcreate"; "LV1"; "VG"; "50"];
1967        ["lvcreate"; "LV2"; "VG"; "50"];
1968        ["vgremove"; "VG"];
1969        ["lvs"]], []);
1970     InitEmpty, Always, TestOutputList (
1971       [["sfdiskM"; "/dev/sda"; ","];
1972        ["pvcreate"; "/dev/sda1"];
1973        ["vgcreate"; "VG"; "/dev/sda1"];
1974        ["lvcreate"; "LV1"; "VG"; "50"];
1975        ["lvcreate"; "LV2"; "VG"; "50"];
1976        ["vgremove"; "VG"];
1977        ["vgs"]], [])],
1978    "remove an LVM volume group",
1979    "\
1980 Remove an LVM volume group C<vgname>, (for example C<VG>).
1981
1982 This also forcibly removes all logical volumes in the volume
1983 group (if any).");
1984
1985   ("pvremove", (RErr, [String "device"]), 79, [],
1986    [InitEmpty, Always, TestOutputListOfDevices (
1987       [["sfdiskM"; "/dev/sda"; ","];
1988        ["pvcreate"; "/dev/sda1"];
1989        ["vgcreate"; "VG"; "/dev/sda1"];
1990        ["lvcreate"; "LV1"; "VG"; "50"];
1991        ["lvcreate"; "LV2"; "VG"; "50"];
1992        ["vgremove"; "VG"];
1993        ["pvremove"; "/dev/sda1"];
1994        ["lvs"]], []);
1995     InitEmpty, Always, TestOutputListOfDevices (
1996       [["sfdiskM"; "/dev/sda"; ","];
1997        ["pvcreate"; "/dev/sda1"];
1998        ["vgcreate"; "VG"; "/dev/sda1"];
1999        ["lvcreate"; "LV1"; "VG"; "50"];
2000        ["lvcreate"; "LV2"; "VG"; "50"];
2001        ["vgremove"; "VG"];
2002        ["pvremove"; "/dev/sda1"];
2003        ["vgs"]], []);
2004     InitEmpty, Always, TestOutputListOfDevices (
2005       [["sfdiskM"; "/dev/sda"; ","];
2006        ["pvcreate"; "/dev/sda1"];
2007        ["vgcreate"; "VG"; "/dev/sda1"];
2008        ["lvcreate"; "LV1"; "VG"; "50"];
2009        ["lvcreate"; "LV2"; "VG"; "50"];
2010        ["vgremove"; "VG"];
2011        ["pvremove"; "/dev/sda1"];
2012        ["pvs"]], [])],
2013    "remove an LVM physical volume",
2014    "\
2015 This wipes a physical volume C<device> so that LVM will no longer
2016 recognise it.
2017
2018 The implementation uses the C<pvremove> command which refuses to
2019 wipe physical volumes that contain any volume groups, so you have
2020 to remove those first.");
2021
2022   ("set_e2label", (RErr, [String "device"; String "label"]), 80, [],
2023    [InitBasicFS, Always, TestOutput (
2024       [["set_e2label"; "/dev/sda1"; "testlabel"];
2025        ["get_e2label"; "/dev/sda1"]], "testlabel")],
2026    "set the ext2/3/4 filesystem label",
2027    "\
2028 This sets the ext2/3/4 filesystem label of the filesystem on
2029 C<device> to C<label>.  Filesystem labels are limited to
2030 16 characters.
2031
2032 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
2033 to return the existing label on a filesystem.");
2034
2035   ("get_e2label", (RString "label", [String "device"]), 81, [],
2036    [],
2037    "get the ext2/3/4 filesystem label",
2038    "\
2039 This returns the ext2/3/4 filesystem label of the filesystem on
2040 C<device>.");
2041
2042   ("set_e2uuid", (RErr, [String "device"; String "uuid"]), 82, [],
2043    [InitBasicFS, Always, TestOutput (
2044       [["set_e2uuid"; "/dev/sda1"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"];
2045        ["get_e2uuid"; "/dev/sda1"]], "a3a61220-882b-4f61-89f4-cf24dcc7297d");
2046     InitBasicFS, Always, TestOutput (
2047       [["set_e2uuid"; "/dev/sda1"; "clear"];
2048        ["get_e2uuid"; "/dev/sda1"]], "");
2049     (* We can't predict what UUIDs will be, so just check the commands run. *)
2050     InitBasicFS, Always, TestRun (
2051       [["set_e2uuid"; "/dev/sda1"; "random"]]);
2052     InitBasicFS, Always, TestRun (
2053       [["set_e2uuid"; "/dev/sda1"; "time"]])],
2054    "set the ext2/3/4 filesystem UUID",
2055    "\
2056 This sets the ext2/3/4 filesystem UUID of the filesystem on
2057 C<device> to C<uuid>.  The format of the UUID and alternatives
2058 such as C<clear>, C<random> and C<time> are described in the
2059 L<tune2fs(8)> manpage.
2060
2061 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
2062 to return the existing UUID of a filesystem.");
2063
2064   ("get_e2uuid", (RString "uuid", [String "device"]), 83, [],
2065    [],
2066    "get the ext2/3/4 filesystem UUID",
2067    "\
2068 This returns the ext2/3/4 filesystem UUID of the filesystem on
2069 C<device>.");
2070
2071   ("fsck", (RInt "status", [String "fstype"; String "device"]), 84, [],
2072    [InitBasicFS, Always, TestOutputInt (
2073       [["umount"; "/dev/sda1"];
2074        ["fsck"; "ext2"; "/dev/sda1"]], 0);
2075     InitBasicFS, Always, TestOutputInt (
2076       [["umount"; "/dev/sda1"];
2077        ["zero"; "/dev/sda1"];
2078        ["fsck"; "ext2"; "/dev/sda1"]], 8)],
2079    "run the filesystem checker",
2080    "\
2081 This runs the filesystem checker (fsck) on C<device> which
2082 should have filesystem type C<fstype>.
2083
2084 The returned integer is the status.  See L<fsck(8)> for the
2085 list of status codes from C<fsck>.
2086
2087 Notes:
2088
2089 =over 4
2090
2091 =item *
2092
2093 Multiple status codes can be summed together.
2094
2095 =item *
2096
2097 A non-zero return code can mean \"success\", for example if
2098 errors have been corrected on the filesystem.
2099
2100 =item *
2101
2102 Checking or repairing NTFS volumes is not supported
2103 (by linux-ntfs).
2104
2105 =back
2106
2107 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2108
2109   ("zero", (RErr, [String "device"]), 85, [],
2110    [InitBasicFS, Always, TestOutput (
2111       [["umount"; "/dev/sda1"];
2112        ["zero"; "/dev/sda1"];
2113        ["file"; "/dev/sda1"]], "data")],
2114    "write zeroes to the device",
2115    "\
2116 This command writes zeroes over the first few blocks of C<device>.
2117
2118 How many blocks are zeroed isn't specified (but it's I<not> enough
2119 to securely wipe the device).  It should be sufficient to remove
2120 any partition tables, filesystem superblocks and so on.
2121
2122 See also: C<guestfs_scrub_device>.");
2123
2124   ("grub_install", (RErr, [String "root"; String "device"]), 86, [],
2125    (* Test disabled because grub-install incompatible with virtio-blk driver.
2126     * See also: https://bugzilla.redhat.com/show_bug.cgi?id=479760
2127     *)
2128    [InitBasicFS, Disabled, TestOutputTrue (
2129       [["grub_install"; "/"; "/dev/sda1"];
2130        ["is_dir"; "/boot"]])],
2131    "install GRUB",
2132    "\
2133 This command installs GRUB (the Grand Unified Bootloader) on
2134 C<device>, with the root directory being C<root>.");
2135
2136   ("cp", (RErr, [String "src"; String "dest"]), 87, [],
2137    [InitBasicFS, Always, TestOutput (
2138       [["write_file"; "/old"; "file content"; "0"];
2139        ["cp"; "/old"; "/new"];
2140        ["cat"; "/new"]], "file content");
2141     InitBasicFS, Always, TestOutputTrue (
2142       [["write_file"; "/old"; "file content"; "0"];
2143        ["cp"; "/old"; "/new"];
2144        ["is_file"; "/old"]]);
2145     InitBasicFS, Always, TestOutput (
2146       [["write_file"; "/old"; "file content"; "0"];
2147        ["mkdir"; "/dir"];
2148        ["cp"; "/old"; "/dir/new"];
2149        ["cat"; "/dir/new"]], "file content")],
2150    "copy a file",
2151    "\
2152 This copies a file from C<src> to C<dest> where C<dest> is
2153 either a destination filename or destination directory.");
2154
2155   ("cp_a", (RErr, [String "src"; String "dest"]), 88, [],
2156    [InitBasicFS, Always, TestOutput (
2157       [["mkdir"; "/olddir"];
2158        ["mkdir"; "/newdir"];
2159        ["write_file"; "/olddir/file"; "file content"; "0"];
2160        ["cp_a"; "/olddir"; "/newdir"];
2161        ["cat"; "/newdir/olddir/file"]], "file content")],
2162    "copy a file or directory recursively",
2163    "\
2164 This copies a file or directory from C<src> to C<dest>
2165 recursively using the C<cp -a> command.");
2166
2167   ("mv", (RErr, [String "src"; String "dest"]), 89, [],
2168    [InitBasicFS, Always, TestOutput (
2169       [["write_file"; "/old"; "file content"; "0"];
2170        ["mv"; "/old"; "/new"];
2171        ["cat"; "/new"]], "file content");
2172     InitBasicFS, Always, TestOutputFalse (
2173       [["write_file"; "/old"; "file content"; "0"];
2174        ["mv"; "/old"; "/new"];
2175        ["is_file"; "/old"]])],
2176    "move a file",
2177    "\
2178 This moves a file from C<src> to C<dest> where C<dest> is
2179 either a destination filename or destination directory.");
2180
2181   ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2182    [InitEmpty, Always, TestRun (
2183       [["drop_caches"; "3"]])],
2184    "drop kernel page cache, dentries and inodes",
2185    "\
2186 This instructs the guest kernel to drop its page cache,
2187 and/or dentries and inode caches.  The parameter C<whattodrop>
2188 tells the kernel what precisely to drop, see
2189 L<http://linux-mm.org/Drop_Caches>
2190
2191 Setting C<whattodrop> to 3 should drop everything.
2192
2193 This automatically calls L<sync(2)> before the operation,
2194 so that the maximum guest memory is freed.");
2195
2196   ("dmesg", (RString "kmsgs", []), 91, [],
2197    [InitEmpty, Always, TestRun (
2198       [["dmesg"]])],
2199    "return kernel messages",
2200    "\
2201 This returns the kernel messages (C<dmesg> output) from
2202 the guest kernel.  This is sometimes useful for extended
2203 debugging of problems.
2204
2205 Another way to get the same information is to enable
2206 verbose messages with C<guestfs_set_verbose> or by setting
2207 the environment variable C<LIBGUESTFS_DEBUG=1> before
2208 running the program.");
2209
2210   ("ping_daemon", (RErr, []), 92, [],
2211    [InitEmpty, Always, TestRun (
2212       [["ping_daemon"]])],
2213    "ping the guest daemon",
2214    "\
2215 This is a test probe into the guestfs daemon running inside
2216 the qemu subprocess.  Calling this function checks that the
2217 daemon responds to the ping message, without affecting the daemon
2218 or attached block device(s) in any other way.");
2219
2220   ("equal", (RBool "equality", [String "file1"; String "file2"]), 93, [],
2221    [InitBasicFS, Always, TestOutputTrue (
2222       [["write_file"; "/file1"; "contents of a file"; "0"];
2223        ["cp"; "/file1"; "/file2"];
2224        ["equal"; "/file1"; "/file2"]]);
2225     InitBasicFS, Always, TestOutputFalse (
2226       [["write_file"; "/file1"; "contents of a file"; "0"];
2227        ["write_file"; "/file2"; "contents of another file"; "0"];
2228        ["equal"; "/file1"; "/file2"]]);
2229     InitBasicFS, Always, TestLastFail (
2230       [["equal"; "/file1"; "/file2"]])],
2231    "test if two files have equal contents",
2232    "\
2233 This compares the two files C<file1> and C<file2> and returns
2234 true if their content is exactly equal, or false otherwise.
2235
2236 The external L<cmp(1)> program is used for the comparison.");
2237
2238   ("strings", (RStringList "stringsout", [String "path"]), 94, [ProtocolLimitWarning],
2239    [InitSquashFS, Always, TestOutputList (
2240       [["strings"; "/known-5"]], ["abcdefghi"; "jklmnopqr"]);
2241     InitSquashFS, Always, TestOutputList (
2242       [["strings"; "/empty"]], [])],
2243    "print the printable strings in a file",
2244    "\
2245 This runs the L<strings(1)> command on a file and returns
2246 the list of printable strings found.");
2247
2248   ("strings_e", (RStringList "stringsout", [String "encoding"; String "path"]), 95, [ProtocolLimitWarning],
2249    [InitSquashFS, Always, TestOutputList (
2250       [["strings_e"; "b"; "/known-5"]], []);
2251     InitBasicFS, Disabled, TestOutputList (
2252       [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2253        ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2254    "print the printable strings in a file",
2255    "\
2256 This is like the C<guestfs_strings> command, but allows you to
2257 specify the encoding.
2258
2259 See the L<strings(1)> manpage for the full list of encodings.
2260
2261 Commonly useful encodings are C<l> (lower case L) which will
2262 show strings inside Windows/x86 files.
2263
2264 The returned strings are transcoded to UTF-8.");
2265
2266   ("hexdump", (RString "dump", [String "path"]), 96, [ProtocolLimitWarning],
2267    [InitSquashFS, Always, TestOutput (
2268       [["hexdump"; "/known-4"]], "00000000  61 62 63 0a 64 65 66 0a  67 68 69                 |abc.def.ghi|\n0000000b\n");
2269     (* Test for RHBZ#501888c2 regression which caused large hexdump
2270      * commands to segfault.
2271      *)
2272     InitSquashFS, Always, TestRun (
2273       [["hexdump"; "/100krandom"]])],
2274    "dump a file in hexadecimal",
2275    "\
2276 This runs C<hexdump -C> on the given C<path>.  The result is
2277 the human-readable, canonical hex dump of the file.");
2278
2279   ("zerofree", (RErr, [String "device"]), 97, [],
2280    [InitNone, Always, TestOutput (
2281       [["sfdiskM"; "/dev/sda"; ","];
2282        ["mkfs"; "ext3"; "/dev/sda1"];
2283        ["mount"; "/dev/sda1"; "/"];
2284        ["write_file"; "/new"; "test file"; "0"];
2285        ["umount"; "/dev/sda1"];
2286        ["zerofree"; "/dev/sda1"];
2287        ["mount"; "/dev/sda1"; "/"];
2288        ["cat"; "/new"]], "test file")],
2289    "zero unused inodes and disk blocks on ext2/3 filesystem",
2290    "\
2291 This runs the I<zerofree> program on C<device>.  This program
2292 claims to zero unused inodes and disk blocks on an ext2/3
2293 filesystem, thus making it possible to compress the filesystem
2294 more effectively.
2295
2296 You should B<not> run this program if the filesystem is
2297 mounted.
2298
2299 It is possible that using this program can damage the filesystem
2300 or data on the filesystem.");
2301
2302   ("pvresize", (RErr, [String "device"]), 98, [],
2303    [],
2304    "resize an LVM physical volume",
2305    "\
2306 This resizes (expands or shrinks) an existing LVM physical
2307 volume to match the new size of the underlying device.");
2308
2309   ("sfdisk_N", (RErr, [String "device"; Int "partnum";
2310                        Int "cyls"; Int "heads"; Int "sectors";
2311                        String "line"]), 99, [DangerWillRobinson],
2312    [],
2313    "modify a single partition on a block device",
2314    "\
2315 This runs L<sfdisk(8)> option to modify just the single
2316 partition C<n> (note: C<n> counts from 1).
2317
2318 For other parameters, see C<guestfs_sfdisk>.  You should usually
2319 pass C<0> for the cyls/heads/sectors parameters.");
2320
2321   ("sfdisk_l", (RString "partitions", [String "device"]), 100, [],
2322    [],
2323    "display the partition table",
2324    "\
2325 This displays the partition table on C<device>, in the
2326 human-readable output of the L<sfdisk(8)> command.  It is
2327 not intended to be parsed.");
2328
2329   ("sfdisk_kernel_geometry", (RString "partitions", [String "device"]), 101, [],
2330    [],
2331    "display the kernel geometry",
2332    "\
2333 This displays the kernel's idea of the geometry of C<device>.
2334
2335 The result is in human-readable format, and not designed to
2336 be parsed.");
2337
2338   ("sfdisk_disk_geometry", (RString "partitions", [String "device"]), 102, [],
2339    [],
2340    "display the disk geometry from the partition table",
2341    "\
2342 This displays the disk geometry of C<device> read from the
2343 partition table.  Especially in the case where the underlying
2344 block device has been resized, this can be different from the
2345 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2346
2347 The result is in human-readable format, and not designed to
2348 be parsed.");
2349
2350   ("vg_activate_all", (RErr, [Bool "activate"]), 103, [],
2351    [],
2352    "activate or deactivate all volume groups",
2353    "\
2354 This command activates or (if C<activate> is false) deactivates
2355 all logical volumes in all volume groups.
2356 If activated, then they are made known to the
2357 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2358 then those devices disappear.
2359
2360 This command is the same as running C<vgchange -a y|n>");
2361
2362   ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [],
2363    [],
2364    "activate or deactivate some volume groups",
2365    "\
2366 This command activates or (if C<activate> is false) deactivates
2367 all logical volumes in the listed volume groups C<volgroups>.
2368 If activated, then they are made known to the
2369 kernel, ie. they appear as C</dev/mapper> devices.  If deactivated,
2370 then those devices disappear.
2371
2372 This command is the same as running C<vgchange -a y|n volgroups...>
2373
2374 Note that if C<volgroups> is an empty list then B<all> volume groups
2375 are activated or deactivated.");
2376
2377   ("lvresize", (RErr, [String "device"; Int "mbytes"]), 105, [],
2378    [InitNone, Always, TestOutput (
2379       [["sfdiskM"; "/dev/sda"; ","];
2380        ["pvcreate"; "/dev/sda1"];
2381        ["vgcreate"; "VG"; "/dev/sda1"];
2382        ["lvcreate"; "LV"; "VG"; "10"];
2383        ["mkfs"; "ext2"; "/dev/VG/LV"];
2384        ["mount"; "/dev/VG/LV"; "/"];
2385        ["write_file"; "/new"; "test content"; "0"];
2386        ["umount"; "/"];
2387        ["lvresize"; "/dev/VG/LV"; "20"];
2388        ["e2fsck_f"; "/dev/VG/LV"];
2389        ["resize2fs"; "/dev/VG/LV"];
2390        ["mount"; "/dev/VG/LV"; "/"];
2391        ["cat"; "/new"]], "test content")],
2392    "resize an LVM logical volume",
2393    "\
2394 This resizes (expands or shrinks) an existing LVM logical
2395 volume to C<mbytes>.  When reducing, data in the reduced part
2396 is lost.");
2397
2398   ("resize2fs", (RErr, [String "device"]), 106, [],
2399    [], (* lvresize tests this *)
2400    "resize an ext2/ext3 filesystem",
2401    "\
2402 This resizes an ext2 or ext3 filesystem to match the size of
2403 the underlying device.
2404
2405 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2406 on the C<device> before calling this command.  For unknown reasons
2407 C<resize2fs> sometimes gives an error about this and sometimes not.
2408 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2409 calling this function.");
2410
2411   ("find", (RStringList "names", [String "directory"]), 107, [],
2412    [InitBasicFS, Always, TestOutputList (
2413       [["find"; "/"]], ["lost+found"]);
2414     InitBasicFS, Always, TestOutputList (
2415       [["touch"; "/a"];
2416        ["mkdir"; "/b"];
2417        ["touch"; "/b/c"];
2418        ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2419     InitBasicFS, Always, TestOutputList (
2420       [["mkdir_p"; "/a/b/c"];
2421        ["touch"; "/a/b/c/d"];
2422        ["find"; "/a/b/"]], ["c"; "c/d"])],
2423    "find all files and directories",
2424    "\
2425 This command lists out all files and directories, recursively,
2426 starting at C<directory>.  It is essentially equivalent to
2427 running the shell command C<find directory -print> but some
2428 post-processing happens on the output, described below.
2429
2430 This returns a list of strings I<without any prefix>.  Thus
2431 if the directory structure was:
2432
2433  /tmp/a
2434  /tmp/b
2435  /tmp/c/d
2436
2437 then the returned list from C<guestfs_find> C</tmp> would be
2438 4 elements:
2439
2440  a
2441  b
2442  c
2443  c/d
2444
2445 If C<directory> is not a directory, then this command returns
2446 an error.
2447
2448 The returned list is sorted.");
2449
2450   ("e2fsck_f", (RErr, [String "device"]), 108, [],
2451    [], (* lvresize tests this *)
2452    "check an ext2/ext3 filesystem",
2453    "\
2454 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2455 filesystem checker on C<device>, noninteractively (C<-p>),
2456 even if the filesystem appears to be clean (C<-f>).
2457
2458 This command is only needed because of C<guestfs_resize2fs>
2459 (q.v.).  Normally you should use C<guestfs_fsck>.");
2460
2461   ("sleep", (RErr, [Int "secs"]), 109, [],
2462    [InitNone, Always, TestRun (
2463       [["sleep"; "1"]])],
2464    "sleep for some seconds",
2465    "\
2466 Sleep for C<secs> seconds.");
2467
2468   ("ntfs_3g_probe", (RInt "status", [Bool "rw"; String "device"]), 110, [],
2469    [InitNone, Always, TestOutputInt (
2470       [["sfdiskM"; "/dev/sda"; ","];
2471        ["mkfs"; "ntfs"; "/dev/sda1"];
2472        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2473     InitNone, Always, TestOutputInt (
2474       [["sfdiskM"; "/dev/sda"; ","];
2475        ["mkfs"; "ext2"; "/dev/sda1"];
2476        ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2477    "probe NTFS volume",
2478    "\
2479 This command runs the L<ntfs-3g.probe(8)> command which probes
2480 an NTFS C<device> for mountability.  (Not all NTFS volumes can
2481 be mounted read-write, and some cannot be mounted at all).
2482
2483 C<rw> is a boolean flag.  Set it to true if you want to test
2484 if the volume can be mounted read-write.  Set it to false if
2485 you want to test if the volume can be mounted read-only.
2486
2487 The return value is an integer which C<0> if the operation
2488 would succeed, or some non-zero value documented in the
2489 L<ntfs-3g.probe(8)> manual page.");
2490
2491   ("sh", (RString "output", [String "command"]), 111, [],
2492    [], (* XXX needs tests *)
2493    "run a command via the shell",
2494    "\
2495 This call runs a command from the guest filesystem via the
2496 guest's C</bin/sh>.
2497
2498 This is like C<guestfs_command>, but passes the command to:
2499
2500  /bin/sh -c \"command\"
2501
2502 Depending on the guest's shell, this usually results in
2503 wildcards being expanded, shell expressions being interpolated
2504 and so on.
2505
2506 All the provisos about C<guestfs_command> apply to this call.");
2507
2508   ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2509    [], (* XXX needs tests *)
2510    "run a command via the shell returning lines",
2511    "\
2512 This is the same as C<guestfs_sh>, but splits the result
2513 into a list of lines.
2514
2515 See also: C<guestfs_command_lines>");
2516
2517   ("glob_expand", (RStringList "paths", [String "pattern"]), 113, [],
2518    [InitBasicFS, Always, TestOutputList (
2519       [["mkdir_p"; "/a/b/c"];
2520        ["touch"; "/a/b/c/d"];
2521        ["touch"; "/a/b/c/e"];
2522        ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2523     InitBasicFS, Always, TestOutputList (
2524       [["mkdir_p"; "/a/b/c"];
2525        ["touch"; "/a/b/c/d"];
2526        ["touch"; "/a/b/c/e"];
2527        ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2528     InitBasicFS, Always, TestOutputList (
2529       [["mkdir_p"; "/a/b/c"];
2530        ["touch"; "/a/b/c/d"];
2531        ["touch"; "/a/b/c/e"];
2532        ["glob_expand"; "/a/*/x/*"]], [])],
2533    "expand a wildcard path",
2534    "\
2535 This command searches for all the pathnames matching
2536 C<pattern> according to the wildcard expansion rules
2537 used by the shell.
2538
2539 If no paths match, then this returns an empty list
2540 (note: not an error).
2541
2542 It is just a wrapper around the C L<glob(3)> function
2543 with flags C<GLOB_MARK|GLOB_BRACE>.
2544 See that manual page for more details.");
2545
2546   ("scrub_device", (RErr, [String "device"]), 114, [DangerWillRobinson],
2547    [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2548       [["scrub_device"; "/dev/sdc"]])],
2549    "scrub (securely wipe) a device",
2550    "\
2551 This command writes patterns over C<device> to make data retrieval
2552 more difficult.
2553
2554 It is an interface to the L<scrub(1)> program.  See that
2555 manual page for more details.");
2556
2557   ("scrub_file", (RErr, [String "file"]), 115, [],
2558    [InitBasicFS, Always, TestRun (
2559       [["write_file"; "/file"; "content"; "0"];
2560        ["scrub_file"; "/file"]])],
2561    "scrub (securely wipe) a file",
2562    "\
2563 This command writes patterns over a file to make data retrieval
2564 more difficult.
2565
2566 The file is I<removed> after scrubbing.
2567
2568 It is an interface to the L<scrub(1)> program.  See that
2569 manual page for more details.");
2570
2571   ("scrub_freespace", (RErr, [String "dir"]), 116, [],
2572    [], (* XXX needs testing *)
2573    "scrub (securely wipe) free space",
2574    "\
2575 This command creates the directory C<dir> and then fills it
2576 with files until the filesystem is full, and scrubs the files
2577 as for C<guestfs_scrub_file>, and deletes them.
2578 The intention is to scrub any free space on the partition
2579 containing C<dir>.
2580
2581 It is an interface to the L<scrub(1)> program.  See that
2582 manual page for more details.");
2583
2584   ("mkdtemp", (RString "dir", [String "template"]), 117, [],
2585    [InitBasicFS, Always, TestRun (
2586       [["mkdir"; "/tmp"];
2587        ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2588    "create a temporary directory",
2589    "\
2590 This command creates a temporary directory.  The
2591 C<template> parameter should be a full pathname for the
2592 temporary directory name with the final six characters being
2593 \"XXXXXX\".
2594
2595 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2596 the second one being suitable for Windows filesystems.
2597
2598 The name of the temporary directory that was created
2599 is returned.
2600
2601 The temporary directory is created with mode 0700
2602 and is owned by root.
2603
2604 The caller is responsible for deleting the temporary
2605 directory and its contents after use.
2606
2607 See also: L<mkdtemp(3)>");
2608
2609   ("wc_l", (RInt "lines", [String "path"]), 118, [],
2610    [InitSquashFS, Always, TestOutputInt (
2611       [["wc_l"; "/10klines"]], 10000)],
2612    "count lines in a file",
2613    "\
2614 This command counts the lines in a file, using the
2615 C<wc -l> external command.");
2616
2617   ("wc_w", (RInt "words", [String "path"]), 119, [],
2618    [InitSquashFS, Always, TestOutputInt (
2619       [["wc_w"; "/10klines"]], 10000)],
2620    "count words in a file",
2621    "\
2622 This command counts the words in a file, using the
2623 C<wc -w> external command.");
2624
2625   ("wc_c", (RInt "chars", [String "path"]), 120, [],
2626    [InitSquashFS, Always, TestOutputInt (
2627       [["wc_c"; "/100kallspaces"]], 102400)],
2628    "count characters in a file",
2629    "\
2630 This command counts the characters in a file, using the
2631 C<wc -c> external command.");
2632
2633   ("head", (RStringList "lines", [String "path"]), 121, [ProtocolLimitWarning],
2634    [InitSquashFS, Always, TestOutputList (
2635       [["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2636    "return first 10 lines of a file",
2637    "\
2638 This command returns up to the first 10 lines of a file as
2639 a list of strings.");
2640
2641   ("head_n", (RStringList "lines", [Int "nrlines"; String "path"]), 122, [ProtocolLimitWarning],
2642    [InitSquashFS, Always, TestOutputList (
2643       [["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2644     InitSquashFS, Always, TestOutputList (
2645       [["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2646     InitSquashFS, Always, TestOutputList (
2647       [["head_n"; "0"; "/10klines"]], [])],
2648    "return first N lines of a file",
2649    "\
2650 If the parameter C<nrlines> is a positive number, this returns the first
2651 C<nrlines> lines of the file C<path>.
2652
2653 If the parameter C<nrlines> is a negative number, this returns lines
2654 from the file C<path>, excluding the last C<nrlines> lines.
2655
2656 If the parameter C<nrlines> is zero, this returns an empty list.");
2657
2658   ("tail", (RStringList "lines", [String "path"]), 123, [ProtocolLimitWarning],
2659    [InitSquashFS, Always, TestOutputList (
2660       [["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2661    "return last 10 lines of a file",
2662    "\
2663 This command returns up to the last 10 lines of a file as
2664 a list of strings.");
2665
2666   ("tail_n", (RStringList "lines", [Int "nrlines"; String "path"]), 124, [ProtocolLimitWarning],
2667    [InitSquashFS, Always, TestOutputList (
2668       [["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2669     InitSquashFS, Always, TestOutputList (
2670       [["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2671     InitSquashFS, Always, TestOutputList (
2672       [["tail_n"; "0"; "/10klines"]], [])],
2673    "return last N lines of a file",
2674    "\
2675 If the parameter C<nrlines> is a positive number, this returns the last
2676 C<nrlines> lines of the file C<path>.
2677
2678 If the parameter C<nrlines> is a negative number, this returns lines
2679 from the file C<path>, starting with the C<-nrlines>th line.
2680
2681 If the parameter C<nrlines> is zero, this returns an empty list.");
2682
2683   ("df", (RString "output", []), 125, [],
2684    [], (* XXX Tricky to test because it depends on the exact format
2685         * of the 'df' command and other imponderables.
2686         *)
2687    "report file system disk space usage",
2688    "\
2689 This command runs the C<df> command to report disk space used.
2690
2691 This command is mostly useful for interactive sessions.  It
2692 is I<not> intended that you try to parse the output string.
2693 Use C<statvfs> from programs.");
2694
2695   ("df_h", (RString "output", []), 126, [],
2696    [], (* XXX Tricky to test because it depends on the exact format
2697         * of the 'df' command and other imponderables.
2698         *)
2699    "report file system disk space usage (human readable)",
2700    "\
2701 This command runs the C<df -h> command to report disk space used
2702 in human-readable format.
2703
2704 This command is mostly useful for interactive sessions.  It
2705 is I<not> intended that you try to parse the output string.
2706 Use C<statvfs> from programs.");
2707
2708   ("du", (RInt64 "sizekb", [String "path"]), 127, [],
2709    [InitSquashFS, Always, TestOutputInt (
2710       [["du"; "/directory"]], 0 (* squashfs doesn't have blocks *))],
2711    "estimate file space usage",
2712    "\
2713 This command runs the C<du -s> command to estimate file space
2714 usage for C<path>.
2715
2716 C<path> can be a file or a directory.  If C<path> is a directory
2717 then the estimate includes the contents of the directory and all
2718 subdirectories (recursively).
2719
2720 The result is the estimated size in I<kilobytes>
2721 (ie. units of 1024 bytes).");
2722
2723   ("initrd_list", (RStringList "filenames", [String "path"]), 128, [],
2724    [InitSquashFS, Always, TestOutputList (
2725       [["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3";"known-4"; "known-5"])],
2726    "list files in an initrd",
2727    "\
2728 This command lists out files contained in an initrd.
2729
2730 The files are listed without any initial C</> character.  The
2731 files are listed in the order they appear (not necessarily
2732 alphabetical).  Directory names are listed as separate items.
2733
2734 Old Linux kernels (2.4 and earlier) used a compressed ext2
2735 filesystem as initrd.  We I<only> support the newer initramfs
2736 format (compressed cpio files).");
2737
2738   ("mount_loop", (RErr, [String "file"; String "mountpoint"]), 129, [],
2739    [],
2740    "mount a file using the loop device",
2741    "\
2742 This command lets you mount C<file> (a filesystem image
2743 in a file) on a mount point.  It is entirely equivalent to
2744 the command C<mount -o loop file mountpoint>.");
2745
2746   ("mkswap", (RErr, [String "device"]), 130, [],
2747    [InitEmpty, Always, TestRun (
2748       [["sfdiskM"; "/dev/sda"; ","];
2749        ["mkswap"; "/dev/sda1"]])],
2750    "create a swap partition",
2751    "\
2752 Create a swap partition on C<device>.");
2753
2754   ("mkswap_L", (RErr, [String "label"; String "device"]), 131, [],
2755    [InitEmpty, Always, TestRun (
2756       [["sfdiskM"; "/dev/sda"; ","];
2757        ["mkswap_L"; "hello"; "/dev/sda1"]])],
2758    "create a swap partition with a label",
2759    "\
2760 Create a swap partition on C<device> with label C<label>.");
2761
2762   ("mkswap_U", (RErr, [String "uuid"; String "device"]), 132, [],
2763    [InitEmpty, Always, TestRun (
2764       [["sfdiskM"; "/dev/sda"; ","];
2765        ["mkswap_U"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"; "/dev/sda1"]])],
2766    "create a swap partition with an explicit UUID",
2767    "\
2768 Create a swap partition on C<device> with UUID C<uuid>.");
2769
2770   ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 133, [],
2771    [InitBasicFS, Always, TestOutputStruct (
2772       [["mknod"; "0o10777"; "0"; "0"; "/node"];
2773        (* NB: default umask 022 means 0777 -> 0755 in these tests *)
2774        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
2775     InitBasicFS, Always, TestOutputStruct (
2776       [["mknod"; "0o60777"; "66"; "99"; "/node"];
2777        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2778    "make block, character or FIFO devices",
2779    "\
2780 This call creates block or character special devices, or
2781 named pipes (FIFOs).
2782
2783 The C<mode> parameter should be the mode, using the standard
2784 constants.  C<devmajor> and C<devminor> are the
2785 device major and minor numbers, only used when creating block
2786 and character special devices.");
2787
2788   ("mkfifo", (RErr, [Int "mode"; String "path"]), 134, [],
2789    [InitBasicFS, Always, TestOutputStruct (
2790       [["mkfifo"; "0o777"; "/node"];
2791        ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
2792    "make FIFO (named pipe)",
2793    "\
2794 This call creates a FIFO (named pipe) called C<path> with
2795 mode C<mode>.  It is just a convenient wrapper around
2796 C<guestfs_mknod>.");
2797
2798   ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 135, [],
2799    [InitBasicFS, Always, TestOutputStruct (
2800       [["mknod_b"; "0o777"; "99"; "66"; "/node"];
2801        ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2802    "make block device node",
2803    "\
2804 This call creates a block device node called C<path> with
2805 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2806 It is just a convenient wrapper around C<guestfs_mknod>.");
2807
2808   ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; String "path"]), 136, [],
2809    [InitBasicFS, Always, TestOutputStruct (
2810       [["mknod_c"; "0o777"; "99"; "66"; "/node"];
2811        ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
2812    "make char device node",
2813    "\
2814 This call creates a char device node called C<path> with
2815 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2816 It is just a convenient wrapper around C<guestfs_mknod>.");
2817
2818   ("umask", (RInt "oldmask", [Int "mask"]), 137, [],
2819    [], (* XXX umask is one of those stateful things that we should
2820         * reset between each test.
2821         *)
2822    "set file mode creation mask (umask)",
2823    "\
2824 This function sets the mask used for creating new files and
2825 device nodes to C<mask & 0777>.
2826
2827 Typical umask values would be C<022> which creates new files
2828 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
2829 C<002> which creates new files with permissions like
2830 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
2831
2832 The default umask is C<022>.  This is important because it
2833 means that directories and device nodes will be created with
2834 C<0644> or C<0755> mode even if you specify C<0777>.
2835
2836 See also L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
2837
2838 This call returns the previous umask.");
2839
2840   ("readdir", (RStructList ("entries", "dirent"), [String "dir"]), 138, [],
2841    [],
2842    "read directories entries",
2843    "\
2844 This returns the list of directory entries in directory C<dir>.
2845
2846 All entries in the directory are returned, including C<.> and
2847 C<..>.  The entries are I<not> sorted, but returned in the same
2848 order as the underlying filesystem.
2849
2850 Also this call returns basic file type information about each
2851 file.  The C<ftyp> field will contain one of the following characters:
2852
2853 =over 4
2854
2855 =item 'b'
2856
2857 Block special
2858
2859 =item 'c'
2860
2861 Char special
2862
2863 =item 'd'
2864
2865 Directory
2866
2867 =item 'f'
2868
2869 FIFO (named pipe)
2870
2871 =item 'l'
2872
2873 Symbolic link
2874
2875 =item 'r'
2876
2877 Regular file
2878
2879 =item 's'
2880
2881 Socket
2882
2883 =item 'u'
2884
2885 Unknown file type
2886
2887 =item '?'
2888
2889 The L<readdir(3)> returned a C<d_type> field with an
2890 unexpected value
2891
2892 =back
2893
2894 This function is primarily intended for use by programs.  To
2895 get a simple list of names, use C<guestfs_ls>.  To get a printable
2896 directory for human consumption, use C<guestfs_ll>.");
2897
2898   ("sfdiskM", (RErr, [String "device"; StringList "lines"]), 139, [DangerWillRobinson],
2899    [],
2900    "create partitions on a block device",
2901    "\
2902 This is a simplified interface to the C<guestfs_sfdisk>
2903 command, where partition sizes are specified in megabytes
2904 only (rounded to the nearest cylinder) and you don't need
2905 to specify the cyls, heads and sectors parameters which
2906 were rarely if ever used anyway.
2907
2908 See also C<guestfs_sfdisk> and the L<sfdisk(8)> manpage.");
2909
2910   ("zfile", (RString "description", [String "method"; String "path"]), 140, [DeprecatedBy "file"],
2911    [],
2912    "determine file type inside a compressed file",
2913    "\
2914 This command runs C<file> after first decompressing C<path>
2915 using C<method>.
2916
2917 C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
2918
2919 Since 1.0.63, use C<guestfs_file> instead which can now
2920 process compressed files.");
2921
2922   ("getxattrs", (RStructList ("xattrs", "xattr"), [String "path"]), 141, [],
2923    [],
2924    "list extended attributes of a file or directory",
2925    "\
2926 This call lists the extended attributes of the file or directory
2927 C<path>.
2928
2929 At the system call level, this is a combination of the
2930 L<listxattr(2)> and L<getxattr(2)> calls.
2931
2932 See also: C<guestfs_lgetxattrs>, L<attr(5)>.");
2933
2934   ("lgetxattrs", (RStructList ("xattrs", "xattr"), [String "path"]), 142, [],
2935    [],
2936    "list extended attributes of a file or directory",
2937    "\
2938 This is the same as C<guestfs_getxattrs>, but if C<path>
2939 is a symbolic link, then it returns the extended attributes
2940 of the link itself.");
2941
2942   ("setxattr", (RErr, [String "xattr";
2943                        String "val"; Int "vallen"; (* will be BufferIn *)
2944                        String "path"]), 143, [],
2945    [],
2946    "set extended attribute of a file or directory",
2947    "\
2948 This call sets the extended attribute named C<xattr>
2949 of the file C<path> to the value C<val> (of length C<vallen>).
2950 The value is arbitrary 8 bit data.
2951
2952 See also: C<guestfs_lsetxattr>, L<attr(5)>.");
2953
2954   ("lsetxattr", (RErr, [String "xattr";
2955                         String "val"; Int "vallen"; (* will be BufferIn *)
2956                         String "path"]), 144, [],
2957    [],
2958    "set extended attribute of a file or directory",
2959    "\
2960 This is the same as C<guestfs_setxattr>, but if C<path>
2961 is a symbolic link, then it sets an extended attribute
2962 of the link itself.");
2963
2964   ("removexattr", (RErr, [String "xattr"; String "path"]), 145, [],
2965    [],
2966    "remove extended attribute of a file or directory",
2967    "\
2968 This call removes the extended attribute named C<xattr>
2969 of the file C<path>.
2970
2971 See also: C<guestfs_lremovexattr>, L<attr(5)>.");
2972
2973   ("lremovexattr", (RErr, [String "xattr"; String "path"]), 146, [],
2974    [],
2975    "remove extended attribute of a file or directory",
2976    "\
2977 This is the same as C<guestfs_removexattr>, but if C<path>
2978 is a symbolic link, then it removes an extended attribute
2979 of the link itself.");
2980
2981   ("mountpoints", (RHashtable "mps", []), 147, [],
2982    [],
2983    "show mountpoints",
2984    "\
2985 This call is similar to C<guestfs_mounts>.  That call returns
2986 a list of devices.  This one returns a hash table (map) of
2987 device name to directory where the device is mounted.");
2988
2989   ("mkmountpoint", (RErr, [String "path"]), 148, [],
2990    [],
2991    "create a mountpoint",
2992    "\
2993 C<guestfs_mkmountpoint> and C<guestfs_rmmountpoint> are
2994 specialized calls that can be used to create extra mountpoints
2995 before mounting the first filesystem.
2996
2997 These calls are I<only> necessary in some very limited circumstances,
2998 mainly the case where you want to mount a mix of unrelated and/or
2999 read-only filesystems together.
3000
3001 For example, live CDs often contain a \"Russian doll\" nest of
3002 filesystems, an ISO outer layer, with a squashfs image inside, with
3003 an ext2/3 image inside that.  You can unpack this as follows
3004 in guestfish:
3005
3006  add-ro Fedora-11-i686-Live.iso
3007  run
3008  mkmountpoint /cd
3009  mkmountpoint /squash
3010  mkmountpoint /ext3
3011  mount /dev/sda /cd
3012  mount-loop /cd/LiveOS/squashfs.img /squash
3013  mount-loop /squash/LiveOS/ext3fs.img /ext3
3014
3015 The inner filesystem is now unpacked under the /ext3 mountpoint.");
3016
3017   ("rmmountpoint", (RErr, [String "path"]), 149, [],
3018    [],
3019    "remove a mountpoint",
3020    "\
3021 This calls removes a mountpoint that was previously created
3022 with C<guestfs_mkmountpoint>.  See C<guestfs_mkmountpoint>
3023 for full details.");
3024
3025   ("read_file", (RBufferOut "content", [String "path"]), 150, [ProtocolLimitWarning],
3026    [InitSquashFS, Always, TestOutputBuffer (
3027       [["read_file"; "/known-4"]], "abc\ndef\nghi")],
3028    "read a file",
3029    "\
3030 This calls returns the contents of the file C<path> as a
3031 buffer.
3032
3033 Unlike C<guestfs_cat>, this function can correctly
3034 handle files that contain embedded ASCII NUL characters.
3035 However unlike C<guestfs_download>, this function is limited
3036 in the total size of file that can be handled.");
3037
3038   ("grep", (RStringList "lines", [String "regex"; String "path"]), 151, [ProtocolLimitWarning],
3039    [InitSquashFS, Always, TestOutputList (
3040       [["grep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"]);
3041     InitSquashFS, Always, TestOutputList (
3042       [["grep"; "nomatch"; "/test-grep.txt"]], [])],
3043    "return lines matching a pattern",
3044    "\
3045 This calls the external C<grep> program and returns the
3046 matching lines.");
3047
3048   ("egrep", (RStringList "lines", [String "regex"; String "path"]), 152, [ProtocolLimitWarning],
3049    [InitSquashFS, Always, TestOutputList (
3050       [["egrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3051    "return lines matching a pattern",
3052    "\
3053 This calls the external C<egrep> program and returns the
3054 matching lines.");
3055
3056   ("fgrep", (RStringList "lines", [String "pattern"; String "path"]), 153, [ProtocolLimitWarning],
3057    [InitSquashFS, Always, TestOutputList (
3058       [["fgrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3059    "return lines matching a pattern",
3060    "\
3061 This calls the external C<fgrep> program and returns the
3062 matching lines.");
3063
3064   ("grepi", (RStringList "lines", [String "regex"; String "path"]), 154, [ProtocolLimitWarning],
3065    [InitSquashFS, Always, TestOutputList (
3066       [["grepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3067    "return lines matching a pattern",
3068    "\
3069 This calls the external C<grep -i> program and returns the
3070 matching lines.");
3071
3072   ("egrepi", (RStringList "lines", [String "regex"; String "path"]), 155, [ProtocolLimitWarning],
3073    [InitSquashFS, Always, TestOutputList (
3074       [["egrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3075    "return lines matching a pattern",
3076    "\
3077 This calls the external C<egrep -i> program and returns the
3078 matching lines.");
3079
3080   ("fgrepi", (RStringList "lines", [String "pattern"; String "path"]), 156, [ProtocolLimitWarning],
3081    [InitSquashFS, Always, TestOutputList (
3082       [["fgrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3083    "return lines matching a pattern",
3084    "\
3085 This calls the external C<fgrep -i> program and returns the
3086 matching lines.");
3087
3088   ("zgrep", (RStringList "lines", [String "regex"; String "path"]), 157, [ProtocolLimitWarning],
3089    [InitSquashFS, Always, TestOutputList (
3090       [["zgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3091    "return lines matching a pattern",
3092    "\
3093 This calls the external C<zgrep> program and returns the
3094 matching lines.");
3095
3096   ("zegrep", (RStringList "lines", [String "regex"; String "path"]), 158, [ProtocolLimitWarning],
3097    [InitSquashFS, Always, TestOutputList (
3098       [["zegrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3099    "return lines matching a pattern",
3100    "\
3101 This calls the external C<zegrep> program and returns the
3102 matching lines.");
3103
3104   ("zfgrep", (RStringList "lines", [String "pattern"; String "path"]), 159, [ProtocolLimitWarning],
3105    [InitSquashFS, Always, TestOutputList (
3106       [["zfgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3107    "return lines matching a pattern",
3108    "\
3109 This calls the external C<zfgrep> program and returns the
3110 matching lines.");
3111
3112   ("zgrepi", (RStringList "lines", [String "regex"; String "path"]), 160, [ProtocolLimitWarning],
3113    [InitSquashFS, Always, TestOutputList (
3114       [["zgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3115    "return lines matching a pattern",
3116    "\
3117 This calls the external C<zgrep -i> program and returns the
3118 matching lines.");
3119
3120   ("zegrepi", (RStringList "lines", [String "regex"; String "path"]), 161, [ProtocolLimitWarning],
3121    [InitSquashFS, Always, TestOutputList (
3122       [["zegrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3123    "return lines matching a pattern",
3124    "\
3125 This calls the external C<zegrep -i> program and returns the
3126 matching lines.");
3127
3128   ("zfgrepi", (RStringList "lines", [String "pattern"; String "path"]), 162, [ProtocolLimitWarning],
3129    [InitSquashFS, Always, TestOutputList (
3130       [["zfgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3131    "return lines matching a pattern",
3132    "\
3133 This calls the external C<zfgrep -i> program and returns the
3134 matching lines.");
3135
3136   ("realpath", (RString "rpath", [String "path"]), 163, [],
3137    [InitSquashFS, Always, TestOutput (
3138       [["realpath"; "/../directory"]], "/directory")],
3139    "canonicalized absolute pathname",
3140    "\
3141 Return the canonicalized absolute pathname of C<path>.  The
3142 returned path has no C<.>, C<..> or symbolic link path elements.");
3143
3144   ("ln", (RErr, [String "target"; String "linkname"]), 164, [],
3145    [InitBasicFS, Always, TestOutputStruct (
3146       [["touch"; "/a"];
3147        ["ln"; "/a"; "/b"];
3148        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3149    "create a hard link",
3150    "\
3151 This command creates a hard link using the C<ln> command.");
3152
3153   ("ln_f", (RErr, [String "target"; String "linkname"]), 165, [],
3154    [InitBasicFS, Always, TestOutputStruct (
3155       [["touch"; "/a"];
3156        ["touch"; "/b"];
3157        ["ln_f"; "/a"; "/b"];
3158        ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3159    "create a hard link",
3160    "\
3161 This command creates a hard link using the C<ln -f> command.
3162 The C<-f> option removes the link (C<linkname>) if it exists already.");
3163
3164   ("ln_s", (RErr, [String "target"; String "linkname"]), 166, [],
3165    [InitBasicFS, Always, TestOutputStruct (
3166       [["touch"; "/a"];
3167        ["ln_s"; "a"; "/b"];
3168        ["lstat"; "/b"]], [CompareWithInt ("mode", 0o120777)])],
3169    "create a symbolic link",
3170    "\
3171 This command creates a symbolic link using the C<ln -s> command.");
3172
3173   ("ln_sf", (RErr, [String "target"; String "linkname"]), 167, [],
3174    [InitBasicFS, Always, TestOutput (
3175       [["mkdir_p"; "/a/b"];
3176        ["touch"; "/a/b/c"];
3177        ["ln_sf"; "../d"; "/a/b/c"];
3178        ["readlink"; "/a/b/c"]], "../d")],
3179    "create a symbolic link",
3180    "\
3181 This command creates a symbolic link using the C<ln -sf> command,
3182 The C<-f> option removes the link (C<linkname>) if it exists already.");
3183
3184   ("readlink", (RString "link", [String "path"]), 168, [],
3185    [] (* XXX tested above *),
3186    "read the target of a symbolic link",
3187    "\
3188 This command reads the target of a symbolic link.");
3189
3190   ("fallocate", (RErr, [String "path"; Int "len"]), 169, [],
3191    [InitBasicFS, Always, TestOutputStruct (
3192       [["fallocate"; "/a"; "1000000"];
3193        ["stat"; "/a"]], [CompareWithInt ("size", 1_000_000)])],
3194    "preallocate a file in the guest filesystem",
3195    "\
3196 This command preallocates a file (containing zero bytes) named
3197 C<path> of size C<len> bytes.  If the file exists already, it
3198 is overwritten.
3199
3200 Do not confuse this with the guestfish-specific
3201 C<alloc> command which allocates a file in the host and
3202 attaches it as a device.");
3203
3204 ]
3205
3206 let all_functions = non_daemon_functions @ daemon_functions
3207
3208 (* In some places we want the functions to be displayed sorted
3209  * alphabetically, so this is useful:
3210  *)
3211 let all_functions_sorted =
3212   List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
3213                compare n1 n2) all_functions
3214
3215 (* Field types for structures. *)
3216 type field =
3217   | FChar                       (* C 'char' (really, a 7 bit byte). *)
3218   | FString                     (* nul-terminated ASCII string. *)
3219   | FBuffer                     (* opaque buffer of bytes, (char *, int) pair *)
3220   | FUInt32
3221   | FInt32
3222   | FUInt64
3223   | FInt64
3224   | FBytes                      (* Any int measure that counts bytes. *)
3225   | FUUID                       (* 32 bytes long, NOT nul-terminated. *)
3226   | FOptPercent                 (* [0..100], or -1 meaning "not present". *)
3227
3228 (* Because we generate extra parsing code for LVM command line tools,
3229  * we have to pull out the LVM columns separately here.
3230  *)
3231 let lvm_pv_cols = [
3232   "pv_name", FString;
3233   "pv_uuid", FUUID;
3234   "pv_fmt", FString;
3235   "pv_size", FBytes;
3236   "dev_size", FBytes;
3237   "pv_free", FBytes;
3238   "pv_used", FBytes;
3239   "pv_attr", FString (* XXX *);
3240   "pv_pe_count", FInt64;
3241   "pv_pe_alloc_count", FInt64;
3242   "pv_tags", FString;
3243   "pe_start", FBytes;
3244   "pv_mda_count", FInt64;
3245   "pv_mda_free", FBytes;
3246   (* Not in Fedora 10:
3247      "pv_mda_size", FBytes;
3248   *)
3249 ]
3250 let lvm_vg_cols = [
3251   "vg_name", FString;
3252   "vg_uuid", FUUID;
3253   "vg_fmt", FString;
3254   "vg_attr", FString (* XXX *);
3255   "vg_size", FBytes;
3256   "vg_free", FBytes;
3257   "vg_sysid", FString;
3258   "vg_extent_size", FBytes;
3259   "vg_extent_count", FInt64;
3260   "vg_free_count", FInt64;
3261   "max_lv", FInt64;
3262   "max_pv", FInt64;
3263   "pv_count", FInt64;
3264   "lv_count", FInt64;
3265   "snap_count", FInt64;
3266   "vg_seqno", FInt64;
3267   "vg_tags", FString;
3268   "vg_mda_count", FInt64;
3269   "vg_mda_free", FBytes;
3270   (* Not in Fedora 10:
3271      "vg_mda_size", FBytes;
3272   *)
3273 ]
3274 let lvm_lv_cols = [
3275   "lv_name", FString;
3276   "lv_uuid", FUUID;
3277   "lv_attr", FString (* XXX *);
3278   "lv_major", FInt64;
3279   "lv_minor", FInt64;
3280   "lv_kernel_major", FInt64;
3281   "lv_kernel_minor", FInt64;
3282   "lv_size", FBytes;
3283   "seg_count", FInt64;
3284   "origin", FString;
3285   "snap_percent", FOptPercent;
3286   "copy_percent", FOptPercent;
3287   "move_pv", FString;
3288   "lv_tags", FString;
3289   "mirror_log", FString;
3290   "modules", FString;
3291 ]
3292
3293 (* Names and fields in all structures (in RStruct and RStructList)
3294  * that we support.
3295  *)
3296 let structs = [
3297   (* The old RIntBool return type, only ever used for aug_defnode.  Do
3298    * not use this struct in any new code.
3299    *)
3300   "int_bool", [
3301     "i", FInt32;                (* for historical compatibility *)
3302     "b", FInt32;                (* for historical compatibility *)
3303   ];
3304
3305   (* LVM PVs, VGs, LVs. *)
3306   "lvm_pv", lvm_pv_cols;
3307   "lvm_vg", lvm_vg_cols;
3308   "lvm_lv", lvm_lv_cols;
3309
3310   (* Column names and types from stat structures.
3311    * NB. Can't use things like 'st_atime' because glibc header files
3312    * define some of these as macros.  Ugh.
3313    *)
3314   "stat", [
3315     "dev", FInt64;
3316     "ino", FInt64;
3317     "mode", FInt64;
3318     "nlink", FInt64;
3319     "uid", FInt64;
3320     "gid", FInt64;
3321     "rdev", FInt64;
3322     "size", FInt64;
3323     "blksize", FInt64;
3324     "blocks", FInt64;
3325     "atime", FInt64;
3326     "mtime", FInt64;
3327     "ctime", FInt64;
3328   ];
3329   "statvfs", [
3330     "bsize", FInt64;
3331     "frsize", FInt64;
3332     "blocks", FInt64;
3333     "bfree", FInt64;
3334     "bavail", FInt64;
3335     "files", FInt64;
3336     "ffree", FInt64;
3337     "favail", FInt64;
3338     "fsid", FInt64;
3339     "flag", FInt64;
3340     "namemax", FInt64;
3341   ];
3342
3343   (* Column names in dirent structure. *)
3344   "dirent", [
3345     "ino", FInt64;
3346     (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
3347     "ftyp", FChar;
3348     "name", FString;
3349   ];
3350
3351   (* Version numbers. *)
3352   "version", [
3353     "major", FInt64;
3354     "minor", FInt64;
3355     "release", FInt64;
3356     "extra", FString;
3357   ];
3358
3359   (* Extended attribute. *)
3360   "xattr", [
3361     "attrname", FString;
3362     "attrval", FBuffer;
3363   ];
3364 ] (* end of structs *)
3365
3366 (* Ugh, Java has to be different ..
3367  * These names are also used by the Haskell bindings.
3368  *)
3369 let java_structs = [
3370   "int_bool", "IntBool";
3371   "lvm_pv", "PV";
3372   "lvm_vg", "VG";
3373   "lvm_lv", "LV";
3374   "stat", "Stat";
3375   "statvfs", "StatVFS";
3376   "dirent", "Dirent";
3377   "version", "Version";
3378   "xattr", "XAttr";
3379 ]
3380
3381 (* Used for testing language bindings. *)
3382 type callt =
3383   | CallString of string
3384   | CallOptString of string option
3385   | CallStringList of string list
3386   | CallInt of int
3387   | CallBool of bool
3388
3389 (* Used to memoize the result of pod2text. *)
3390 let pod2text_memo_filename = "src/.pod2text.data"
3391 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
3392   try
3393     let chan = open_in pod2text_memo_filename in
3394     let v = input_value chan in
3395     close_in chan;
3396     v
3397   with
3398     _ -> Hashtbl.create 13
3399
3400 (* Useful functions.
3401  * Note we don't want to use any external OCaml libraries which
3402  * makes this a bit harder than it should be.
3403  *)
3404 let failwithf fs = ksprintf failwith fs
3405
3406 let replace_char s c1 c2 =
3407   let s2 = String.copy s in
3408   let r = ref false in
3409   for i = 0 to String.length s2 - 1 do
3410     if String.unsafe_get s2 i = c1 then (
3411       String.unsafe_set s2 i c2;
3412       r := true
3413     )
3414   done;
3415   if not !r then s else s2
3416
3417 let isspace c =
3418   c = ' '
3419   (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
3420
3421 let triml ?(test = isspace) str =
3422   let i = ref 0 in
3423   let n = ref (String.length str) in
3424   while !n > 0 && test str.[!i]; do
3425     decr n;
3426     incr i
3427   done;
3428   if !i = 0 then str
3429   else String.sub str !i !n
3430
3431 let trimr ?(test = isspace) str =
3432   let n = ref (String.length str) in
3433   while !n > 0 && test str.[!n-1]; do
3434     decr n
3435   done;
3436   if !n = String.length str then str
3437   else String.sub str 0 !n
3438
3439 let trim ?(test = isspace) str =
3440   trimr ~test (triml ~test str)
3441
3442 let rec find s sub =
3443   let len = String.length s in
3444   let sublen = String.length sub in
3445   let rec loop i =
3446     if i <= len-sublen then (
3447       let rec loop2 j =
3448         if j < sublen then (
3449           if s.[i+j] = sub.[j] then loop2 (j+1)
3450           else -1
3451         ) else
3452           i (* found *)
3453       in
3454       let r = loop2 0 in
3455       if r = -1 then loop (i+1) else r
3456     ) else
3457       -1 (* not found *)
3458   in
3459   loop 0
3460
3461 let rec replace_str s s1 s2 =
3462   let len = String.length s in
3463   let sublen = String.length s1 in
3464   let i = find s s1 in
3465   if i = -1 then s
3466   else (
3467     let s' = String.sub s 0 i in
3468     let s'' = String.sub s (i+sublen) (len-i-sublen) in
3469     s' ^ s2 ^ replace_str s'' s1 s2
3470   )
3471
3472 let rec string_split sep str =
3473   let len = String.length str in
3474   let seplen = String.length sep in
3475   let i = find str sep in
3476   if i = -1 then [str]
3477   else (
3478     let s' = String.sub str 0 i in
3479     let s'' = String.sub str (i+seplen) (len-i-seplen) in
3480     s' :: string_split sep s''
3481   )
3482
3483 let files_equal n1 n2 =
3484   let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
3485   match Sys.command cmd with
3486   | 0 -> true
3487   | 1 -> false
3488   | i -> failwithf "%s: failed with error code %d" cmd i
3489
3490 let rec find_map f = function
3491   | [] -> raise Not_found
3492   | x :: xs ->
3493       match f x with
3494       | Some y -> y
3495       | None -> find_map f xs
3496
3497 let iteri f xs =
3498   let rec loop i = function
3499     | [] -> ()
3500     | x :: xs -> f i x; loop (i+1) xs
3501   in
3502   loop 0 xs
3503
3504 let mapi f xs =
3505   let rec loop i = function
3506     | [] -> []
3507     | x :: xs -> let r = f i x in r :: loop (i+1) xs
3508   in
3509   loop 0 xs
3510
3511 let name_of_argt = function
3512   | String n | OptString n | StringList n | Bool n | Int n
3513   | FileIn n | FileOut n -> n
3514
3515 let java_name_of_struct typ =
3516   try List.assoc typ java_structs
3517   with Not_found ->
3518     failwithf
3519       "java_name_of_struct: no java_structs entry corresponding to %s" typ
3520
3521 let cols_of_struct typ =
3522   try List.assoc typ structs
3523   with Not_found ->
3524     failwithf "cols_of_struct: unknown struct %s" typ
3525
3526 let seq_of_test = function
3527   | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
3528   | TestOutputListOfDevices (s, _)
3529   | TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
3530   | TestOutputTrue s | TestOutputFalse s
3531   | TestOutputLength (s, _) | TestOutputBuffer (s, _)
3532   | TestOutputStruct (s, _)
3533   | TestLastFail s -> s
3534
3535 (* Handling for function flags. *)
3536 let protocol_limit_warning =
3537   "Because of the message protocol, there is a transfer limit
3538 of somewhere between 2MB and 4MB.  To transfer large files you should use
3539 FTP."
3540
3541 let danger_will_robinson =
3542   "B<This command is dangerous.  Without careful use you
3543 can easily destroy all your data>."
3544
3545 let deprecation_notice flags =
3546   try
3547     let alt =
3548       find_map (function DeprecatedBy str -> Some str | _ -> None) flags in
3549     let txt =
3550       sprintf "This function is deprecated.
3551 In new code, use the C<%s> call instead.
3552
3553 Deprecated functions will not be removed from the API, but the
3554 fact that they are deprecated indicates that there are problems
3555 with correct use of these functions." alt in
3556     Some txt
3557   with
3558     Not_found -> None
3559
3560 (* Check function names etc. for consistency. *)
3561 let check_functions () =
3562   let contains_uppercase str =
3563     let len = String.length str in
3564     let rec loop i =
3565       if i >= len then false
3566       else (
3567         let c = str.[i] in
3568         if c >= 'A' && c <= 'Z' then true
3569         else loop (i+1)
3570       )
3571     in
3572     loop 0
3573   in
3574
3575   (* Check function names. *)
3576   List.iter (
3577     fun (name, _, _, _, _, _, _) ->
3578       if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
3579         failwithf "function name %s does not need 'guestfs' prefix" name;
3580       if name = "" then
3581         failwithf "function name is empty";
3582       if name.[0] < 'a' || name.[0] > 'z' then
3583         failwithf "function name %s must start with lowercase a-z" name;
3584       if String.contains name '-' then
3585         failwithf "function name %s should not contain '-', use '_' instead."
3586           name
3587   ) all_functions;
3588
3589   (* Check function parameter/return names. *)
3590   List.iter (
3591     fun (name, style, _, _, _, _, _) ->
3592       let check_arg_ret_name n =
3593         if contains_uppercase n then
3594           failwithf "%s param/ret %s should not contain uppercase chars"
3595             name n;
3596         if String.contains n '-' || String.contains n '_' then
3597           failwithf "%s param/ret %s should not contain '-' or '_'"
3598             name n;
3599         if n = "value" then
3600           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;
3601         if n = "int" || n = "char" || n = "short" || n = "long" then
3602           failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
3603         if n = "i" || n = "n" then
3604           failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
3605         if n = "argv" || n = "args" then
3606           failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name
3607       in
3608
3609       (match fst style with
3610        | RErr -> ()
3611        | RInt n | RInt64 n | RBool n
3612        | RConstString n | RConstOptString n | RString n
3613        | RStringList n | RStruct (n, _) | RStructList (n, _)
3614        | RHashtable n | RBufferOut n ->
3615            check_arg_ret_name n
3616       );
3617       List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
3618   ) all_functions;
3619
3620   (* Check short descriptions. *)
3621   List.iter (
3622     fun (name, _, _, _, _, shortdesc, _) ->
3623       if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
3624         failwithf "short description of %s should begin with lowercase." name;
3625       let c = shortdesc.[String.length shortdesc-1] in
3626       if c = '\n' || c = '.' then
3627         failwithf "short description of %s should not end with . or \\n." name
3628   ) all_functions;
3629
3630   (* Check long dscriptions. *)
3631   List.iter (
3632     fun (name, _, _, _, _, _, longdesc) ->
3633       if longdesc.[String.length longdesc-1] = '\n' then
3634         failwithf "long description of %s should not end with \\n." name
3635   ) all_functions;
3636
3637   (* Check proc_nrs. *)
3638   List.iter (
3639     fun (name, _, proc_nr, _, _, _, _) ->
3640       if proc_nr <= 0 then
3641         failwithf "daemon function %s should have proc_nr > 0" name
3642   ) daemon_functions;
3643
3644   List.iter (
3645     fun (name, _, proc_nr, _, _, _, _) ->
3646       if proc_nr <> -1 then
3647         failwithf "non-daemon function %s should have proc_nr -1" name
3648   ) non_daemon_functions;
3649
3650   let proc_nrs =
3651     List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
3652       daemon_functions in
3653   let proc_nrs =
3654     List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
3655   let rec loop = function
3656     | [] -> ()
3657     | [_] -> ()
3658     | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
3659         loop rest
3660     | (name1,nr1) :: (name2,nr2) :: _ ->
3661         failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
3662           name1 name2 nr1 nr2
3663   in
3664   loop proc_nrs;
3665
3666   (* Check tests. *)
3667   List.iter (
3668     function
3669       (* Ignore functions that have no tests.  We generate a
3670        * warning when the user does 'make check' instead.
3671        *)
3672     | name, _, _, _, [], _, _ -> ()
3673     | name, _, _, _, tests, _, _ ->
3674         let funcs =
3675           List.map (
3676             fun (_, _, test) ->
3677               match seq_of_test test with
3678               | [] ->
3679                   failwithf "%s has a test containing an empty sequence" name
3680               | cmds -> List.map List.hd cmds
3681           ) tests in
3682         let funcs = List.flatten funcs in
3683
3684         let tested = List.mem name funcs in
3685
3686         if not tested then
3687           failwithf "function %s has tests but does not test itself" name
3688   ) all_functions
3689
3690 (* 'pr' prints to the current output file. *)
3691 let chan = ref stdout
3692 let pr fs = ksprintf (output_string !chan) fs
3693
3694 (* Generate a header block in a number of standard styles. *)
3695 type comment_style = CStyle | HashStyle | OCamlStyle | HaskellStyle
3696 type license = GPLv2 | LGPLv2
3697
3698 let generate_header comment license =
3699   let c = match comment with
3700     | CStyle ->     pr "/* "; " *"
3701     | HashStyle ->  pr "# ";  "#"
3702     | OCamlStyle -> pr "(* "; " *"
3703     | HaskellStyle -> pr "{- "; "  " in
3704   pr "libguestfs generated file\n";
3705   pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
3706   pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
3707   pr "%s\n" c;
3708   pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
3709   pr "%s\n" c;
3710   (match license with
3711    | GPLv2 ->
3712        pr "%s This program is free software; you can redistribute it and/or modify\n" c;
3713        pr "%s it under the terms of the GNU General Public License as published by\n" c;
3714        pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
3715        pr "%s (at your option) any later version.\n" c;
3716        pr "%s\n" c;
3717        pr "%s This program is distributed in the hope that it will be useful,\n" c;
3718        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
3719        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" c;
3720        pr "%s GNU General Public License for more details.\n" c;
3721        pr "%s\n" c;
3722        pr "%s You should have received a copy of the GNU General Public License along\n" c;
3723        pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
3724        pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
3725
3726    | LGPLv2 ->
3727        pr "%s This library is free software; you can redistribute it and/or\n" c;
3728        pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
3729        pr "%s License as published by the Free Software Foundation; either\n" c;
3730        pr "%s version 2 of the License, or (at your option) any later version.\n" c;
3731        pr "%s\n" c;
3732        pr "%s This library is distributed in the hope that it will be useful,\n" c;
3733        pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
3734        pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n" c;
3735        pr "%s Lesser General Public License for more details.\n" c;
3736        pr "%s\n" c;
3737        pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
3738        pr "%s License along with this library; if not, write to the Free Software\n" c;
3739        pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
3740   );
3741   (match comment with
3742    | CStyle -> pr " */\n"
3743    | HashStyle -> ()
3744    | OCamlStyle -> pr " *)\n"
3745    | HaskellStyle -> pr "-}\n"
3746   );
3747   pr "\n"
3748
3749 (* Start of main code generation functions below this line. *)
3750
3751 (* Generate the pod documentation for the C API. *)
3752 let rec generate_actions_pod () =
3753   List.iter (
3754     fun (shortname, style, _, flags, _, _, longdesc) ->
3755       if not (List.mem NotInDocs flags) then (
3756         let name = "guestfs_" ^ shortname in
3757         pr "=head2 %s\n\n" name;
3758         pr " ";
3759         generate_prototype ~extern:false ~handle:"handle" name style;
3760         pr "\n\n";
3761         pr "%s\n\n" longdesc;
3762         (match fst style with
3763          | RErr ->
3764              pr "This function returns 0 on success or -1 on error.\n\n"
3765          | RInt _ ->
3766              pr "On error this function returns -1.\n\n"
3767          | RInt64 _ ->
3768              pr "On error this function returns -1.\n\n"
3769          | RBool _ ->
3770              pr "This function returns a C truth value on success or -1 on error.\n\n"
3771          | RConstString _ ->
3772              pr "This function returns a string, or NULL on error.
3773 The string is owned by the guest handle and must I<not> be freed.\n\n"
3774          | RConstOptString _ ->
3775              pr "This function returns a string which may be NULL.
3776 There is way to return an error from this function.
3777 The string is owned by the guest handle and must I<not> be freed.\n\n"
3778          | RString _ ->
3779              pr "This function returns a string, or NULL on error.
3780 I<The caller must free the returned string after use>.\n\n"
3781          | RStringList _ ->
3782              pr "This function returns a NULL-terminated array of strings
3783 (like L<environ(3)>), or NULL if there was an error.
3784 I<The caller must free the strings and the array after use>.\n\n"
3785          | RStruct (_, typ) ->
3786              pr "This function returns a C<struct guestfs_%s *>,
3787 or NULL if there was an error.
3788 I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ
3789          | RStructList (_, typ) ->
3790              pr "This function returns a C<struct guestfs_%s_list *>
3791 (see E<lt>guestfs-structs.hE<gt>),
3792 or NULL if there was an error.
3793 I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ
3794          | RHashtable _ ->
3795              pr "This function returns a NULL-terminated array of
3796 strings, or NULL if there was an error.
3797 The array of strings will always have length C<2n+1>, where
3798 C<n> keys and values alternate, followed by the trailing NULL entry.
3799 I<The caller must free the strings and the array after use>.\n\n"
3800          | RBufferOut _ ->
3801              pr "This function returns a buffer, or NULL on error.
3802 The size of the returned buffer is written to C<*size_r>.
3803 I<The caller must free the returned buffer after use>.\n\n"
3804         );
3805         if List.mem ProtocolLimitWarning flags then
3806           pr "%s\n\n" protocol_limit_warning;
3807         if List.mem DangerWillRobinson flags then
3808           pr "%s\n\n" danger_will_robinson;
3809         match deprecation_notice flags with
3810         | None -> ()
3811         | Some txt -> pr "%s\n\n" txt
3812       )
3813   ) all_functions_sorted
3814
3815 and generate_structs_pod () =
3816   (* Structs documentation. *)
3817   List.iter (
3818     fun (typ, cols) ->
3819       pr "=head2 guestfs_%s\n" typ;
3820       pr "\n";
3821       pr " struct guestfs_%s {\n" typ;
3822       List.iter (
3823         function
3824         | name, FChar -> pr "   char %s;\n" name
3825         | name, FUInt32 -> pr "   uint32_t %s;\n" name
3826         | name, FInt32 -> pr "   int32_t %s;\n" name
3827         | name, (FUInt64|FBytes) -> pr "   uint64_t %s;\n" name
3828         | name, FInt64 -> pr "   int64_t %s;\n" name
3829         | name, FString -> pr "   char *%s;\n" name
3830         | name, FBuffer ->
3831             pr "   /* The next two fields describe a byte array. */\n";
3832             pr "   uint32_t %s_len;\n" name;
3833             pr "   char *%s;\n" name
3834         | name, FUUID ->
3835             pr "   /* The next field is NOT nul-terminated, be careful when printing it: */\n";
3836             pr "   char %s[32];\n" name
3837         | name, FOptPercent ->
3838             pr "   /* The next field is [0..100] or -1 meaning 'not present': */\n";
3839             pr "   float %s;\n" name
3840       ) cols;
3841       pr " };\n";
3842       pr " \n";
3843       pr " struct guestfs_%s_list {\n" typ;
3844       pr "   uint32_t len; /* Number of elements in list. */\n";
3845       pr "   struct guestfs_%s *val; /* Elements. */\n" typ;
3846       pr " };\n";
3847       pr " \n";
3848       pr " void guestfs_free_%s (struct guestfs_free_%s *);\n" typ typ;
3849       pr " void guestfs_free_%s_list (struct guestfs_free_%s_list *);\n"
3850         typ typ;
3851       pr "\n"
3852   ) structs
3853
3854 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
3855  * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
3856  *
3857  * We have to use an underscore instead of a dash because otherwise
3858  * rpcgen generates incorrect code.
3859  *
3860  * This header is NOT exported to clients, but see also generate_structs_h.
3861  *)
3862 and generate_xdr () =
3863   generate_header CStyle LGPLv2;
3864
3865   (* This has to be defined to get around a limitation in Sun's rpcgen. *)
3866   pr "typedef string str<>;\n";
3867   pr "\n";
3868
3869   (* Internal structures. *)
3870   List.iter (
3871     function
3872     | typ, cols ->
3873         pr "struct guestfs_int_%s {\n" typ;
3874         List.iter (function
3875                    | name, FChar -> pr "  char %s;\n" name
3876                    | name, FString -> pr "  string %s<>;\n" name
3877                    | name, FBuffer -> pr "  opaque %s<>;\n" name
3878                    | name, FUUID -> pr "  opaque %s[32];\n" name
3879                    | name, (FInt32|FUInt32) -> pr "  int %s;\n" name
3880                    | name, (FInt64|FUInt64|FBytes) -> pr "  hyper %s;\n" name
3881                    | name, FOptPercent -> pr "  float %s;\n" name
3882                   ) cols;
3883         pr "};\n";
3884         pr "\n";
3885         pr "typedef struct guestfs_int_%s guestfs_int_%s_list<>;\n" typ typ;
3886         pr "\n";
3887   ) structs;
3888
3889   List.iter (
3890     fun (shortname, style, _, _, _, _, _) ->
3891       let name = "guestfs_" ^ shortname in
3892
3893       (match snd style with
3894        | [] -> ()
3895        | args ->
3896            pr "struct %s_args {\n" name;
3897            List.iter (
3898              function
3899              | String n -> pr "  string %s<>;\n" n
3900              | OptString n -> pr "  str *%s;\n" n
3901              | StringList n -> pr "  str %s<>;\n" n
3902              | Bool n -> pr "  bool %s;\n" n
3903              | Int n -> pr "  int %s;\n" n
3904              | FileIn _ | FileOut _ -> ()
3905            ) args;
3906            pr "};\n\n"
3907       );
3908       (match fst style with
3909        | RErr -> ()
3910        | RInt n ->
3911            pr "struct %s_ret {\n" name;
3912            pr "  int %s;\n" n;
3913            pr "};\n\n"
3914        | RInt64 n ->
3915            pr "struct %s_ret {\n" name;
3916            pr "  hyper %s;\n" n;
3917            pr "};\n\n"
3918        | RBool n ->
3919            pr "struct %s_ret {\n" name;
3920            pr "  bool %s;\n" n;
3921            pr "};\n\n"
3922        | RConstString _ | RConstOptString _ ->
3923            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
3924        | RString n ->
3925            pr "struct %s_ret {\n" name;
3926            pr "  string %s<>;\n" n;
3927            pr "};\n\n"
3928        | RStringList n ->
3929            pr "struct %s_ret {\n" name;
3930            pr "  str %s<>;\n" n;
3931            pr "};\n\n"
3932        | RStruct (n, typ) ->
3933            pr "struct %s_ret {\n" name;
3934            pr "  guestfs_int_%s %s;\n" typ n;
3935            pr "};\n\n"
3936        | RStructList (n, typ) ->
3937            pr "struct %s_ret {\n" name;
3938            pr "  guestfs_int_%s_list %s;\n" typ n;
3939            pr "};\n\n"
3940        | RHashtable n ->
3941            pr "struct %s_ret {\n" name;
3942            pr "  str %s<>;\n" n;
3943            pr "};\n\n"
3944        | RBufferOut n ->
3945            pr "struct %s_ret {\n" name;
3946            pr "  opaque %s<>;\n" n;
3947            pr "};\n\n"
3948       );
3949   ) daemon_functions;
3950
3951   (* Table of procedure numbers. *)
3952   pr "enum guestfs_procedure {\n";
3953   List.iter (
3954     fun (shortname, _, proc_nr, _, _, _, _) ->
3955       pr "  GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
3956   ) daemon_functions;
3957   pr "  GUESTFS_PROC_NR_PROCS\n";
3958   pr "};\n";
3959   pr "\n";
3960
3961   (* Having to choose a maximum message size is annoying for several
3962    * reasons (it limits what we can do in the API), but it (a) makes
3963    * the protocol a lot simpler, and (b) provides a bound on the size
3964    * of the daemon which operates in limited memory space.  For large
3965    * file transfers you should use FTP.
3966    *)
3967   pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
3968   pr "\n";
3969
3970   (* Message header, etc. *)
3971   pr "\
3972 /* The communication protocol is now documented in the guestfs(3)
3973  * manpage.
3974  */
3975
3976 const GUESTFS_PROGRAM = 0x2000F5F5;
3977 const GUESTFS_PROTOCOL_VERSION = 1;
3978
3979 /* These constants must be larger than any possible message length. */
3980 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
3981 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
3982
3983 enum guestfs_message_direction {
3984   GUESTFS_DIRECTION_CALL = 0,        /* client -> daemon */
3985   GUESTFS_DIRECTION_REPLY = 1        /* daemon -> client */
3986 };
3987
3988 enum guestfs_message_status {
3989   GUESTFS_STATUS_OK = 0,
3990   GUESTFS_STATUS_ERROR = 1
3991 };
3992
3993 const GUESTFS_ERROR_LEN = 256;
3994
3995 struct guestfs_message_error {
3996   string error_message<GUESTFS_ERROR_LEN>;
3997 };
3998
3999 struct guestfs_message_header {
4000   unsigned prog;                     /* GUESTFS_PROGRAM */
4001   unsigned vers;                     /* GUESTFS_PROTOCOL_VERSION */
4002   guestfs_procedure proc;            /* GUESTFS_PROC_x */
4003   guestfs_message_direction direction;
4004   unsigned serial;                   /* message serial number */
4005   guestfs_message_status status;
4006 };
4007
4008 const GUESTFS_MAX_CHUNK_SIZE = 8192;
4009
4010 struct guestfs_chunk {
4011   int cancel;                        /* if non-zero, transfer is cancelled */
4012   /* data size is 0 bytes if the transfer has finished successfully */
4013   opaque data<GUESTFS_MAX_CHUNK_SIZE>;
4014 };
4015 "
4016
4017 (* Generate the guestfs-structs.h file. *)
4018 and generate_structs_h () =
4019   generate_header CStyle LGPLv2;
4020
4021   (* This is a public exported header file containing various
4022    * structures.  The structures are carefully written to have
4023    * exactly the same in-memory format as the XDR structures that
4024    * we use on the wire to the daemon.  The reason for creating
4025    * copies of these structures here is just so we don't have to
4026    * export the whole of guestfs_protocol.h (which includes much
4027    * unrelated and XDR-dependent stuff that we don't want to be
4028    * public, or required by clients).
4029    *
4030    * To reiterate, we will pass these structures to and from the
4031    * client with a simple assignment or memcpy, so the format
4032    * must be identical to what rpcgen / the RFC defines.
4033    *)
4034
4035   (* Public structures. *)
4036   List.iter (
4037     fun (typ, cols) ->
4038       pr "struct guestfs_%s {\n" typ;
4039       List.iter (
4040         function
4041         | name, FChar -> pr "  char %s;\n" name
4042         | name, FString -> pr "  char *%s;\n" name
4043         | name, FBuffer ->
4044             pr "  uint32_t %s_len;\n" name;
4045             pr "  char *%s;\n" name
4046         | name, FUUID -> pr "  char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
4047         | name, FUInt32 -> pr "  uint32_t %s;\n" name
4048         | name, FInt32 -> pr "  int32_t %s;\n" name
4049         | name, (FUInt64|FBytes) -> pr "  uint64_t %s;\n" name
4050         | name, FInt64 -> pr "  int64_t %s;\n" name
4051         | name, FOptPercent -> pr "  float %s; /* [0..100] or -1 */\n" name
4052       ) cols;
4053       pr "};\n";
4054       pr "\n";
4055       pr "struct guestfs_%s_list {\n" typ;
4056       pr "  uint32_t len;\n";
4057       pr "  struct guestfs_%s *val;\n" typ;
4058       pr "};\n";
4059       pr "\n";
4060       pr "extern void guestfs_free_%s (struct guestfs_%s *);\n" typ typ;
4061       pr "extern void guestfs_free_%s_list (struct guestfs_%s_list *);\n" typ typ;
4062       pr "\n"
4063   ) structs
4064
4065 (* Generate the guestfs-actions.h file. *)
4066 and generate_actions_h () =
4067   generate_header CStyle LGPLv2;
4068   List.iter (
4069     fun (shortname, style, _, _, _, _, _) ->
4070       let name = "guestfs_" ^ shortname in
4071       generate_prototype ~single_line:true ~newline:true ~handle:"handle"
4072         name style
4073   ) all_functions
4074
4075 (* Generate the client-side dispatch stubs. *)
4076 and generate_client_actions () =
4077   generate_header CStyle LGPLv2;
4078
4079   pr "\
4080 #include <stdio.h>
4081 #include <stdlib.h>
4082
4083 #include \"guestfs.h\"
4084 #include \"guestfs_protocol.h\"
4085
4086 #define error guestfs_error
4087 #define perrorf guestfs_perrorf
4088 #define safe_malloc guestfs_safe_malloc
4089 #define safe_realloc guestfs_safe_realloc
4090 #define safe_strdup guestfs_safe_strdup
4091 #define safe_memdup guestfs_safe_memdup
4092
4093 /* Check the return message from a call for validity. */
4094 static int
4095 check_reply_header (guestfs_h *g,
4096                     const struct guestfs_message_header *hdr,
4097                     int proc_nr, int serial)
4098 {
4099   if (hdr->prog != GUESTFS_PROGRAM) {
4100     error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
4101     return -1;
4102   }
4103   if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
4104     error (g, \"wrong protocol version (%%d/%%d)\",
4105            hdr->vers, GUESTFS_PROTOCOL_VERSION);
4106     return -1;
4107   }
4108   if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
4109     error (g, \"unexpected message direction (%%d/%%d)\",
4110            hdr->direction, GUESTFS_DIRECTION_REPLY);
4111     return -1;
4112   }
4113   if (hdr->proc != proc_nr) {
4114     error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
4115     return -1;
4116   }
4117   if (hdr->serial != serial) {
4118     error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
4119     return -1;
4120   }
4121
4122   return 0;
4123 }
4124
4125 /* Check we are in the right state to run a high-level action. */
4126 static int
4127 check_state (guestfs_h *g, const char *caller)
4128 {
4129   if (!guestfs_is_ready (g)) {
4130     if (guestfs_is_config (g))
4131       error (g, \"%%s: call launch before using this function\\n(in guestfish, don't forget to use the 'run' command)\",
4132         caller);
4133     else if (guestfs_is_launching (g))
4134       error (g, \"%%s: call wait_ready() before using this function\",
4135         caller);
4136     else
4137       error (g, \"%%s called from the wrong state, %%d != READY\",
4138         caller, guestfs_get_state (g));
4139     return -1;
4140   }
4141   return 0;
4142 }
4143
4144 ";
4145
4146   (* Client-side stubs for each function. *)
4147   List.iter (
4148     fun (shortname, style, _, _, _, _, _) ->
4149       let name = "guestfs_" ^ shortname in
4150
4151       (* Generate the context struct which stores the high-level
4152        * state between callback functions.
4153        *)
4154       pr "struct %s_ctx {\n" shortname;
4155       pr "  /* This flag is set by the callbacks, so we know we've done\n";
4156       pr "   * the callbacks as expected, and in the right sequence.\n";
4157       pr "   * 0 = not called, 1 = reply_cb called.\n";
4158       pr "   */\n";
4159       pr "  int cb_sequence;\n";
4160       pr "  struct guestfs_message_header hdr;\n";
4161       pr "  struct guestfs_message_error err;\n";
4162       (match fst style with
4163        | RErr -> ()
4164        | RConstString _ | RConstOptString _ ->
4165            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4166        | RInt _ | RInt64 _
4167        | RBool _ | RString _ | RStringList _
4168        | RStruct _ | RStructList _
4169        | RHashtable _ | RBufferOut _ ->
4170            pr "  struct %s_ret ret;\n" name
4171       );
4172       pr "};\n";
4173       pr "\n";
4174
4175       (* Generate the reply callback function. *)
4176       pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
4177       pr "{\n";
4178       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
4179       pr "  struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
4180       pr "\n";
4181       pr "  /* This should definitely not happen. */\n";
4182       pr "  if (ctx->cb_sequence != 0) {\n";
4183       pr "    ctx->cb_sequence = 9999;\n";
4184       pr "    error (g, \"%%s: internal error: reply callback called twice\", \"%s\");\n" name;
4185       pr "    return;\n";
4186       pr "  }\n";
4187       pr "\n";
4188       pr "  ml->main_loop_quit (ml, g);\n";
4189       pr "\n";
4190       pr "  if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
4191       pr "    error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
4192       pr "    return;\n";
4193       pr "  }\n";
4194       pr "  if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
4195       pr "    if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
4196       pr "      error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
4197         name;
4198       pr "      return;\n";
4199       pr "    }\n";
4200       pr "    goto done;\n";
4201       pr "  }\n";
4202
4203       (match fst style with
4204        | RErr -> ()
4205        | RConstString _ | RConstOptString _ ->
4206            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4207        | RInt _ | RInt64 _
4208        | RBool _ | RString _ | RStringList _
4209        | RStruct _ | RStructList _
4210        | RHashtable _ | RBufferOut _ ->
4211            pr "  if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
4212            pr "    error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
4213            pr "    return;\n";
4214            pr "  }\n";
4215       );
4216
4217       pr " done:\n";
4218       pr "  ctx->cb_sequence = 1;\n";
4219       pr "}\n\n";
4220
4221       (* Generate the action stub. *)
4222       generate_prototype ~extern:false ~semicolon:false ~newline:true
4223         ~handle:"g" name style;
4224
4225       let error_code =
4226         match fst style with
4227         | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
4228         | RConstString _ | RConstOptString _ ->
4229             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4230         | RString _ | RStringList _
4231         | RStruct _ | RStructList _
4232         | RHashtable _ | RBufferOut _ ->
4233             "NULL" in
4234
4235       pr "{\n";
4236
4237       (match snd style with
4238        | [] -> ()
4239        | _ -> pr "  struct %s_args args;\n" name
4240       );
4241
4242       pr "  struct %s_ctx ctx;\n" shortname;
4243       pr "  guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
4244       pr "  int serial;\n";
4245       pr "\n";
4246       pr "  if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
4247       pr "  guestfs_set_busy (g);\n";
4248       pr "\n";
4249       pr "  memset (&ctx, 0, sizeof ctx);\n";
4250       pr "\n";
4251
4252       (* Send the main header and arguments. *)
4253       (match snd style with
4254        | [] ->
4255            pr "  serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n"
4256              (String.uppercase shortname)
4257        | args ->
4258            List.iter (
4259              function
4260              | String n ->
4261                  pr "  args.%s = (char *) %s;\n" n n
4262              | OptString n ->
4263                  pr "  args.%s = %s ? (char **) &%s : NULL;\n" n n n
4264              | StringList n ->
4265                  pr "  args.%s.%s_val = (char **) %s;\n" n n n;
4266                  pr "  for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
4267              | Bool n ->
4268                  pr "  args.%s = %s;\n" n n
4269              | Int n ->
4270                  pr "  args.%s = %s;\n" n n
4271              | FileIn _ | FileOut _ -> ()
4272            ) args;
4273            pr "  serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
4274              (String.uppercase shortname);
4275            pr "        (xdrproc_t) xdr_%s_args, (char *) &args);\n"
4276              name;
4277       );
4278       pr "  if (serial == -1) {\n";
4279       pr "    guestfs_end_busy (g);\n";
4280       pr "    return %s;\n" error_code;
4281       pr "  }\n";
4282       pr "\n";
4283
4284       (* Send any additional files (FileIn) requested. *)
4285       let need_read_reply_label = ref false in
4286       List.iter (
4287         function
4288         | FileIn n ->
4289             pr "  {\n";
4290             pr "    int r;\n";
4291             pr "\n";
4292             pr "    r = guestfs__send_file_sync (g, %s);\n" n;
4293             pr "    if (r == -1) {\n";
4294             pr "      guestfs_end_busy (g);\n";
4295             pr "      return %s;\n" error_code;
4296             pr "    }\n";
4297             pr "    if (r == -2) /* daemon cancelled */\n";
4298             pr "      goto read_reply;\n";
4299             need_read_reply_label := true;
4300             pr "  }\n";
4301             pr "\n";
4302         | _ -> ()
4303       ) (snd style);
4304
4305       (* Wait for the reply from the remote end. *)
4306       if !need_read_reply_label then pr " read_reply:\n";
4307       pr "  guestfs__switch_to_receiving (g);\n";
4308       pr "  ctx.cb_sequence = 0;\n";
4309       pr "  guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
4310       pr "  (void) ml->main_loop_run (ml, g);\n";
4311       pr "  guestfs_set_reply_callback (g, NULL, NULL);\n";
4312       pr "  if (ctx.cb_sequence != 1) {\n";
4313       pr "    error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
4314       pr "    guestfs_end_busy (g);\n";
4315       pr "    return %s;\n" error_code;
4316       pr "  }\n";
4317       pr "\n";
4318
4319       pr "  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
4320         (String.uppercase shortname);
4321       pr "    guestfs_end_busy (g);\n";
4322       pr "    return %s;\n" error_code;
4323       pr "  }\n";
4324       pr "\n";
4325
4326       pr "  if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
4327       pr "    error (g, \"%%s\", ctx.err.error_message);\n";
4328       pr "    free (ctx.err.error_message);\n";
4329       pr "    guestfs_end_busy (g);\n";
4330       pr "    return %s;\n" error_code;
4331       pr "  }\n";
4332       pr "\n";
4333
4334       (* Expecting to receive further files (FileOut)? *)
4335       List.iter (
4336         function
4337         | FileOut n ->
4338             pr "  if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
4339             pr "    guestfs_end_busy (g);\n";
4340             pr "    return %s;\n" error_code;
4341             pr "  }\n";
4342             pr "\n";
4343         | _ -> ()
4344       ) (snd style);
4345
4346       pr "  guestfs_end_busy (g);\n";
4347
4348       (match fst style with
4349        | RErr -> pr "  return 0;\n"
4350        | RInt n | RInt64 n | RBool n ->
4351            pr "  return ctx.ret.%s;\n" n
4352        | RConstString _ | RConstOptString _ ->
4353            failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4354        | RString n ->
4355            pr "  return ctx.ret.%s; /* caller will free */\n" n
4356        | RStringList n | RHashtable n ->
4357            pr "  /* caller will free this, but we need to add a NULL entry */\n";
4358            pr "  ctx.ret.%s.%s_val =\n" n n;
4359            pr "    safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
4360            pr "                  sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
4361              n n;
4362            pr "  ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
4363            pr "  return ctx.ret.%s.%s_val;\n" n n
4364        | RStruct (n, _) ->
4365            pr "  /* caller will free this */\n";
4366            pr "  return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
4367        | RStructList (n, _) ->
4368            pr "  /* caller will free this */\n";
4369            pr "  return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
4370        | RBufferOut n ->
4371            pr "  *size_r = ctx.ret.%s.%s_len;\n" n n;
4372            pr "  return ctx.ret.%s.%s_val; /* caller will free */\n" n n
4373       );
4374
4375       pr "}\n\n"
4376   ) daemon_functions;
4377
4378   (* Functions to free structures. *)
4379   pr "/* Structure-freeing functions.  These rely on the fact that the\n";
4380   pr " * structure format is identical to the XDR format.  See note in\n";
4381   pr " * generator.ml.\n";
4382   pr " */\n";
4383   pr "\n";
4384
4385   List.iter (
4386     fun (typ, _) ->
4387       pr "void\n";
4388       pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
4389       pr "{\n";
4390       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
4391       pr "  free (x);\n";
4392       pr "}\n";
4393       pr "\n";
4394
4395       pr "void\n";
4396       pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
4397       pr "{\n";
4398       pr "  xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
4399       pr "  free (x);\n";
4400       pr "}\n";
4401       pr "\n";
4402
4403   ) structs;
4404
4405 (* Generate daemon/actions.h. *)
4406 and generate_daemon_actions_h () =
4407   generate_header CStyle GPLv2;
4408
4409   pr "#include \"../src/guestfs_protocol.h\"\n";
4410   pr "\n";
4411
4412   List.iter (
4413     fun (name, style, _, _, _, _, _) ->
4414       generate_prototype
4415         ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
4416         name style;
4417   ) daemon_functions
4418
4419 (* Generate the server-side stubs. *)
4420 and generate_daemon_actions () =
4421   generate_header CStyle GPLv2;
4422
4423   pr "#include <config.h>\n";
4424   pr "\n";
4425   pr "#include <stdio.h>\n";
4426   pr "#include <stdlib.h>\n";
4427   pr "#include <string.h>\n";
4428   pr "#include <inttypes.h>\n";
4429   pr "#include <ctype.h>\n";
4430   pr "#include <rpc/types.h>\n";
4431   pr "#include <rpc/xdr.h>\n";
4432   pr "\n";
4433   pr "#include \"daemon.h\"\n";
4434   pr "#include \"../src/guestfs_protocol.h\"\n";
4435   pr "#include \"actions.h\"\n";
4436   pr "\n";
4437
4438   List.iter (
4439     fun (name, style, _, _, _, _, _) ->
4440       (* Generate server-side stubs. *)
4441       pr "static void %s_stub (XDR *xdr_in)\n" name;
4442       pr "{\n";
4443       let error_code =
4444         match fst style with
4445         | RErr | RInt _ -> pr "  int r;\n"; "-1"
4446         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
4447         | RBool _ -> pr "  int r;\n"; "-1"
4448         | RConstString _ | RConstOptString _ ->
4449             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4450         | RString _ -> pr "  char *r;\n"; "NULL"
4451         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
4452         | RStruct (_, typ) -> pr "  guestfs_int_%s *r;\n" typ; "NULL"
4453         | RStructList (_, typ) -> pr "  guestfs_int_%s_list *r;\n" typ; "NULL"
4454         | RBufferOut _ ->
4455             pr "  size_t size;\n";
4456             pr "  char *r;\n";
4457             "NULL" in
4458
4459       (match snd style with
4460        | [] -> ()
4461        | args ->
4462            pr "  struct guestfs_%s_args args;\n" name;
4463            List.iter (
4464              function
4465                (* Note we allow the string to be writable, in order to
4466                 * allow device name translation.  This is safe because
4467                 * we can modify the string (passed from RPC).
4468                 *)
4469              | String n
4470              | OptString n -> pr "  char *%s;\n" n
4471              | StringList n -> pr "  char **%s;\n" n
4472              | Bool n -> pr "  int %s;\n" n
4473              | Int n -> pr "  int %s;\n" n
4474              | FileIn _ | FileOut _ -> ()
4475            ) args
4476       );
4477       pr "\n";
4478
4479       (match snd style with
4480        | [] -> ()
4481        | args ->
4482            pr "  memset (&args, 0, sizeof args);\n";
4483            pr "\n";
4484            pr "  if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
4485            pr "    reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
4486            pr "    return;\n";
4487            pr "  }\n";
4488            List.iter (
4489              function
4490              | String n -> pr "  %s = args.%s;\n" n n
4491              | OptString n -> pr "  %s = args.%s ? *args.%s : NULL;\n" n n n
4492              | StringList n ->
4493                  pr "  %s = realloc (args.%s.%s_val,\n" n n n;
4494                  pr "                sizeof (char *) * (args.%s.%s_len+1));\n" n n;
4495                  pr "  if (%s == NULL) {\n" n;
4496                  pr "    reply_with_perror (\"realloc\");\n";
4497                  pr "    goto done;\n";
4498                  pr "  }\n";
4499                  pr "  %s[args.%s.%s_len] = NULL;\n" n n n;
4500                  pr "  args.%s.%s_val = %s;\n" n n n;
4501              | Bool n -> pr "  %s = args.%s;\n" n n
4502              | Int n -> pr "  %s = args.%s;\n" n n
4503              | FileIn _ | FileOut _ -> ()
4504            ) args;
4505            pr "\n"
4506       );
4507
4508       (* Don't want to call the impl with any FileIn or FileOut
4509        * parameters, since these go "outside" the RPC protocol.
4510        *)
4511       let args' =
4512         List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
4513           (snd style) in
4514       pr "  r = do_%s " name;
4515       generate_c_call_args (fst style, args');
4516       pr ";\n";
4517
4518       pr "  if (r == %s)\n" error_code;
4519       pr "    /* do_%s has already called reply_with_error */\n" name;
4520       pr "    goto done;\n";
4521       pr "\n";
4522
4523       (* If there are any FileOut parameters, then the impl must
4524        * send its own reply.
4525        *)
4526       let no_reply =
4527         List.exists (function FileOut _ -> true | _ -> false) (snd style) in
4528       if no_reply then
4529         pr "  /* do_%s has already sent a reply */\n" name
4530       else (
4531         match fst style with
4532         | RErr -> pr "  reply (NULL, NULL);\n"
4533         | RInt n | RInt64 n | RBool n ->
4534             pr "  struct guestfs_%s_ret ret;\n" name;
4535             pr "  ret.%s = r;\n" n;
4536             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4537               name
4538         | RConstString _ | RConstOptString _ ->
4539             failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4540         | RString n ->
4541             pr "  struct guestfs_%s_ret ret;\n" name;
4542             pr "  ret.%s = r;\n" n;
4543             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4544               name;
4545             pr "  free (r);\n"
4546         | RStringList n | RHashtable n ->
4547             pr "  struct guestfs_%s_ret ret;\n" name;
4548             pr "  ret.%s.%s_len = count_strings (r);\n" n n;
4549             pr "  ret.%s.%s_val = r;\n" n n;
4550             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4551               name;
4552             pr "  free_strings (r);\n"
4553         | RStruct (n, _) ->
4554             pr "  struct guestfs_%s_ret ret;\n" name;
4555             pr "  ret.%s = *r;\n" n;
4556             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4557               name;
4558             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4559               name
4560         | RStructList (n, _) ->
4561             pr "  struct guestfs_%s_ret ret;\n" name;
4562             pr "  ret.%s = *r;\n" n;
4563             pr "  reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4564               name;
4565             pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4566               name
4567         | RBufferOut n ->
4568             pr "  struct guestfs_%s_ret ret;\n" name;
4569             pr "  ret.%s.%s_val = r;\n" n n;
4570             pr "  ret.%s.%s_len = size;\n" n n;
4571             pr "  reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4572               name;
4573             pr "  free (r);\n"
4574       );
4575
4576       (* Free the args. *)
4577       (match snd style with
4578        | [] ->
4579            pr "done: ;\n";
4580        | _ ->
4581            pr "done:\n";
4582            pr "  xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
4583              name
4584       );
4585
4586       pr "}\n\n";
4587   ) daemon_functions;
4588
4589   (* Dispatch function. *)
4590   pr "void dispatch_incoming_message (XDR *xdr_in)\n";
4591   pr "{\n";
4592   pr "  switch (proc_nr) {\n";
4593
4594   List.iter (
4595     fun (name, style, _, _, _, _, _) ->
4596       pr "    case GUESTFS_PROC_%s:\n" (String.uppercase name);
4597       pr "      %s_stub (xdr_in);\n" name;
4598       pr "      break;\n"
4599   ) daemon_functions;
4600
4601   pr "    default:\n";
4602   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";
4603   pr "  }\n";
4604   pr "}\n";
4605   pr "\n";
4606
4607   (* LVM columns and tokenization functions. *)
4608   (* XXX This generates crap code.  We should rethink how we
4609    * do this parsing.
4610    *)
4611   List.iter (
4612     function
4613     | typ, cols ->
4614         pr "static const char *lvm_%s_cols = \"%s\";\n"
4615           typ (String.concat "," (List.map fst cols));
4616         pr "\n";
4617
4618         pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
4619         pr "{\n";
4620         pr "  char *tok, *p, *next;\n";
4621         pr "  int i, j;\n";
4622         pr "\n";
4623         (*
4624           pr "  fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
4625           pr "\n";
4626         *)
4627         pr "  if (!str) {\n";
4628         pr "    fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
4629         pr "    return -1;\n";
4630         pr "  }\n";
4631         pr "  if (!*str || isspace (*str)) {\n";
4632         pr "    fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
4633         pr "    return -1;\n";
4634         pr "  }\n";
4635         pr "  tok = str;\n";
4636         List.iter (
4637           fun (name, coltype) ->
4638             pr "  if (!tok) {\n";
4639             pr "    fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
4640             pr "    return -1;\n";
4641             pr "  }\n";
4642             pr "  p = strchrnul (tok, ',');\n";
4643             pr "  if (*p) next = p+1; else next = NULL;\n";
4644             pr "  *p = '\\0';\n";
4645             (match coltype with
4646              | FString ->
4647                  pr "  r->%s = strdup (tok);\n" name;
4648                  pr "  if (r->%s == NULL) {\n" name;
4649                  pr "    perror (\"strdup\");\n";
4650                  pr "    return -1;\n";
4651                  pr "  }\n"
4652              | FUUID ->
4653                  pr "  for (i = j = 0; i < 32; ++j) {\n";
4654                  pr "    if (tok[j] == '\\0') {\n";
4655                  pr "      fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
4656                  pr "      return -1;\n";
4657                  pr "    } else if (tok[j] != '-')\n";
4658                  pr "      r->%s[i++] = tok[j];\n" name;
4659                  pr "  }\n";
4660              | FBytes ->
4661                  pr "  if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
4662                  pr "    fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4663                  pr "    return -1;\n";
4664                  pr "  }\n";
4665              | FInt64 ->
4666                  pr "  if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
4667                  pr "    fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4668                  pr "    return -1;\n";
4669                  pr "  }\n";
4670              | FOptPercent ->
4671                  pr "  if (tok[0] == '\\0')\n";
4672                  pr "    r->%s = -1;\n" name;
4673                  pr "  else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
4674                  pr "    fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4675                  pr "    return -1;\n";
4676                  pr "  }\n";
4677              | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
4678                  assert false (* can never be an LVM column *)
4679             );
4680             pr "  tok = next;\n";
4681         ) cols;
4682
4683         pr "  if (tok != NULL) {\n";
4684         pr "    fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
4685         pr "    return -1;\n";
4686         pr "  }\n";
4687         pr "  return 0;\n";
4688         pr "}\n";
4689         pr "\n";
4690
4691         pr "guestfs_int_lvm_%s_list *\n" typ;
4692         pr "parse_command_line_%ss (void)\n" typ;
4693         pr "{\n";
4694         pr "  char *out, *err;\n";
4695         pr "  char *p, *pend;\n";
4696         pr "  int r, i;\n";
4697         pr "  guestfs_int_lvm_%s_list *ret;\n" typ;
4698         pr "  void *newp;\n";
4699         pr "\n";
4700         pr "  ret = malloc (sizeof *ret);\n";
4701         pr "  if (!ret) {\n";
4702         pr "    reply_with_perror (\"malloc\");\n";
4703         pr "    return NULL;\n";
4704         pr "  }\n";
4705         pr "\n";
4706         pr "  ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
4707         pr "  ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
4708         pr "\n";
4709         pr "  r = command (&out, &err,\n";
4710         pr "           \"/sbin/lvm\", \"%ss\",\n" typ;
4711         pr "           \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
4712         pr "           \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
4713         pr "  if (r == -1) {\n";
4714         pr "    reply_with_error (\"%%s\", err);\n";
4715         pr "    free (out);\n";
4716         pr "    free (err);\n";
4717         pr "    free (ret);\n";
4718         pr "    return NULL;\n";
4719         pr "  }\n";
4720         pr "\n";
4721         pr "  free (err);\n";
4722         pr "\n";
4723         pr "  /* Tokenize each line of the output. */\n";
4724         pr "  p = out;\n";
4725         pr "  i = 0;\n";
4726         pr "  while (p) {\n";
4727         pr "    pend = strchr (p, '\\n');       /* Get the next line of output. */\n";
4728         pr "    if (pend) {\n";
4729         pr "      *pend = '\\0';\n";
4730         pr "      pend++;\n";
4731         pr "    }\n";
4732         pr "\n";
4733         pr "    while (*p && isspace (*p))      /* Skip any leading whitespace. */\n";
4734         pr "      p++;\n";
4735         pr "\n";
4736         pr "    if (!*p) {                      /* Empty line?  Skip it. */\n";
4737         pr "      p = pend;\n";
4738         pr "      continue;\n";
4739         pr "    }\n";
4740         pr "\n";
4741         pr "    /* Allocate some space to store this next entry. */\n";
4742         pr "    newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
4743         pr "                sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
4744         pr "    if (newp == NULL) {\n";
4745         pr "      reply_with_perror (\"realloc\");\n";
4746         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
4747         pr "      free (ret);\n";
4748         pr "      free (out);\n";
4749         pr "      return NULL;\n";
4750         pr "    }\n";
4751         pr "    ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
4752         pr "\n";
4753         pr "    /* Tokenize the next entry. */\n";
4754         pr "    r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
4755         pr "    if (r == -1) {\n";
4756         pr "      reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
4757         pr "      free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
4758         pr "      free (ret);\n";
4759         pr "      free (out);\n";
4760         pr "      return NULL;\n";
4761         pr "    }\n";
4762         pr "\n";
4763         pr "    ++i;\n";
4764         pr "    p = pend;\n";
4765         pr "  }\n";
4766         pr "\n";
4767         pr "  ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
4768         pr "\n";
4769         pr "  free (out);\n";
4770         pr "  return ret;\n";
4771         pr "}\n"
4772
4773   ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
4774
4775 (* Generate a list of function names, for debugging in the daemon.. *)
4776 and generate_daemon_names () =
4777   generate_header CStyle GPLv2;
4778
4779   pr "#include <config.h>\n";
4780   pr "\n";
4781   pr "#include \"daemon.h\"\n";
4782   pr "\n";
4783
4784   pr "/* This array is indexed by proc_nr.  See guestfs_protocol.x. */\n";
4785   pr "const char *function_names[] = {\n";
4786   List.iter (
4787     fun (name, _, proc_nr, _, _, _, _) -> pr "  [%d] = \"%s\",\n" proc_nr name
4788   ) daemon_functions;
4789   pr "};\n";
4790
4791 (* Generate the tests. *)
4792 and generate_tests () =
4793   generate_header CStyle GPLv2;
4794
4795   pr "\
4796 #include <stdio.h>
4797 #include <stdlib.h>
4798 #include <string.h>
4799 #include <unistd.h>
4800 #include <sys/types.h>
4801 #include <fcntl.h>
4802
4803 #include \"guestfs.h\"
4804
4805 static guestfs_h *g;
4806 static int suppress_error = 0;
4807
4808 static void print_error (guestfs_h *g, void *data, const char *msg)
4809 {
4810   if (!suppress_error)
4811     fprintf (stderr, \"%%s\\n\", msg);
4812 }
4813
4814 static void print_strings (char * const * const argv)
4815 {
4816   int argc;
4817
4818   for (argc = 0; argv[argc] != NULL; ++argc)
4819     printf (\"\\t%%s\\n\", argv[argc]);
4820 }
4821
4822 /*
4823 static void print_table (char * const * const argv)
4824 {
4825   int i;
4826
4827   for (i = 0; argv[i] != NULL; i += 2)
4828     printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
4829 }
4830 */
4831
4832 static void no_test_warnings (void)
4833 {
4834 ";
4835
4836   List.iter (
4837     function
4838     | name, _, _, _, [], _, _ ->
4839         pr "  fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
4840     | name, _, _, _, tests, _, _ -> ()
4841   ) all_functions;
4842
4843   pr "}\n";
4844   pr "\n";
4845
4846   (* Generate the actual tests.  Note that we generate the tests
4847    * in reverse order, deliberately, so that (in general) the
4848    * newest tests run first.  This makes it quicker and easier to
4849    * debug them.
4850    *)
4851   let test_names =
4852     List.map (
4853       fun (name, _, _, _, tests, _, _) ->
4854         mapi (generate_one_test name) tests
4855     ) (List.rev all_functions) in
4856   let test_names = List.concat test_names in
4857   let nr_tests = List.length test_names in
4858
4859   pr "\
4860 int main (int argc, char *argv[])
4861 {
4862   char c = 0;
4863   int failed = 0;
4864   const char *filename;
4865   int fd;
4866   int nr_tests, test_num = 0;
4867
4868   setbuf (stdout, NULL);
4869
4870   no_test_warnings ();
4871
4872   g = guestfs_create ();
4873   if (g == NULL) {
4874     printf (\"guestfs_create FAILED\\n\");
4875     exit (1);
4876   }
4877
4878   guestfs_set_error_handler (g, print_error, NULL);
4879
4880   guestfs_set_path (g, \"../appliance\");
4881
4882   filename = \"test1.img\";
4883   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4884   if (fd == -1) {
4885     perror (filename);
4886     exit (1);
4887   }
4888   if (lseek (fd, %d, SEEK_SET) == -1) {
4889     perror (\"lseek\");
4890     close (fd);
4891     unlink (filename);
4892     exit (1);
4893   }
4894   if (write (fd, &c, 1) == -1) {
4895     perror (\"write\");
4896     close (fd);
4897     unlink (filename);
4898     exit (1);
4899   }
4900   if (close (fd) == -1) {
4901     perror (filename);
4902     unlink (filename);
4903     exit (1);
4904   }
4905   if (guestfs_add_drive (g, filename) == -1) {
4906     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4907     exit (1);
4908   }
4909
4910   filename = \"test2.img\";
4911   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4912   if (fd == -1) {
4913     perror (filename);
4914     exit (1);
4915   }
4916   if (lseek (fd, %d, SEEK_SET) == -1) {
4917     perror (\"lseek\");
4918     close (fd);
4919     unlink (filename);
4920     exit (1);
4921   }
4922   if (write (fd, &c, 1) == -1) {
4923     perror (\"write\");
4924     close (fd);
4925     unlink (filename);
4926     exit (1);
4927   }
4928   if (close (fd) == -1) {
4929     perror (filename);
4930     unlink (filename);
4931     exit (1);
4932   }
4933   if (guestfs_add_drive (g, filename) == -1) {
4934     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4935     exit (1);
4936   }
4937
4938   filename = \"test3.img\";
4939   fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
4940   if (fd == -1) {
4941     perror (filename);
4942     exit (1);
4943   }
4944   if (lseek (fd, %d, SEEK_SET) == -1) {
4945     perror (\"lseek\");
4946     close (fd);
4947     unlink (filename);
4948     exit (1);
4949   }
4950   if (write (fd, &c, 1) == -1) {
4951     perror (\"write\");
4952     close (fd);
4953     unlink (filename);
4954     exit (1);
4955   }
4956   if (close (fd) == -1) {
4957     perror (filename);
4958     unlink (filename);
4959     exit (1);
4960   }
4961   if (guestfs_add_drive (g, filename) == -1) {
4962     printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
4963     exit (1);
4964   }
4965
4966   if (guestfs_add_drive_ro (g, \"../images/test.sqsh\") == -1) {
4967     printf (\"guestfs_add_drive_ro ../images/test.sqsh FAILED\\n\");
4968     exit (1);
4969   }
4970
4971   if (guestfs_launch (g) == -1) {
4972     printf (\"guestfs_launch FAILED\\n\");
4973     exit (1);
4974   }
4975
4976   /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
4977   alarm (600);
4978
4979   if (guestfs_wait_ready (g) == -1) {
4980     printf (\"guestfs_wait_ready FAILED\\n\");
4981     exit (1);
4982   }
4983
4984   /* Cancel previous alarm. */
4985   alarm (0);
4986
4987   nr_tests = %d;
4988
4989 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
4990
4991   iteri (
4992     fun i test_name ->
4993       pr "  test_num++;\n";
4994       pr "  printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
4995       pr "  if (%s () == -1) {\n" test_name;
4996       pr "    printf (\"%s FAILED\\n\");\n" test_name;
4997       pr "    failed++;\n";
4998       pr "  }\n";
4999   ) test_names;
5000   pr "\n";
5001
5002   pr "  guestfs_close (g);\n";
5003   pr "  unlink (\"test1.img\");\n";
5004   pr "  unlink (\"test2.img\");\n";
5005   pr "  unlink (\"test3.img\");\n";
5006   pr "\n";
5007
5008   pr "  if (failed > 0) {\n";
5009   pr "    printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
5010   pr "    exit (1);\n";
5011   pr "  }\n";
5012   pr "\n";
5013
5014   pr "  exit (0);\n";
5015   pr "}\n"
5016
5017 and generate_one_test name i (init, prereq, test) =
5018   let test_name = sprintf "test_%s_%d" name i in
5019
5020   pr "\
5021 static int %s_skip (void)
5022 {
5023   const char *str;
5024
5025   str = getenv (\"TEST_ONLY\");
5026   if (str)
5027     return strstr (str, \"%s\") == NULL;
5028   str = getenv (\"SKIP_%s\");
5029   if (str && strcmp (str, \"1\") == 0) return 1;
5030   str = getenv (\"SKIP_TEST_%s\");
5031   if (str && strcmp (str, \"1\") == 0) return 1;
5032   return 0;
5033 }
5034
5035 " test_name name (String.uppercase test_name) (String.uppercase name);
5036
5037   (match prereq with
5038    | Disabled | Always -> ()
5039    | If code | Unless code ->
5040        pr "static int %s_prereq (void)\n" test_name;
5041        pr "{\n";
5042        pr "  %s\n" code;
5043        pr "}\n";
5044        pr "\n";
5045   );
5046
5047   pr "\
5048 static int %s (void)
5049 {
5050   if (%s_skip ()) {
5051     printf (\"        %%s skipped (reason: environment variable set)\\n\", \"%s\");
5052     return 0;
5053   }
5054
5055 " test_name test_name test_name;
5056
5057   (match prereq with
5058    | Disabled ->
5059        pr "  printf (\"        %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
5060    | If _ ->
5061        pr "  if (! %s_prereq ()) {\n" test_name;
5062        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
5063        pr "    return 0;\n";
5064        pr "  }\n";
5065        pr "\n";
5066        generate_one_test_body name i test_name init test;
5067    | Unless _ ->
5068        pr "  if (%s_prereq ()) {\n" test_name;
5069        pr "    printf (\"        %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
5070        pr "    return 0;\n";
5071        pr "  }\n";
5072        pr "\n";
5073        generate_one_test_body name i test_name init test;
5074    | Always ->
5075        generate_one_test_body name i test_name init test
5076   );
5077
5078   pr "  return 0;\n";
5079   pr "}\n";
5080   pr "\n";
5081   test_name
5082
5083 and generate_one_test_body name i test_name init test =
5084   (match init with
5085    | InitNone (* XXX at some point, InitNone and InitEmpty became
5086                * folded together as the same thing.  Really we should
5087                * make InitNone do nothing at all, but the tests may
5088                * need to be checked to make sure this is OK.
5089                *)
5090    | InitEmpty ->
5091        pr "  /* InitNone|InitEmpty for %s */\n" test_name;
5092        List.iter (generate_test_command_call test_name)
5093          [["blockdev_setrw"; "/dev/sda"];
5094           ["umount_all"];
5095           ["lvm_remove_all"]]
5096    | InitBasicFS ->
5097        pr "  /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
5098        List.iter (generate_test_command_call test_name)
5099          [["blockdev_setrw"; "/dev/sda"];
5100           ["umount_all"];
5101           ["lvm_remove_all"];
5102           ["sfdiskM"; "/dev/sda"; ","];
5103           ["mkfs"; "ext2"; "/dev/sda1"];
5104           ["mount"; "/dev/sda1"; "/"]]
5105    | InitBasicFSonLVM ->
5106        pr "  /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
5107          test_name;
5108        List.iter (generate_test_command_call test_name)
5109          [["blockdev_setrw"; "/dev/sda"];
5110           ["umount_all"];
5111           ["lvm_remove_all"];
5112           ["sfdiskM"; "/dev/sda"; ","];
5113           ["pvcreate"; "/dev/sda1"];
5114           ["vgcreate"; "VG"; "/dev/sda1"];
5115           ["lvcreate"; "LV"; "VG"; "8"];
5116           ["mkfs"; "ext2"; "/dev/VG/LV"];
5117           ["mount"; "/dev/VG/LV"; "/"]]
5118    | InitSquashFS ->
5119        pr "  /* InitSquashFS for %s */\n" test_name;
5120        List.iter (generate_test_command_call test_name)
5121          [["blockdev_setrw"; "/dev/sda"];
5122           ["umount_all"];
5123           ["lvm_remove_all"];
5124           ["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"]]
5125   );
5126
5127   let get_seq_last = function
5128     | [] ->
5129         failwithf "%s: you cannot use [] (empty list) when expecting a command"
5130           test_name
5131     | seq ->
5132         let seq = List.rev seq in
5133         List.rev (List.tl seq), List.hd seq
5134   in
5135
5136   match test with
5137   | TestRun seq ->
5138       pr "  /* TestRun for %s (%d) */\n" name i;
5139       List.iter (generate_test_command_call test_name) seq
5140   | TestOutput (seq, expected) ->
5141       pr "  /* TestOutput for %s (%d) */\n" name i;
5142       pr "  const char *expected = \"%s\";\n" (c_quote expected);
5143       let seq, last = get_seq_last seq in
5144       let test () =
5145         pr "    if (strcmp (r, expected) != 0) {\n";
5146         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
5147         pr "      return -1;\n";
5148         pr "    }\n"
5149       in
5150       List.iter (generate_test_command_call test_name) seq;
5151       generate_test_command_call ~test test_name last
5152   | TestOutputList (seq, expected) ->
5153       pr "  /* TestOutputList for %s (%d) */\n" name i;
5154       let seq, last = get_seq_last seq in
5155       let test () =
5156         iteri (
5157           fun i str ->
5158             pr "    if (!r[%d]) {\n" i;
5159             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
5160             pr "      print_strings (r);\n";
5161             pr "      return -1;\n";
5162             pr "    }\n";
5163             pr "    {\n";
5164             pr "      const char *expected = \"%s\";\n" (c_quote str);
5165             pr "      if (strcmp (r[%d], expected) != 0) {\n" i;
5166             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
5167             pr "        return -1;\n";
5168             pr "      }\n";
5169             pr "    }\n"
5170         ) expected;
5171         pr "    if (r[%d] != NULL) {\n" (List.length expected);
5172         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
5173           test_name;
5174         pr "      print_strings (r);\n";
5175         pr "      return -1;\n";
5176         pr "    }\n"
5177       in
5178       List.iter (generate_test_command_call test_name) seq;
5179       generate_test_command_call ~test test_name last
5180   | TestOutputListOfDevices (seq, expected) ->
5181       pr "  /* TestOutputListOfDevices for %s (%d) */\n" name i;
5182       let seq, last = get_seq_last seq in
5183       let test () =
5184         iteri (
5185           fun i str ->
5186             pr "    if (!r[%d]) {\n" i;
5187             pr "      fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
5188             pr "      print_strings (r);\n";
5189             pr "      return -1;\n";
5190             pr "    }\n";
5191             pr "    {\n";
5192             pr "      const char *expected = \"%s\";\n" (c_quote str);
5193             pr "      r[%d][5] = 's';\n" i;
5194             pr "      if (strcmp (r[%d], expected) != 0) {\n" i;
5195             pr "        fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
5196             pr "        return -1;\n";
5197             pr "      }\n";
5198             pr "    }\n"
5199         ) expected;
5200         pr "    if (r[%d] != NULL) {\n" (List.length expected);
5201         pr "      fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
5202           test_name;
5203         pr "      print_strings (r);\n";
5204         pr "      return -1;\n";
5205         pr "    }\n"
5206       in
5207       List.iter (generate_test_command_call test_name) seq;
5208       generate_test_command_call ~test test_name last
5209   | TestOutputInt (seq, expected) ->
5210       pr "  /* TestOutputInt for %s (%d) */\n" name i;
5211       let seq, last = get_seq_last seq in
5212       let test () =
5213         pr "    if (r != %d) {\n" expected;
5214         pr "      fprintf (stderr, \"%s: expected %d but got %%d\\n\","
5215           test_name expected;
5216         pr "               (int) r);\n";
5217         pr "      return -1;\n";
5218         pr "    }\n"
5219       in
5220       List.iter (generate_test_command_call test_name) seq;
5221       generate_test_command_call ~test test_name last
5222   | TestOutputIntOp (seq, op, expected) ->
5223       pr "  /* TestOutputIntOp for %s (%d) */\n" name i;
5224       let seq, last = get_seq_last seq in
5225       let test () =
5226         pr "    if (! (r %s %d)) {\n" op expected;
5227         pr "      fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
5228           test_name op expected;
5229         pr "               (int) r);\n";
5230         pr "      return -1;\n";
5231         pr "    }\n"
5232       in
5233       List.iter (generate_test_command_call test_name) seq;
5234       generate_test_command_call ~test test_name last
5235   | TestOutputTrue seq ->
5236       pr "  /* TestOutputTrue for %s (%d) */\n" name i;
5237       let seq, last = get_seq_last seq in
5238       let test () =
5239         pr "    if (!r) {\n";
5240         pr "      fprintf (stderr, \"%s: expected true, got false\\n\");\n"
5241           test_name;
5242         pr "      return -1;\n";
5243         pr "    }\n"
5244       in
5245       List.iter (generate_test_command_call test_name) seq;
5246       generate_test_command_call ~test test_name last
5247   | TestOutputFalse seq ->
5248       pr "  /* TestOutputFalse for %s (%d) */\n" name i;
5249       let seq, last = get_seq_last seq in
5250       let test () =
5251         pr "    if (r) {\n";
5252         pr "      fprintf (stderr, \"%s: expected false, got true\\n\");\n"
5253           test_name;
5254         pr "      return -1;\n";
5255         pr "    }\n"
5256       in
5257       List.iter (generate_test_command_call test_name) seq;
5258       generate_test_command_call ~test test_name last
5259   | TestOutputLength (seq, expected) ->
5260       pr "  /* TestOutputLength for %s (%d) */\n" name i;
5261       let seq, last = get_seq_last seq in
5262       let test () =
5263         pr "    int j;\n";
5264         pr "    for (j = 0; j < %d; ++j)\n" expected;
5265         pr "      if (r[j] == NULL) {\n";
5266         pr "        fprintf (stderr, \"%s: short list returned\\n\");\n"
5267           test_name;
5268         pr "        print_strings (r);\n";
5269         pr "        return -1;\n";
5270         pr "      }\n";
5271         pr "    if (r[j] != NULL) {\n";
5272         pr "      fprintf (stderr, \"%s: long list returned\\n\");\n"
5273           test_name;
5274         pr "      print_strings (r);\n";
5275         pr "      return -1;\n";
5276         pr "    }\n"
5277       in
5278       List.iter (generate_test_command_call test_name) seq;
5279       generate_test_command_call ~test test_name last
5280   | TestOutputBuffer (seq, expected) ->
5281       pr "  /* TestOutputBuffer for %s (%d) */\n" name i;
5282       pr "  const char *expected = \"%s\";\n" (c_quote expected);
5283       let seq, last = get_seq_last seq in
5284       let len = String.length expected in
5285       let test () =
5286         pr "    if (size != %d) {\n" len;
5287         pr "      fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
5288         pr "      return -1;\n";
5289         pr "    }\n";
5290         pr "    if (strncmp (r, expected, size) != 0) {\n";
5291         pr "      fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
5292         pr "      return -1;\n";
5293         pr "    }\n"
5294       in
5295       List.iter (generate_test_command_call test_name) seq;
5296       generate_test_command_call ~test test_name last
5297   | TestOutputStruct (seq, checks) ->
5298       pr "  /* TestOutputStruct for %s (%d) */\n" name i;
5299       let seq, last = get_seq_last seq in
5300       let test () =
5301         List.iter (
5302           function
5303           | CompareWithInt (field, expected) ->
5304               pr "    if (r->%s != %d) {\n" field expected;
5305               pr "      fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
5306                 test_name field expected;
5307               pr "               (int) r->%s);\n" field;
5308               pr "      return -1;\n";
5309               pr "    }\n"
5310           | CompareWithIntOp (field, op, expected) ->
5311               pr "    if (!(r->%s %s %d)) {\n" field op expected;
5312               pr "      fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
5313                 test_name field op expected;
5314               pr "               (int) r->%s);\n" field;
5315               pr "      return -1;\n";
5316               pr "    }\n"
5317           | CompareWithString (field, expected) ->
5318               pr "    if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
5319               pr "      fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
5320                 test_name field expected;
5321               pr "               r->%s);\n" field;
5322               pr "      return -1;\n";
5323               pr "    }\n"
5324           | CompareFieldsIntEq (field1, field2) ->
5325               pr "    if (r->%s != r->%s) {\n" field1 field2;
5326               pr "      fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
5327                 test_name field1 field2;
5328               pr "               (int) r->%s, (int) r->%s);\n" field1 field2;
5329               pr "      return -1;\n";
5330               pr "    }\n"
5331           | CompareFieldsStrEq (field1, field2) ->
5332               pr "    if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
5333               pr "      fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
5334                 test_name field1 field2;
5335               pr "               r->%s, r->%s);\n" field1 field2;
5336               pr "      return -1;\n";
5337               pr "    }\n"
5338         ) checks
5339       in
5340       List.iter (generate_test_command_call test_name) seq;
5341       generate_test_command_call ~test test_name last
5342   | TestLastFail seq ->
5343       pr "  /* TestLastFail for %s (%d) */\n" name i;
5344       let seq, last = get_seq_last seq in
5345       List.iter (generate_test_command_call test_name) seq;
5346       generate_test_command_call test_name ~expect_error:true last
5347
5348 (* Generate the code to run a command, leaving the result in 'r'.
5349  * If you expect to get an error then you should set expect_error:true.
5350  *)
5351 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
5352   match cmd with
5353   | [] -> assert false
5354   | name :: args ->
5355       (* Look up the command to find out what args/ret it has. *)
5356       let style =
5357         try
5358           let _, style, _, _, _, _, _ =
5359             List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
5360           style
5361         with Not_found ->
5362           failwithf "%s: in test, command %s was not found" test_name name in
5363
5364       if List.length (snd style) <> List.length args then
5365         failwithf "%s: in test, wrong number of args given to %s"
5366           test_name name;
5367
5368       pr "  {\n";
5369
5370       List.iter (
5371         function
5372         | OptString n, "NULL" -> ()
5373         | String n, arg
5374         | OptString n, arg ->
5375             pr "    const char *%s = \"%s\";\n" n (c_quote arg);
5376         | Int _, _
5377         | Bool _, _
5378         | FileIn _, _ | FileOut _, _ -> ()
5379         | StringList n, arg ->
5380             let strs = string_split " " arg in
5381             iteri (
5382               fun i str ->
5383                 pr "    const char *%s_%d = \"%s\";\n" n i (c_quote str);
5384             ) strs;
5385             pr "    const char *%s[] = {\n" n;
5386             iteri (
5387               fun i _ -> pr "      %s_%d,\n" n i
5388             ) strs;
5389             pr "      NULL\n";
5390             pr "    };\n";
5391       ) (List.combine (snd style) args);
5392
5393       let error_code =
5394         match fst style with
5395         | RErr | RInt _ | RBool _ -> pr "    int r;\n"; "-1"
5396         | RInt64 _ -> pr "    int64_t r;\n"; "-1"
5397         | RConstString _ | RConstOptString _ ->
5398             pr "    const char *r;\n"; "NULL"
5399         | RString _ -> pr "    char *r;\n"; "NULL"
5400         | RStringList _ | RHashtable _ ->
5401             pr "    char **r;\n";
5402             pr "    int i;\n";
5403             "NULL"
5404         | RStruct (_, typ) ->
5405             pr "    struct guestfs_%s *r;\n" typ; "NULL"
5406         | RStructList (_, typ) ->
5407             pr "    struct guestfs_%s_list *r;\n" typ; "NULL"
5408         | RBufferOut _ ->
5409             pr "    char *r;\n";
5410             pr "    size_t size;\n";
5411             "NULL" in
5412
5413       pr "    suppress_error = %d;\n" (if expect_error then 1 else 0);
5414       pr "    r = guestfs_%s (g" name;
5415
5416       (* Generate the parameters. *)
5417       List.iter (
5418         function
5419         | OptString _, "NULL" -> pr ", NULL"
5420         | String n, _
5421         | OptString n, _ ->
5422             pr ", %s" n
5423         | FileIn _, arg | FileOut _, arg ->
5424             pr ", \"%s\"" (c_quote arg)
5425         | StringList n, _ ->
5426             pr ", %s" n
5427         | Int _, arg ->
5428             let i =
5429               try int_of_string arg
5430               with Failure "int_of_string" ->
5431                 failwithf "%s: expecting an int, but got '%s'" test_name arg in
5432             pr ", %d" i
5433         | Bool _, arg ->
5434             let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
5435       ) (List.combine (snd style) args);
5436
5437       (match fst style with
5438        | RBufferOut _ -> pr ", &size"
5439        | _ -> ()
5440       );
5441
5442       pr ");\n";
5443
5444       if not expect_error then
5445         pr "    if (r == %s)\n" error_code
5446       else
5447         pr "    if (r != %s)\n" error_code;
5448       pr "      return -1;\n";
5449
5450       (* Insert the test code. *)
5451       (match test with
5452        | None -> ()
5453        | Some f -> f ()
5454       );
5455
5456       (match fst style with
5457        | RErr | RInt _ | RInt64 _ | RBool _
5458        | RConstString _ | RConstOptString _ -> ()
5459        | RString _ | RBufferOut _ -> pr "    free (r);\n"
5460        | RStringList _ | RHashtable _ ->
5461            pr "    for (i = 0; r[i] != NULL; ++i)\n";
5462            pr "      free (r[i]);\n";
5463            pr "    free (r);\n"
5464        | RStruct (_, typ) ->
5465            pr "    guestfs_free_%s (r);\n" typ
5466        | RStructList (_, typ) ->
5467            pr "    guestfs_free_%s_list (r);\n" typ
5468       );
5469
5470       pr "  }\n"
5471
5472 and c_quote str =
5473   let str = replace_str str "\r" "\\r" in
5474   let str = replace_str str "\n" "\\n" in
5475   let str = replace_str str "\t" "\\t" in
5476   let str = replace_str str "\000" "\\0" in
5477   str
5478
5479 (* Generate a lot of different functions for guestfish. *)
5480 and generate_fish_cmds () =
5481   generate_header CStyle GPLv2;
5482
5483   let all_functions =
5484     List.filter (
5485       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5486     ) all_functions in
5487   let all_functions_sorted =
5488     List.filter (
5489       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5490     ) all_functions_sorted in
5491
5492   pr "#include <stdio.h>\n";
5493   pr "#include <stdlib.h>\n";
5494   pr "#include <string.h>\n";
5495   pr "#include <inttypes.h>\n";
5496   pr "#include <ctype.h>\n";
5497   pr "\n";
5498   pr "#include <guestfs.h>\n";
5499   pr "#include \"fish.h\"\n";
5500   pr "\n";
5501
5502   (* list_commands function, which implements guestfish -h *)
5503   pr "void list_commands (void)\n";
5504   pr "{\n";
5505   pr "  printf (\"    %%-16s     %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
5506   pr "  list_builtin_commands ();\n";
5507   List.iter (
5508     fun (name, _, _, flags, _, shortdesc, _) ->
5509       let name = replace_char name '_' '-' in
5510       pr "  printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
5511         name shortdesc
5512   ) all_functions_sorted;
5513   pr "  printf (\"    %%s\\n\",";
5514   pr "          _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
5515   pr "}\n";
5516   pr "\n";
5517
5518   (* display_command function, which implements guestfish -h cmd *)
5519   pr "void display_command (const char *cmd)\n";
5520   pr "{\n";
5521   List.iter (
5522     fun (name, style, _, flags, _, shortdesc, longdesc) ->
5523       let name2 = replace_char name '_' '-' in
5524       let alias =
5525         try find_map (function FishAlias n -> Some n | _ -> None) flags
5526         with Not_found -> name in
5527       let longdesc = replace_str longdesc "C<guestfs_" "C<" in
5528       let synopsis =
5529         match snd style with
5530         | [] -> name2
5531         | args ->
5532             sprintf "%s <%s>"
5533               name2 (String.concat "> <" (List.map name_of_argt args)) in
5534
5535       let warnings =
5536         if List.mem ProtocolLimitWarning flags then
5537           ("\n\n" ^ protocol_limit_warning)
5538         else "" in
5539
5540       (* For DangerWillRobinson commands, we should probably have
5541        * guestfish prompt before allowing you to use them (especially
5542        * in interactive mode). XXX
5543        *)
5544       let warnings =
5545         warnings ^
5546           if List.mem DangerWillRobinson flags then
5547             ("\n\n" ^ danger_will_robinson)
5548           else "" in
5549
5550       let warnings =
5551         warnings ^
5552           match deprecation_notice flags with
5553           | None -> ""
5554           | Some txt -> "\n\n" ^ txt in
5555
5556       let describe_alias =
5557         if name <> alias then
5558           sprintf "\n\nYou can use '%s' as an alias for this command." alias
5559         else "" in
5560
5561       pr "  if (";
5562       pr "strcasecmp (cmd, \"%s\") == 0" name;
5563       if name <> name2 then
5564         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
5565       if name <> alias then
5566         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
5567       pr ")\n";
5568       pr "    pod2text (\"%s\", _(\"%s\"), %S);\n"
5569         name2 shortdesc
5570         (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
5571       pr "  else\n"
5572   ) all_functions;
5573   pr "    display_builtin_command (cmd);\n";
5574   pr "}\n";
5575   pr "\n";
5576
5577   (* print_* functions *)
5578   List.iter (
5579     fun (typ, cols) ->
5580       let needs_i =
5581         List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
5582
5583       pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
5584       pr "{\n";
5585       if needs_i then (
5586         pr "  int i;\n";
5587         pr "\n"
5588       );
5589       List.iter (
5590         function
5591         | name, FString ->
5592             pr "  printf (\"%s: %%s\\n\", %s->%s);\n" name typ name
5593         | name, FUUID ->
5594             pr "  printf (\"%s: \");\n" name;
5595             pr "  for (i = 0; i < 32; ++i)\n";
5596             pr "    printf (\"%%c\", %s->%s[i]);\n" typ name;
5597             pr "  printf (\"\\n\");\n"
5598         | name, FBuffer ->
5599             pr "  printf (\"%s: \");\n" name;
5600             pr "  for (i = 0; i < %s->%s_len; ++i)\n" typ name;
5601             pr "    if (isprint (%s->%s[i]))\n" typ name;
5602             pr "      printf (\"%%c\", %s->%s[i]);\n" typ name;
5603             pr "    else\n";
5604             pr "      printf (\"\\\\x%%02x\", %s->%s[i]);\n" typ name;
5605             pr "  printf (\"\\n\");\n"
5606         | name, (FUInt64|FBytes) ->
5607             pr "  printf (\"%s: %%\" PRIu64 \"\\n\", %s->%s);\n" name typ name
5608         | name, FInt64 ->
5609             pr "  printf (\"%s: %%\" PRIi64 \"\\n\", %s->%s);\n" name typ name
5610         | name, FUInt32 ->
5611             pr "  printf (\"%s: %%\" PRIu32 \"\\n\", %s->%s);\n" name typ name
5612         | name, FInt32 ->
5613             pr "  printf (\"%s: %%\" PRIi32 \"\\n\", %s->%s);\n" name typ name
5614         | name, FChar ->
5615             pr "  printf (\"%s: %%c\\n\", %s->%s);\n" name typ name
5616         | name, FOptPercent ->
5617             pr "  if (%s->%s >= 0) printf (\"%s: %%g %%%%\\n\", %s->%s);\n"
5618               typ name name typ name;
5619             pr "  else printf (\"%s: \\n\");\n" name
5620       ) cols;
5621       pr "}\n";
5622       pr "\n";
5623       pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
5624         typ typ typ;
5625       pr "{\n";
5626       pr "  int i;\n";
5627       pr "\n";
5628       pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
5629       pr "    print_%s (&%ss->val[i]);\n" typ typ;
5630       pr "}\n";
5631       pr "\n";
5632   ) structs;
5633
5634   (* run_<action> actions *)
5635   List.iter (
5636     fun (name, style, _, flags, _, _, _) ->
5637       pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
5638       pr "{\n";
5639       (match fst style with
5640        | RErr
5641        | RInt _
5642        | RBool _ -> pr "  int r;\n"
5643        | RInt64 _ -> pr "  int64_t r;\n"
5644        | RConstString _ | RConstOptString _ -> pr "  const char *r;\n"
5645        | RString _ -> pr "  char *r;\n"
5646        | RStringList _ | RHashtable _ -> pr "  char **r;\n"
5647        | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ
5648        | RStructList (_, typ) -> pr "  struct guestfs_%s_list *r;\n" typ
5649        | RBufferOut _ ->
5650            pr "  char *r;\n";
5651            pr "  size_t size;\n";
5652       );
5653       List.iter (
5654         function
5655         | String n
5656         | OptString n
5657         | FileIn n
5658         | FileOut n -> pr "  const char *%s;\n" n
5659         | StringList n -> pr "  char **%s;\n" n
5660         | Bool n -> pr "  int %s;\n" n
5661         | Int n -> pr "  int %s;\n" n
5662       ) (snd style);
5663
5664       (* Check and convert parameters. *)
5665       let argc_expected = List.length (snd style) in
5666       pr "  if (argc != %d) {\n" argc_expected;
5667       pr "    fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
5668         argc_expected;
5669       pr "    fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
5670       pr "    return -1;\n";
5671       pr "  }\n";
5672       iteri (
5673         fun i ->
5674           function
5675           | String name -> pr "  %s = argv[%d];\n" name i
5676           | OptString name ->
5677               pr "  %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
5678                 name i i
5679           | FileIn name ->
5680               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
5681                 name i i
5682           | FileOut name ->
5683               pr "  %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
5684                 name i i
5685           | StringList name ->
5686               pr "  %s = parse_string_list (argv[%d]);\n" name i
5687           | Bool name ->
5688               pr "  %s = is_true (argv[%d]) ? 1 : 0;\n" name i
5689           | Int name ->
5690               pr "  %s = atoi (argv[%d]);\n" name i
5691       ) (snd style);
5692
5693       (* Call C API function. *)
5694       let fn =
5695         try find_map (function FishAction n -> Some n | _ -> None) flags
5696         with Not_found -> sprintf "guestfs_%s" name in
5697       pr "  r = %s " fn;
5698       generate_c_call_args ~handle:"g" style;
5699       pr ";\n";
5700
5701       (* Check return value for errors and display command results. *)
5702       (match fst style with
5703        | RErr -> pr "  return r;\n"
5704        | RInt _ ->
5705            pr "  if (r == -1) return -1;\n";
5706            pr "  printf (\"%%d\\n\", r);\n";
5707            pr "  return 0;\n"
5708        | RInt64 _ ->
5709            pr "  if (r == -1) return -1;\n";
5710            pr "  printf (\"%%\" PRIi64 \"\\n\", r);\n";
5711            pr "  return 0;\n"
5712        | RBool _ ->
5713            pr "  if (r == -1) return -1;\n";
5714            pr "  if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
5715            pr "  return 0;\n"
5716        | RConstString _ ->
5717            pr "  if (r == NULL) return -1;\n";
5718            pr "  printf (\"%%s\\n\", r);\n";
5719            pr "  return 0;\n"
5720        | RConstOptString _ ->
5721            pr "  printf (\"%%s\\n\", r ? : \"(null)\");\n";
5722            pr "  return 0;\n"
5723        | RString _ ->
5724            pr "  if (r == NULL) return -1;\n";
5725            pr "  printf (\"%%s\\n\", r);\n";
5726            pr "  free (r);\n";
5727            pr "  return 0;\n"
5728        | RStringList _ ->
5729            pr "  if (r == NULL) return -1;\n";
5730            pr "  print_strings (r);\n";
5731            pr "  free_strings (r);\n";
5732            pr "  return 0;\n"
5733        | RStruct (_, typ) ->
5734            pr "  if (r == NULL) return -1;\n";
5735            pr "  print_%s (r);\n" typ;
5736            pr "  guestfs_free_%s (r);\n" typ;
5737            pr "  return 0;\n"
5738        | RStructList (_, typ) ->
5739            pr "  if (r == NULL) return -1;\n";
5740            pr "  print_%s_list (r);\n" typ;
5741            pr "  guestfs_free_%s_list (r);\n" typ;
5742            pr "  return 0;\n"
5743        | RHashtable _ ->
5744            pr "  if (r == NULL) return -1;\n";
5745            pr "  print_table (r);\n";
5746            pr "  free_strings (r);\n";
5747            pr "  return 0;\n"
5748        | RBufferOut _ ->
5749            pr "  if (r == NULL) return -1;\n";
5750            pr "  fwrite (r, size, 1, stdout);\n";
5751            pr "  free (r);\n";
5752            pr "  return 0;\n"
5753       );
5754       pr "}\n";
5755       pr "\n"
5756   ) all_functions;
5757
5758   (* run_action function *)
5759   pr "int run_action (const char *cmd, int argc, char *argv[])\n";
5760   pr "{\n";
5761   List.iter (
5762     fun (name, _, _, flags, _, _, _) ->
5763       let name2 = replace_char name '_' '-' in
5764       let alias =
5765         try find_map (function FishAlias n -> Some n | _ -> None) flags
5766         with Not_found -> name in
5767       pr "  if (";
5768       pr "strcasecmp (cmd, \"%s\") == 0" name;
5769       if name <> name2 then
5770         pr " || strcasecmp (cmd, \"%s\") == 0" name2;
5771       if name <> alias then
5772         pr " || strcasecmp (cmd, \"%s\") == 0" alias;
5773       pr ")\n";
5774       pr "    return run_%s (cmd, argc, argv);\n" name;
5775       pr "  else\n";
5776   ) all_functions;
5777   pr "    {\n";
5778   pr "      fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
5779   pr "      return -1;\n";
5780   pr "    }\n";
5781   pr "  return 0;\n";
5782   pr "}\n";
5783   pr "\n"
5784
5785 (* Readline completion for guestfish. *)
5786 and generate_fish_completion () =
5787   generate_header CStyle GPLv2;
5788
5789   let all_functions =
5790     List.filter (
5791       fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5792     ) all_functions in
5793
5794   pr "\
5795 #include <config.h>
5796
5797 #include <stdio.h>
5798 #include <stdlib.h>
5799 #include <string.h>
5800
5801 #ifdef HAVE_LIBREADLINE
5802 #include <readline/readline.h>
5803 #endif
5804
5805 #include \"fish.h\"
5806
5807 #ifdef HAVE_LIBREADLINE
5808
5809 static const char *const commands[] = {
5810   BUILTIN_COMMANDS_FOR_COMPLETION,
5811 ";
5812
5813   (* Get the commands, including the aliases.  They don't need to be
5814    * sorted - the generator() function just does a dumb linear search.
5815    *)
5816   let commands =
5817     List.map (
5818       fun (name, _, _, flags, _, _, _) ->
5819         let name2 = replace_char name '_' '-' in
5820         let alias =
5821           try find_map (function FishAlias n -> Some n | _ -> None) flags
5822           with Not_found -> name in
5823
5824         if name <> alias then [name2; alias] else [name2]
5825     ) all_functions in
5826   let commands = List.flatten commands in
5827
5828   List.iter (pr "  \"%s\",\n") commands;
5829
5830   pr "  NULL
5831 };
5832
5833 static char *
5834 generator (const char *text, int state)
5835 {
5836   static int index, len;
5837   const char *name;
5838
5839   if (!state) {
5840     index = 0;
5841     len = strlen (text);
5842   }
5843
5844   rl_attempted_completion_over = 1;
5845
5846   while ((name = commands[index]) != NULL) {
5847     index++;
5848     if (strncasecmp (name, text, len) == 0)
5849       return strdup (name);
5850   }
5851
5852   return NULL;
5853 }
5854
5855 #endif /* HAVE_LIBREADLINE */
5856
5857 char **do_completion (const char *text, int start, int end)
5858 {
5859   char **matches = NULL;
5860
5861 #ifdef HAVE_LIBREADLINE
5862   rl_completion_append_character = ' ';
5863
5864   if (start == 0)
5865     matches = rl_completion_matches (text, generator);
5866   else if (complete_dest_paths)
5867     matches = rl_completion_matches (text, complete_dest_paths_generator);
5868 #endif
5869
5870   return matches;
5871 }
5872 ";
5873
5874 (* Generate the POD documentation for guestfish. *)
5875 and generate_fish_actions_pod () =
5876   let all_functions_sorted =
5877     List.filter (
5878       fun (_, _, _, flags, _, _, _) ->
5879         not (List.mem NotInFish flags || List.mem NotInDocs flags)
5880     ) all_functions_sorted in
5881
5882   let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
5883
5884   List.iter (
5885     fun (name, style, _, flags, _, _, longdesc) ->
5886       let longdesc =
5887         Str.global_substitute rex (
5888           fun s ->
5889             let sub =
5890               try Str.matched_group 1 s
5891               with Not_found ->
5892                 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
5893             "C<" ^ replace_char sub '_' '-' ^ ">"
5894         ) longdesc in
5895       let name = replace_char name '_' '-' in
5896       let alias =
5897         try find_map (function FishAlias n -> Some n | _ -> None) flags
5898         with Not_found -> name in
5899
5900       pr "=head2 %s" name;
5901       if name <> alias then
5902         pr " | %s" alias;
5903       pr "\n";
5904       pr "\n";
5905       pr " %s" name;
5906       List.iter (
5907         function
5908         | String n -> pr " %s" n
5909         | OptString n -> pr " %s" n
5910         | StringList n -> pr " '%s ...'" n
5911         | Bool _ -> pr " true|false"
5912         | Int n -> pr " %s" n
5913         | FileIn n | FileOut n -> pr " (%s|-)" n
5914       ) (snd style);
5915       pr "\n";
5916       pr "\n";
5917       pr "%s\n\n" longdesc;
5918
5919       if List.exists (function FileIn _ | FileOut _ -> true
5920                       | _ -> false) (snd style) then
5921         pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
5922
5923       if List.mem ProtocolLimitWarning flags then
5924         pr "%s\n\n" protocol_limit_warning;
5925
5926       if List.mem DangerWillRobinson flags then
5927         pr "%s\n\n" danger_will_robinson;
5928
5929       match deprecation_notice flags with
5930       | None -> ()
5931       | Some txt -> pr "%s\n\n" txt
5932   ) all_functions_sorted
5933
5934 (* Generate a C function prototype. *)
5935 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
5936     ?(single_line = false) ?(newline = false) ?(in_daemon = false)
5937     ?(prefix = "")
5938     ?handle name style =
5939   if extern then pr "extern ";
5940   if static then pr "static ";
5941   (match fst style with
5942    | RErr -> pr "int "
5943    | RInt _ -> pr "int "
5944    | RInt64 _ -> pr "int64_t "
5945    | RBool _ -> pr "int "
5946    | RConstString _ | RConstOptString _ -> pr "const char *"
5947    | RString _ | RBufferOut _ -> pr "char *"
5948    | RStringList _ | RHashtable _ -> pr "char **"
5949    | RStruct (_, typ) ->
5950        if not in_daemon then pr "struct guestfs_%s *" typ
5951        else pr "guestfs_int_%s *" typ
5952    | RStructList (_, typ) ->
5953        if not in_daemon then pr "struct guestfs_%s_list *" typ
5954        else pr "guestfs_int_%s_list *" typ
5955   );
5956   let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
5957   pr "%s%s (" prefix name;
5958   if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
5959     pr "void"
5960   else (
5961     let comma = ref false in
5962     (match handle with
5963      | None -> ()
5964      | Some handle -> pr "guestfs_h *%s" handle; comma := true
5965     );
5966     let next () =
5967       if !comma then (
5968         if single_line then pr ", " else pr ",\n\t\t"
5969       );
5970       comma := true
5971     in
5972     List.iter (
5973       function
5974       | String n
5975       | OptString n ->
5976           next ();
5977           if not in_daemon then pr "const char *%s" n
5978           else pr "char *%s" n
5979       | StringList n ->
5980           next ();
5981           if not in_daemon then pr "char * const* const %s" n
5982           else pr "char **%s" n
5983       | Bool n -> next (); pr "int %s" n
5984       | Int n -> next (); pr "int %s" n
5985       | FileIn n
5986       | FileOut n ->
5987           if not in_daemon then (next (); pr "const char *%s" n)
5988     ) (snd style);
5989     if is_RBufferOut then (next (); pr "size_t *size_r");
5990   );
5991   pr ")";
5992   if semicolon then pr ";";
5993   if newline then pr "\n"
5994
5995 (* Generate C call arguments, eg "(handle, foo, bar)" *)
5996 and generate_c_call_args ?handle ?(decl = false) style =
5997   pr "(";
5998   let comma = ref false in
5999   let next () =
6000     if !comma then pr ", ";
6001     comma := true
6002   in
6003   (match handle with
6004    | None -> ()
6005    | Some handle -> pr "%s" handle; comma := true
6006   );
6007   List.iter (
6008     fun arg ->
6009       next ();
6010       pr "%s" (name_of_argt arg)
6011   ) (snd style);
6012   (* For RBufferOut calls, add implicit &size parameter. *)
6013   if not decl then (
6014     match fst style with
6015     | RBufferOut _ ->
6016         next ();
6017         pr "&size"
6018     | _ -> ()
6019   );
6020   pr ")"
6021
6022 (* Generate the OCaml bindings interface. *)
6023 and generate_ocaml_mli () =
6024   generate_header OCamlStyle LGPLv2;
6025
6026   pr "\
6027 (** For API documentation you should refer to the C API
6028     in the guestfs(3) manual page.  The OCaml API uses almost
6029     exactly the same calls. *)
6030
6031 type t
6032 (** A [guestfs_h] handle. *)
6033
6034 exception Error of string
6035 (** This exception is raised when there is an error. *)
6036
6037 val create : unit -> t
6038
6039 val close : t -> unit
6040 (** Handles are closed by the garbage collector when they become
6041     unreferenced, but callers can also call this in order to
6042     provide predictable cleanup. *)
6043
6044 ";
6045   generate_ocaml_structure_decls ();
6046
6047   (* The actions. *)
6048   List.iter (
6049     fun (name, style, _, _, _, shortdesc, _) ->
6050       generate_ocaml_prototype name style;
6051       pr "(** %s *)\n" shortdesc;
6052       pr "\n"
6053   ) all_functions
6054
6055 (* Generate the OCaml bindings implementation. *)
6056 and generate_ocaml_ml () =
6057   generate_header OCamlStyle LGPLv2;
6058
6059   pr "\
6060 type t
6061 exception Error of string
6062 external create : unit -> t = \"ocaml_guestfs_create\"
6063 external close : t -> unit = \"ocaml_guestfs_close\"
6064
6065 let () =
6066   Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
6067
6068 ";
6069
6070   generate_ocaml_structure_decls ();
6071
6072   (* The actions. *)
6073   List.iter (
6074     fun (name, style, _, _, _, shortdesc, _) ->
6075       generate_ocaml_prototype ~is_external:true name style;
6076   ) all_functions
6077
6078 (* Generate the OCaml bindings C implementation. *)
6079 and generate_ocaml_c () =
6080   generate_header CStyle LGPLv2;
6081
6082   pr "\
6083 #include <stdio.h>
6084 #include <stdlib.h>
6085 #include <string.h>
6086
6087 #include <caml/config.h>
6088 #include <caml/alloc.h>
6089 #include <caml/callback.h>
6090 #include <caml/fail.h>
6091 #include <caml/memory.h>
6092 #include <caml/mlvalues.h>
6093 #include <caml/signals.h>
6094
6095 #include <guestfs.h>
6096
6097 #include \"guestfs_c.h\"
6098
6099 /* Copy a hashtable of string pairs into an assoc-list.  We return
6100  * the list in reverse order, but hashtables aren't supposed to be
6101  * ordered anyway.
6102  */
6103 static CAMLprim value
6104 copy_table (char * const * argv)
6105 {
6106   CAMLparam0 ();
6107   CAMLlocal5 (rv, pairv, kv, vv, cons);
6108   int i;
6109
6110   rv = Val_int (0);
6111   for (i = 0; argv[i] != NULL; i += 2) {
6112     kv = caml_copy_string (argv[i]);
6113     vv = caml_copy_string (argv[i+1]);
6114     pairv = caml_alloc (2, 0);
6115     Store_field (pairv, 0, kv);
6116     Store_field (pairv, 1, vv);
6117     cons = caml_alloc (2, 0);
6118     Store_field (cons, 1, rv);
6119     rv = cons;
6120     Store_field (cons, 0, pairv);
6121   }
6122
6123   CAMLreturn (rv);
6124 }
6125
6126 ";
6127
6128   (* Struct copy functions. *)
6129   List.iter (
6130     fun (typ, cols) ->
6131       let has_optpercent_col =
6132         List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
6133
6134       pr "static CAMLprim value\n";
6135       pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
6136       pr "{\n";
6137       pr "  CAMLparam0 ();\n";
6138       if has_optpercent_col then
6139         pr "  CAMLlocal3 (rv, v, v2);\n"
6140       else
6141         pr "  CAMLlocal2 (rv, v);\n";
6142       pr "\n";
6143       pr "  rv = caml_alloc (%d, 0);\n" (List.length cols);
6144       iteri (
6145         fun i col ->
6146           (match col with
6147            | name, FString ->
6148                pr "  v = caml_copy_string (%s->%s);\n" typ name
6149            | name, FBuffer ->
6150                pr "  v = caml_alloc_string (%s->%s_len);\n" typ name;
6151                pr "  memcpy (String_val (v), %s->%s, %s->%s_len);\n"
6152                  typ name typ name
6153            | name, FUUID ->
6154                pr "  v = caml_alloc_string (32);\n";
6155                pr "  memcpy (String_val (v), %s->%s, 32);\n" typ name
6156            | name, (FBytes|FInt64|FUInt64) ->
6157                pr "  v = caml_copy_int64 (%s->%s);\n" typ name
6158            | name, (FInt32|FUInt32) ->
6159                pr "  v = caml_copy_int32 (%s->%s);\n" typ name
6160            | name, FOptPercent ->
6161                pr "  if (%s->%s >= 0) { /* Some %s */\n" typ name name;
6162                pr "    v2 = caml_copy_double (%s->%s);\n" typ name;
6163                pr "    v = caml_alloc (1, 0);\n";
6164                pr "    Store_field (v, 0, v2);\n";
6165                pr "  } else /* None */\n";
6166                pr "    v = Val_int (0);\n";
6167            | name, FChar ->
6168                pr "  v = Val_int (%s->%s);\n" typ name
6169           );
6170           pr "  Store_field (rv, %d, v);\n" i
6171       ) cols;
6172       pr "  CAMLreturn (rv);\n";
6173       pr "}\n";
6174       pr "\n";
6175
6176       pr "static CAMLprim value\n";
6177       pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n"
6178         typ typ typ;
6179       pr "{\n";
6180       pr "  CAMLparam0 ();\n";
6181       pr "  CAMLlocal2 (rv, v);\n";
6182       pr "  int i;\n";
6183       pr "\n";
6184       pr "  if (%ss->len == 0)\n" typ;
6185       pr "    CAMLreturn (Atom (0));\n";
6186       pr "  else {\n";
6187       pr "    rv = caml_alloc (%ss->len, 0);\n" typ;
6188       pr "    for (i = 0; i < %ss->len; ++i) {\n" typ;
6189       pr "      v = copy_%s (&%ss->val[i]);\n" typ typ;
6190       pr "      caml_modify (&Field (rv, i), v);\n";
6191       pr "    }\n";
6192       pr "    CAMLreturn (rv);\n";
6193       pr "  }\n";
6194       pr "}\n";
6195       pr "\n";
6196   ) structs;
6197
6198   (* The wrappers. *)
6199   List.iter (
6200     fun (name, style, _, _, _, _, _) ->
6201       let params =
6202         "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
6203
6204       let needs_extra_vs =
6205         match fst style with RConstOptString _ -> true | _ -> false in
6206
6207       pr "CAMLprim value\n";
6208       pr "ocaml_guestfs_%s (value %s" name (List.hd params);
6209       List.iter (pr ", value %s") (List.tl params);
6210       pr ")\n";
6211       pr "{\n";
6212
6213       (match params with
6214        | [p1; p2; p3; p4; p5] ->
6215            pr "  CAMLparam5 (%s);\n" (String.concat ", " params)
6216        | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
6217            pr "  CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
6218            pr "  CAMLxparam%d (%s);\n"
6219              (List.length rest) (String.concat ", " rest)
6220        | ps ->
6221            pr "  CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
6222       );
6223       if not needs_extra_vs then
6224         pr "  CAMLlocal1 (rv);\n"
6225       else
6226         pr "  CAMLlocal3 (rv, v, v2);\n";
6227       pr "\n";
6228
6229       pr "  guestfs_h *g = Guestfs_val (gv);\n";
6230       pr "  if (g == NULL)\n";
6231       pr "    caml_failwith (\"%s: used handle after closing it\");\n" name;
6232       pr "\n";
6233
6234       List.iter (
6235         function
6236         | String n
6237         | FileIn n
6238         | FileOut n ->
6239             pr "  const char *%s = String_val (%sv);\n" n n
6240         | OptString n ->
6241             pr "  const char *%s =\n" n;
6242             pr "    %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
6243               n n
6244         | StringList n ->
6245             pr "  char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
6246         | Bool n ->
6247             pr "  int %s = Bool_val (%sv);\n" n n
6248         | Int n ->
6249             pr "  int %s = Int_val (%sv);\n" n n
6250       ) (snd style);
6251       let error_code =
6252         match fst style with
6253         | RErr -> pr "  int r;\n"; "-1"
6254         | RInt _ -> pr "  int r;\n"; "-1"
6255         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
6256         | RBool _ -> pr "  int r;\n"; "-1"
6257         | RConstString _ | RConstOptString _ ->
6258             pr "  const char *r;\n"; "NULL"
6259         | RString _ -> pr "  char *r;\n"; "NULL"
6260         | RStringList _ ->
6261             pr "  int i;\n";
6262             pr "  char **r;\n";
6263             "NULL"
6264         | RStruct (_, typ) ->
6265             pr "  struct guestfs_%s *r;\n" typ; "NULL"
6266         | RStructList (_, typ) ->
6267             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
6268         | RHashtable _ ->
6269             pr "  int i;\n";
6270             pr "  char **r;\n";
6271             "NULL"
6272         | RBufferOut _ ->
6273             pr "  char *r;\n";
6274             pr "  size_t size;\n";
6275             "NULL" in
6276       pr "\n";
6277
6278       pr "  caml_enter_blocking_section ();\n";
6279       pr "  r = guestfs_%s " name;
6280       generate_c_call_args ~handle:"g" style;
6281       pr ";\n";
6282       pr "  caml_leave_blocking_section ();\n";
6283
6284       List.iter (
6285         function
6286         | StringList n ->
6287             pr "  ocaml_guestfs_free_strings (%s);\n" n;
6288         | String _ | OptString _ | Bool _ | Int _ | FileIn _ | FileOut _ -> ()
6289       ) (snd style);
6290
6291       pr "  if (r == %s)\n" error_code;
6292       pr "    ocaml_guestfs_raise_error (g, \"%s\");\n" name;
6293       pr "\n";
6294
6295       (match fst style with
6296        | RErr -> pr "  rv = Val_unit;\n"
6297        | RInt _ -> pr "  rv = Val_int (r);\n"
6298        | RInt64 _ ->
6299            pr "  rv = caml_copy_int64 (r);\n"
6300        | RBool _ -> pr "  rv = Val_bool (r);\n"
6301        | RConstString _ ->
6302            pr "  rv = caml_copy_string (r);\n"
6303        | RConstOptString _ ->
6304            pr "  if (r) { /* Some string */\n";
6305            pr "    v = caml_alloc (1, 0);\n";
6306            pr "    v2 = caml_copy_string (r);\n";
6307            pr "    Store_field (v, 0, v2);\n";
6308            pr "  } else /* None */\n";
6309            pr "    v = Val_int (0);\n";
6310        | RString _ ->
6311            pr "  rv = caml_copy_string (r);\n";
6312            pr "  free (r);\n"
6313        | RStringList _ ->
6314            pr "  rv = caml_copy_string_array ((const char **) r);\n";
6315            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
6316            pr "  free (r);\n"
6317        | RStruct (_, typ) ->
6318            pr "  rv = copy_%s (r);\n" typ;
6319            pr "  guestfs_free_%s (r);\n" typ;
6320        | RStructList (_, typ) ->
6321            pr "  rv = copy_%s_list (r);\n" typ;
6322            pr "  guestfs_free_%s_list (r);\n" typ;
6323        | RHashtable _ ->
6324            pr "  rv = copy_table (r);\n";
6325            pr "  for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
6326            pr "  free (r);\n";
6327        | RBufferOut _ ->
6328            pr "  rv = caml_alloc_string (size);\n";
6329            pr "  memcpy (String_val (rv), r, size);\n";
6330       );
6331
6332       pr "  CAMLreturn (rv);\n";
6333       pr "}\n";
6334       pr "\n";
6335
6336       if List.length params > 5 then (
6337         pr "CAMLprim value\n";
6338         pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
6339         pr "{\n";
6340         pr "  return ocaml_guestfs_%s (argv[0]" name;
6341         iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
6342         pr ");\n";
6343         pr "}\n";
6344         pr "\n"
6345       )
6346   ) all_functions
6347
6348 and generate_ocaml_structure_decls () =
6349   List.iter (
6350     fun (typ, cols) ->
6351       pr "type %s = {\n" typ;
6352       List.iter (
6353         function
6354         | name, FString -> pr "  %s : string;\n" name
6355         | name, FBuffer -> pr "  %s : string;\n" name
6356         | name, FUUID -> pr "  %s : string;\n" name
6357         | name, (FBytes|FInt64|FUInt64) -> pr "  %s : int64;\n" name
6358         | name, (FInt32|FUInt32) -> pr "  %s : int32;\n" name
6359         | name, FChar -> pr "  %s : char;\n" name
6360         | name, FOptPercent -> pr "  %s : float option;\n" name
6361       ) cols;
6362       pr "}\n";
6363       pr "\n"
6364   ) structs
6365
6366 and generate_ocaml_prototype ?(is_external = false) name style =
6367   if is_external then pr "external " else pr "val ";
6368   pr "%s : t -> " name;
6369   List.iter (
6370     function
6371     | String _ | FileIn _ | FileOut _ -> pr "string -> "
6372     | OptString _ -> pr "string option -> "
6373     | StringList _ -> pr "string array -> "
6374     | Bool _ -> pr "bool -> "
6375     | Int _ -> pr "int -> "
6376   ) (snd style);
6377   (match fst style with
6378    | RErr -> pr "unit" (* all errors are turned into exceptions *)
6379    | RInt _ -> pr "int"
6380    | RInt64 _ -> pr "int64"
6381    | RBool _ -> pr "bool"
6382    | RConstString _ -> pr "string"
6383    | RConstOptString _ -> pr "string option"
6384    | RString _ | RBufferOut _ -> pr "string"
6385    | RStringList _ -> pr "string array"
6386    | RStruct (_, typ) -> pr "%s" typ
6387    | RStructList (_, typ) -> pr "%s array" typ
6388    | RHashtable _ -> pr "(string * string) list"
6389   );
6390   if is_external then (
6391     pr " = ";
6392     if List.length (snd style) + 1 > 5 then
6393       pr "\"ocaml_guestfs_%s_byte\" " name;
6394     pr "\"ocaml_guestfs_%s\"" name
6395   );
6396   pr "\n"
6397
6398 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
6399 and generate_perl_xs () =
6400   generate_header CStyle LGPLv2;
6401
6402   pr "\
6403 #include \"EXTERN.h\"
6404 #include \"perl.h\"
6405 #include \"XSUB.h\"
6406
6407 #include <guestfs.h>
6408
6409 #ifndef PRId64
6410 #define PRId64 \"lld\"
6411 #endif
6412
6413 static SV *
6414 my_newSVll(long long val) {
6415 #ifdef USE_64_BIT_ALL
6416   return newSViv(val);
6417 #else
6418   char buf[100];
6419   int len;
6420   len = snprintf(buf, 100, \"%%\" PRId64, val);
6421   return newSVpv(buf, len);
6422 #endif
6423 }
6424
6425 #ifndef PRIu64
6426 #define PRIu64 \"llu\"
6427 #endif
6428
6429 static SV *
6430 my_newSVull(unsigned long long val) {
6431 #ifdef USE_64_BIT_ALL
6432   return newSVuv(val);
6433 #else
6434   char buf[100];
6435   int len;
6436   len = snprintf(buf, 100, \"%%\" PRIu64, val);
6437   return newSVpv(buf, len);
6438 #endif
6439 }
6440
6441 /* http://www.perlmonks.org/?node_id=680842 */
6442 static char **
6443 XS_unpack_charPtrPtr (SV *arg) {
6444   char **ret;
6445   AV *av;
6446   I32 i;
6447
6448   if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
6449     croak (\"array reference expected\");
6450
6451   av = (AV *)SvRV (arg);
6452   ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
6453   if (!ret)
6454     croak (\"malloc failed\");
6455
6456   for (i = 0; i <= av_len (av); i++) {
6457     SV **elem = av_fetch (av, i, 0);
6458
6459     if (!elem || !*elem)
6460       croak (\"missing element in list\");
6461
6462     ret[i] = SvPV_nolen (*elem);
6463   }
6464
6465   ret[i] = NULL;
6466
6467   return ret;
6468 }
6469
6470 MODULE = Sys::Guestfs  PACKAGE = Sys::Guestfs
6471
6472 PROTOTYPES: ENABLE
6473
6474 guestfs_h *
6475 _create ()
6476    CODE:
6477       RETVAL = guestfs_create ();
6478       if (!RETVAL)
6479         croak (\"could not create guestfs handle\");
6480       guestfs_set_error_handler (RETVAL, NULL, NULL);
6481  OUTPUT:
6482       RETVAL
6483
6484 void
6485 DESTROY (g)
6486       guestfs_h *g;
6487  PPCODE:
6488       guestfs_close (g);
6489
6490 ";
6491
6492   List.iter (
6493     fun (name, style, _, _, _, _, _) ->
6494       (match fst style with
6495        | RErr -> pr "void\n"
6496        | RInt _ -> pr "SV *\n"
6497        | RInt64 _ -> pr "SV *\n"
6498        | RBool _ -> pr "SV *\n"
6499        | RConstString _ -> pr "SV *\n"
6500        | RConstOptString _ -> pr "SV *\n"
6501        | RString _ -> pr "SV *\n"
6502        | RBufferOut _ -> pr "SV *\n"
6503        | RStringList _
6504        | RStruct _ | RStructList _
6505        | RHashtable _ ->
6506            pr "void\n" (* all lists returned implictly on the stack *)
6507       );
6508       (* Call and arguments. *)
6509       pr "%s " name;
6510       generate_c_call_args ~handle:"g" ~decl:true style;
6511       pr "\n";
6512       pr "      guestfs_h *g;\n";
6513       iteri (
6514         fun i ->
6515           function
6516           | String n | FileIn n | FileOut n -> pr "      char *%s;\n" n
6517           | OptString n ->
6518               (* http://www.perlmonks.org/?node_id=554277
6519                * Note that the implicit handle argument means we have
6520                * to add 1 to the ST(x) operator.
6521                *)
6522               pr "      char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
6523           | StringList n -> pr "      char **%s;\n" n
6524           | Bool n -> pr "      int %s;\n" n
6525           | Int n -> pr "      int %s;\n" n
6526       ) (snd style);
6527
6528       let do_cleanups () =
6529         List.iter (
6530           function
6531           | String _ | OptString _ | Bool _ | Int _
6532           | FileIn _ | FileOut _ -> ()
6533           | StringList n -> pr "      free (%s);\n" n
6534         ) (snd style)
6535       in
6536
6537       (* Code. *)
6538       (match fst style with
6539        | RErr ->
6540            pr "PREINIT:\n";
6541            pr "      int r;\n";
6542            pr " PPCODE:\n";
6543            pr "      r = guestfs_%s " name;
6544            generate_c_call_args ~handle:"g" style;
6545            pr ";\n";
6546            do_cleanups ();
6547            pr "      if (r == -1)\n";
6548            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6549        | RInt n
6550        | RBool n ->
6551            pr "PREINIT:\n";
6552            pr "      int %s;\n" n;
6553            pr "   CODE:\n";
6554            pr "      %s = guestfs_%s " n name;
6555            generate_c_call_args ~handle:"g" style;
6556            pr ";\n";
6557            do_cleanups ();
6558            pr "      if (%s == -1)\n" n;
6559            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6560            pr "      RETVAL = newSViv (%s);\n" n;
6561            pr " OUTPUT:\n";
6562            pr "      RETVAL\n"
6563        | RInt64 n ->
6564            pr "PREINIT:\n";
6565            pr "      int64_t %s;\n" n;
6566            pr "   CODE:\n";
6567            pr "      %s = guestfs_%s " n name;
6568            generate_c_call_args ~handle:"g" style;
6569            pr ";\n";
6570            do_cleanups ();
6571            pr "      if (%s == -1)\n" n;
6572            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6573            pr "      RETVAL = my_newSVll (%s);\n" n;
6574            pr " OUTPUT:\n";
6575            pr "      RETVAL\n"
6576        | RConstString n ->
6577            pr "PREINIT:\n";
6578            pr "      const char *%s;\n" n;
6579            pr "   CODE:\n";
6580            pr "      %s = guestfs_%s " n name;
6581            generate_c_call_args ~handle:"g" style;
6582            pr ";\n";
6583            do_cleanups ();
6584            pr "      if (%s == NULL)\n" n;
6585            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6586            pr "      RETVAL = newSVpv (%s, 0);\n" n;
6587            pr " OUTPUT:\n";
6588            pr "      RETVAL\n"
6589        | RConstOptString n ->
6590            pr "PREINIT:\n";
6591            pr "      const char *%s;\n" n;
6592            pr "   CODE:\n";
6593            pr "      %s = guestfs_%s " n name;
6594            generate_c_call_args ~handle:"g" style;
6595            pr ";\n";
6596            do_cleanups ();
6597            pr "      if (%s == NULL)\n" n;
6598            pr "        RETVAL = &PL_sv_undef;\n";
6599            pr "      else\n";
6600            pr "        RETVAL = newSVpv (%s, 0);\n" n;
6601            pr " OUTPUT:\n";
6602            pr "      RETVAL\n"
6603        | RString n ->
6604            pr "PREINIT:\n";
6605            pr "      char *%s;\n" n;
6606            pr "   CODE:\n";
6607            pr "      %s = guestfs_%s " n name;
6608            generate_c_call_args ~handle:"g" style;
6609            pr ";\n";
6610            do_cleanups ();
6611            pr "      if (%s == NULL)\n" n;
6612            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6613            pr "      RETVAL = newSVpv (%s, 0);\n" n;
6614            pr "      free (%s);\n" n;
6615            pr " OUTPUT:\n";
6616            pr "      RETVAL\n"
6617        | RStringList n | RHashtable n ->
6618            pr "PREINIT:\n";
6619            pr "      char **%s;\n" n;
6620            pr "      int i, n;\n";
6621            pr " PPCODE:\n";
6622            pr "      %s = guestfs_%s " n name;
6623            generate_c_call_args ~handle:"g" style;
6624            pr ";\n";
6625            do_cleanups ();
6626            pr "      if (%s == NULL)\n" n;
6627            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6628            pr "      for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
6629            pr "      EXTEND (SP, n);\n";
6630            pr "      for (i = 0; i < n; ++i) {\n";
6631            pr "        PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
6632            pr "        free (%s[i]);\n" n;
6633            pr "      }\n";
6634            pr "      free (%s);\n" n;
6635        | RStruct (n, typ) ->
6636            let cols = cols_of_struct typ in
6637            generate_perl_struct_code typ cols name style n do_cleanups
6638        | RStructList (n, typ) ->
6639            let cols = cols_of_struct typ in
6640            generate_perl_struct_list_code typ cols name style n do_cleanups
6641        | RBufferOut n ->
6642            pr "PREINIT:\n";
6643            pr "      char *%s;\n" n;
6644            pr "      size_t size;\n";
6645            pr "   CODE:\n";
6646            pr "      %s = guestfs_%s " n name;
6647            generate_c_call_args ~handle:"g" style;
6648            pr ";\n";
6649            do_cleanups ();
6650            pr "      if (%s == NULL)\n" n;
6651            pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6652            pr "      RETVAL = newSVpv (%s, size);\n" n;
6653            pr "      free (%s);\n" n;
6654            pr " OUTPUT:\n";
6655            pr "      RETVAL\n"
6656       );
6657
6658       pr "\n"
6659   ) all_functions
6660
6661 and generate_perl_struct_list_code typ cols name style n do_cleanups =
6662   pr "PREINIT:\n";
6663   pr "      struct guestfs_%s_list *%s;\n" typ n;
6664   pr "      int i;\n";
6665   pr "      HV *hv;\n";
6666   pr " PPCODE:\n";
6667   pr "      %s = guestfs_%s " n name;
6668   generate_c_call_args ~handle:"g" style;
6669   pr ";\n";
6670   do_cleanups ();
6671   pr "      if (%s == NULL)\n" n;
6672   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6673   pr "      EXTEND (SP, %s->len);\n" n;
6674   pr "      for (i = 0; i < %s->len; ++i) {\n" n;
6675   pr "        hv = newHV ();\n";
6676   List.iter (
6677     function
6678     | name, FString ->
6679         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
6680           name (String.length name) n name
6681     | name, FUUID ->
6682         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
6683           name (String.length name) n name
6684     | name, FBuffer ->
6685         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
6686           name (String.length name) n name n name
6687     | name, (FBytes|FUInt64) ->
6688         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
6689           name (String.length name) n name
6690     | name, FInt64 ->
6691         pr "        (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
6692           name (String.length name) n name
6693     | name, (FInt32|FUInt32) ->
6694         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
6695           name (String.length name) n name
6696     | name, FChar ->
6697         pr "        (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
6698           name (String.length name) n name
6699     | name, FOptPercent ->
6700         pr "        (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
6701           name (String.length name) n name
6702   ) cols;
6703   pr "        PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
6704   pr "      }\n";
6705   pr "      guestfs_free_%s_list (%s);\n" typ n
6706
6707 and generate_perl_struct_code typ cols name style n do_cleanups =
6708   pr "PREINIT:\n";
6709   pr "      struct guestfs_%s *%s;\n" typ n;
6710   pr " PPCODE:\n";
6711   pr "      %s = guestfs_%s " n name;
6712   generate_c_call_args ~handle:"g" style;
6713   pr ";\n";
6714   do_cleanups ();
6715   pr "      if (%s == NULL)\n" n;
6716   pr "        croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6717   pr "      EXTEND (SP, 2 * %d);\n" (List.length cols);
6718   List.iter (
6719     fun ((name, _) as col) ->
6720       pr "      PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
6721
6722       match col with
6723       | name, FString ->
6724           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
6725             n name
6726       | name, FBuffer ->
6727           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, %s->%s_len)));\n"
6728             n name n name
6729       | name, FUUID ->
6730           pr "      PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
6731             n name
6732       | name, (FBytes|FUInt64) ->
6733           pr "      PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
6734             n name
6735       | name, FInt64 ->
6736           pr "      PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
6737             n name
6738       | name, (FInt32|FUInt32) ->
6739           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
6740             n name
6741       | name, FChar ->
6742           pr "      PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
6743             n name
6744       | name, FOptPercent ->
6745           pr "      PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
6746             n name
6747   ) cols;
6748   pr "      free (%s);\n" n
6749
6750 (* Generate Sys/Guestfs.pm. *)
6751 and generate_perl_pm () =
6752   generate_header HashStyle LGPLv2;
6753
6754   pr "\
6755 =pod
6756
6757 =head1 NAME
6758
6759 Sys::Guestfs - Perl bindings for libguestfs
6760
6761 =head1 SYNOPSIS
6762
6763  use Sys::Guestfs;
6764
6765  my $h = Sys::Guestfs->new ();
6766  $h->add_drive ('guest.img');
6767  $h->launch ();
6768  $h->wait_ready ();
6769  $h->mount ('/dev/sda1', '/');
6770  $h->touch ('/hello');
6771  $h->sync ();
6772
6773 =head1 DESCRIPTION
6774
6775 The C<Sys::Guestfs> module provides a Perl XS binding to the
6776 libguestfs API for examining and modifying virtual machine
6777 disk images.
6778
6779 Amongst the things this is good for: making batch configuration
6780 changes to guests, getting disk used/free statistics (see also:
6781 virt-df), migrating between virtualization systems (see also:
6782 virt-p2v), performing partial backups, performing partial guest
6783 clones, cloning guests and changing registry/UUID/hostname info, and
6784 much else besides.
6785
6786 Libguestfs uses Linux kernel and qemu code, and can access any type of
6787 guest filesystem that Linux and qemu can, including but not limited
6788 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
6789 schemes, qcow, qcow2, vmdk.
6790
6791 Libguestfs provides ways to enumerate guest storage (eg. partitions,
6792 LVs, what filesystem is in each LV, etc.).  It can also run commands
6793 in the context of the guest.  Also you can access filesystems over FTP.
6794
6795 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
6796 functions for using libguestfs from Perl, including integration
6797 with libvirt.
6798
6799 =head1 ERRORS
6800
6801 All errors turn into calls to C<croak> (see L<Carp(3)>).
6802
6803 =head1 METHODS
6804
6805 =over 4
6806
6807 =cut
6808
6809 package Sys::Guestfs;
6810
6811 use strict;
6812 use warnings;
6813
6814 require XSLoader;
6815 XSLoader::load ('Sys::Guestfs');
6816
6817 =item $h = Sys::Guestfs->new ();
6818
6819 Create a new guestfs handle.
6820
6821 =cut
6822
6823 sub new {
6824   my $proto = shift;
6825   my $class = ref ($proto) || $proto;
6826
6827   my $self = Sys::Guestfs::_create ();
6828   bless $self, $class;
6829   return $self;
6830 }
6831
6832 ";
6833
6834   (* Actions.  We only need to print documentation for these as
6835    * they are pulled in from the XS code automatically.
6836    *)
6837   List.iter (
6838     fun (name, style, _, flags, _, _, longdesc) ->
6839       if not (List.mem NotInDocs flags) then (
6840         let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
6841         pr "=item ";
6842         generate_perl_prototype name style;
6843         pr "\n\n";
6844         pr "%s\n\n" longdesc;
6845         if List.mem ProtocolLimitWarning flags then
6846           pr "%s\n\n" protocol_limit_warning;
6847         if List.mem DangerWillRobinson flags then
6848           pr "%s\n\n" danger_will_robinson;
6849         match deprecation_notice flags with
6850         | None -> ()
6851         | Some txt -> pr "%s\n\n" txt
6852       )
6853   ) all_functions_sorted;
6854
6855   (* End of file. *)
6856   pr "\
6857 =cut
6858
6859 1;
6860
6861 =back
6862
6863 =head1 COPYRIGHT
6864
6865 Copyright (C) 2009 Red Hat Inc.
6866
6867 =head1 LICENSE
6868
6869 Please see the file COPYING.LIB for the full license.
6870
6871 =head1 SEE ALSO
6872
6873 L<guestfs(3)>,
6874 L<guestfish(1)>,
6875 L<http://libguestfs.org>,
6876 L<Sys::Guestfs::Lib(3)>.
6877
6878 =cut
6879 "
6880
6881 and generate_perl_prototype name style =
6882   (match fst style with
6883    | RErr -> ()
6884    | RBool n
6885    | RInt n
6886    | RInt64 n
6887    | RConstString n
6888    | RConstOptString n
6889    | RString n
6890    | RBufferOut n -> pr "$%s = " n
6891    | RStruct (n,_)
6892    | RHashtable n -> pr "%%%s = " n
6893    | RStringList n
6894    | RStructList (n,_) -> pr "@%s = " n
6895   );
6896   pr "$h->%s (" name;
6897   let comma = ref false in
6898   List.iter (
6899     fun arg ->
6900       if !comma then pr ", ";
6901       comma := true;
6902       match arg with
6903       | String n | OptString n | Bool n | Int n | FileIn n | FileOut n ->
6904           pr "$%s" n
6905       | StringList n ->
6906           pr "\\@%s" n
6907   ) (snd style);
6908   pr ");"
6909
6910 (* Generate Python C module. *)
6911 and generate_python_c () =
6912   generate_header CStyle LGPLv2;
6913
6914   pr "\
6915 #include <stdio.h>
6916 #include <stdlib.h>
6917 #include <assert.h>
6918
6919 #include <Python.h>
6920
6921 #include \"guestfs.h\"
6922
6923 typedef struct {
6924   PyObject_HEAD
6925   guestfs_h *g;
6926 } Pyguestfs_Object;
6927
6928 static guestfs_h *
6929 get_handle (PyObject *obj)
6930 {
6931   assert (obj);
6932   assert (obj != Py_None);
6933   return ((Pyguestfs_Object *) obj)->g;
6934 }
6935
6936 static PyObject *
6937 put_handle (guestfs_h *g)
6938 {
6939   assert (g);
6940   return
6941     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
6942 }
6943
6944 /* This list should be freed (but not the strings) after use. */
6945 static const char **
6946 get_string_list (PyObject *obj)
6947 {
6948   int i, len;
6949   const char **r;
6950
6951   assert (obj);
6952
6953   if (!PyList_Check (obj)) {
6954     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
6955     return NULL;
6956   }
6957
6958   len = PyList_Size (obj);
6959   r = malloc (sizeof (char *) * (len+1));
6960   if (r == NULL) {
6961     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
6962     return NULL;
6963   }
6964
6965   for (i = 0; i < len; ++i)
6966     r[i] = PyString_AsString (PyList_GetItem (obj, i));
6967   r[len] = NULL;
6968
6969   return r;
6970 }
6971
6972 static PyObject *
6973 put_string_list (char * const * const argv)
6974 {
6975   PyObject *list;
6976   int argc, i;
6977
6978   for (argc = 0; argv[argc] != NULL; ++argc)
6979     ;
6980
6981   list = PyList_New (argc);
6982   for (i = 0; i < argc; ++i)
6983     PyList_SetItem (list, i, PyString_FromString (argv[i]));
6984
6985   return list;
6986 }
6987
6988 static PyObject *
6989 put_table (char * const * const argv)
6990 {
6991   PyObject *list, *item;
6992   int argc, i;
6993
6994   for (argc = 0; argv[argc] != NULL; ++argc)
6995     ;
6996
6997   list = PyList_New (argc >> 1);
6998   for (i = 0; i < argc; i += 2) {
6999     item = PyTuple_New (2);
7000     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
7001     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
7002     PyList_SetItem (list, i >> 1, item);
7003   }
7004
7005   return list;
7006 }
7007
7008 static void
7009 free_strings (char **argv)
7010 {
7011   int argc;
7012
7013   for (argc = 0; argv[argc] != NULL; ++argc)
7014     free (argv[argc]);
7015   free (argv);
7016 }
7017
7018 static PyObject *
7019 py_guestfs_create (PyObject *self, PyObject *args)
7020 {
7021   guestfs_h *g;
7022
7023   g = guestfs_create ();
7024   if (g == NULL) {
7025     PyErr_SetString (PyExc_RuntimeError,
7026                      \"guestfs.create: failed to allocate handle\");
7027     return NULL;
7028   }
7029   guestfs_set_error_handler (g, NULL, NULL);
7030   return put_handle (g);
7031 }
7032
7033 static PyObject *
7034 py_guestfs_close (PyObject *self, PyObject *args)
7035 {
7036   PyObject *py_g;
7037   guestfs_h *g;
7038
7039   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
7040     return NULL;
7041   g = get_handle (py_g);
7042
7043   guestfs_close (g);
7044
7045   Py_INCREF (Py_None);
7046   return Py_None;
7047 }
7048
7049 ";
7050
7051   (* Structures, turned into Python dictionaries. *)
7052   List.iter (
7053     fun (typ, cols) ->
7054       pr "static PyObject *\n";
7055       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
7056       pr "{\n";
7057       pr "  PyObject *dict;\n";
7058       pr "\n";
7059       pr "  dict = PyDict_New ();\n";
7060       List.iter (
7061         function
7062         | name, FString ->
7063             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7064             pr "                        PyString_FromString (%s->%s));\n"
7065               typ name
7066         | name, FBuffer ->
7067             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7068             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
7069               typ name typ name
7070         | name, FUUID ->
7071             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7072             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
7073               typ name
7074         | name, (FBytes|FUInt64) ->
7075             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7076             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
7077               typ name
7078         | name, FInt64 ->
7079             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7080             pr "                        PyLong_FromLongLong (%s->%s));\n"
7081               typ name
7082         | name, FUInt32 ->
7083             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7084             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
7085               typ name
7086         | name, FInt32 ->
7087             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7088             pr "                        PyLong_FromLong (%s->%s));\n"
7089               typ name
7090         | name, FOptPercent ->
7091             pr "  if (%s->%s >= 0)\n" typ name;
7092             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
7093             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
7094               typ name;
7095             pr "  else {\n";
7096             pr "    Py_INCREF (Py_None);\n";
7097             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);" name;
7098             pr "  }\n"
7099         | name, FChar ->
7100             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
7101             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
7102       ) cols;
7103       pr "  return dict;\n";
7104       pr "};\n";
7105       pr "\n";
7106
7107       pr "static PyObject *\n";
7108       pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
7109       pr "{\n";
7110       pr "  PyObject *list;\n";
7111       pr "  int i;\n";
7112       pr "\n";
7113       pr "  list = PyList_New (%ss->len);\n" typ;
7114       pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
7115       pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
7116       pr "  return list;\n";
7117       pr "};\n";
7118       pr "\n"
7119   ) structs;
7120
7121   (* Python wrapper functions. *)
7122   List.iter (
7123     fun (name, style, _, _, _, _, _) ->
7124       pr "static PyObject *\n";
7125       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
7126       pr "{\n";
7127
7128       pr "  PyObject *py_g;\n";
7129       pr "  guestfs_h *g;\n";
7130       pr "  PyObject *py_r;\n";
7131
7132       let error_code =
7133         match fst style with
7134         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
7135         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
7136         | RConstString _ | RConstOptString _ ->
7137             pr "  const char *r;\n"; "NULL"
7138         | RString _ -> pr "  char *r;\n"; "NULL"
7139         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
7140         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
7141         | RStructList (_, typ) ->
7142             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
7143         | RBufferOut _ ->
7144             pr "  char *r;\n";
7145             pr "  size_t size;\n";
7146             "NULL" in
7147
7148       List.iter (
7149         function
7150         | String n | FileIn n | FileOut n -> pr "  const char *%s;\n" n
7151         | OptString n -> pr "  const char *%s;\n" n
7152         | StringList n ->
7153             pr "  PyObject *py_%s;\n" n;
7154             pr "  const char **%s;\n" n
7155         | Bool n -> pr "  int %s;\n" n
7156         | Int n -> pr "  int %s;\n" n
7157       ) (snd style);
7158
7159       pr "\n";
7160
7161       (* Convert the parameters. *)
7162       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
7163       List.iter (
7164         function
7165         | String _ | FileIn _ | FileOut _ -> pr "s"
7166         | OptString _ -> pr "z"
7167         | StringList _ -> pr "O"
7168         | Bool _ -> pr "i" (* XXX Python has booleans? *)
7169         | Int _ -> pr "i"
7170       ) (snd style);
7171       pr ":guestfs_%s\",\n" name;
7172       pr "                         &py_g";
7173       List.iter (
7174         function
7175         | String n | FileIn n | FileOut n -> pr ", &%s" n
7176         | OptString n -> pr ", &%s" n
7177         | StringList n -> pr ", &py_%s" n
7178         | Bool n -> pr ", &%s" n
7179         | Int n -> pr ", &%s" n
7180       ) (snd style);
7181
7182       pr "))\n";
7183       pr "    return NULL;\n";
7184
7185       pr "  g = get_handle (py_g);\n";
7186       List.iter (
7187         function
7188         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
7189         | StringList n ->
7190             pr "  %s = get_string_list (py_%s);\n" n n;
7191             pr "  if (!%s) return NULL;\n" n
7192       ) (snd style);
7193
7194       pr "\n";
7195
7196       pr "  r = guestfs_%s " name;
7197       generate_c_call_args ~handle:"g" style;
7198       pr ";\n";
7199
7200       List.iter (
7201         function
7202         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
7203         | StringList n ->
7204             pr "  free (%s);\n" n
7205       ) (snd style);
7206
7207       pr "  if (r == %s) {\n" error_code;
7208       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
7209       pr "    return NULL;\n";
7210       pr "  }\n";
7211       pr "\n";
7212
7213       (match fst style with
7214        | RErr ->
7215            pr "  Py_INCREF (Py_None);\n";
7216            pr "  py_r = Py_None;\n"
7217        | RInt _
7218        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
7219        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
7220        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
7221        | RConstOptString _ ->
7222            pr "  if (r)\n";
7223            pr "    py_r = PyString_FromString (r);\n";
7224            pr "  else {\n";
7225            pr "    Py_INCREF (Py_None);\n";
7226            pr "    py_r = Py_None;\n";
7227            pr "  }\n"
7228        | RString _ ->
7229            pr "  py_r = PyString_FromString (r);\n";
7230            pr "  free (r);\n"
7231        | RStringList _ ->
7232            pr "  py_r = put_string_list (r);\n";
7233            pr "  free_strings (r);\n"
7234        | RStruct (_, typ) ->
7235            pr "  py_r = put_%s (r);\n" typ;
7236            pr "  guestfs_free_%s (r);\n" typ
7237        | RStructList (_, typ) ->
7238            pr "  py_r = put_%s_list (r);\n" typ;
7239            pr "  guestfs_free_%s_list (r);\n" typ
7240        | RHashtable n ->
7241            pr "  py_r = put_table (r);\n";
7242            pr "  free_strings (r);\n"
7243        | RBufferOut _ ->
7244            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
7245            pr "  free (r);\n"
7246       );
7247
7248       pr "  return py_r;\n";
7249       pr "}\n";
7250       pr "\n"
7251   ) all_functions;
7252
7253   (* Table of functions. *)
7254   pr "static PyMethodDef methods[] = {\n";
7255   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
7256   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
7257   List.iter (
7258     fun (name, _, _, _, _, _, _) ->
7259       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
7260         name name
7261   ) all_functions;
7262   pr "  { NULL, NULL, 0, NULL }\n";
7263   pr "};\n";
7264   pr "\n";
7265
7266   (* Init function. *)
7267   pr "\
7268 void
7269 initlibguestfsmod (void)
7270 {
7271   static int initialized = 0;
7272
7273   if (initialized) return;
7274   Py_InitModule ((char *) \"libguestfsmod\", methods);
7275   initialized = 1;
7276 }
7277 "
7278
7279 (* Generate Python module. *)
7280 and generate_python_py () =
7281   generate_header HashStyle LGPLv2;
7282
7283   pr "\
7284 u\"\"\"Python bindings for libguestfs
7285
7286 import guestfs
7287 g = guestfs.GuestFS ()
7288 g.add_drive (\"guest.img\")
7289 g.launch ()
7290 g.wait_ready ()
7291 parts = g.list_partitions ()
7292
7293 The guestfs module provides a Python binding to the libguestfs API
7294 for examining and modifying virtual machine disk images.
7295
7296 Amongst the things this is good for: making batch configuration
7297 changes to guests, getting disk used/free statistics (see also:
7298 virt-df), migrating between virtualization systems (see also:
7299 virt-p2v), performing partial backups, performing partial guest
7300 clones, cloning guests and changing registry/UUID/hostname info, and
7301 much else besides.
7302
7303 Libguestfs uses Linux kernel and qemu code, and can access any type of
7304 guest filesystem that Linux and qemu can, including but not limited
7305 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
7306 schemes, qcow, qcow2, vmdk.
7307
7308 Libguestfs provides ways to enumerate guest storage (eg. partitions,
7309 LVs, what filesystem is in each LV, etc.).  It can also run commands
7310 in the context of the guest.  Also you can access filesystems over FTP.
7311
7312 Errors which happen while using the API are turned into Python
7313 RuntimeError exceptions.
7314
7315 To create a guestfs handle you usually have to perform the following
7316 sequence of calls:
7317
7318 # Create the handle, call add_drive at least once, and possibly
7319 # several times if the guest has multiple block devices:
7320 g = guestfs.GuestFS ()
7321 g.add_drive (\"guest.img\")
7322
7323 # Launch the qemu subprocess and wait for it to become ready:
7324 g.launch ()
7325 g.wait_ready ()
7326
7327 # Now you can issue commands, for example:
7328 logvols = g.lvs ()
7329
7330 \"\"\"
7331
7332 import libguestfsmod
7333
7334 class GuestFS:
7335     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
7336
7337     def __init__ (self):
7338         \"\"\"Create a new libguestfs handle.\"\"\"
7339         self._o = libguestfsmod.create ()
7340
7341     def __del__ (self):
7342         libguestfsmod.close (self._o)
7343
7344 ";
7345
7346   List.iter (
7347     fun (name, style, _, flags, _, _, longdesc) ->
7348       pr "    def %s " name;
7349       generate_py_call_args ~handle:"self" (snd style);
7350       pr ":\n";
7351
7352       if not (List.mem NotInDocs flags) then (
7353         let doc = replace_str longdesc "C<guestfs_" "C<g." in
7354         let doc =
7355           match fst style with
7356           | RErr | RInt _ | RInt64 _ | RBool _
7357           | RConstOptString _ | RConstString _
7358           | RString _ | RBufferOut _ -> doc
7359           | RStringList _ ->
7360               doc ^ "\n\nThis function returns a list of strings."
7361           | RStruct (_, typ) ->
7362               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
7363           | RStructList (_, typ) ->
7364               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
7365           | RHashtable _ ->
7366               doc ^ "\n\nThis function returns a dictionary." in
7367         let doc =
7368           if List.mem ProtocolLimitWarning flags then
7369             doc ^ "\n\n" ^ protocol_limit_warning
7370           else doc in
7371         let doc =
7372           if List.mem DangerWillRobinson flags then
7373             doc ^ "\n\n" ^ danger_will_robinson
7374           else doc in
7375         let doc =
7376           match deprecation_notice flags with
7377           | None -> doc
7378           | Some txt -> doc ^ "\n\n" ^ txt in
7379         let doc = pod2text ~width:60 name doc in
7380         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
7381         let doc = String.concat "\n        " doc in
7382         pr "        u\"\"\"%s\"\"\"\n" doc;
7383       );
7384       pr "        return libguestfsmod.%s " name;
7385       generate_py_call_args ~handle:"self._o" (snd style);
7386       pr "\n";
7387       pr "\n";
7388   ) all_functions
7389
7390 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
7391 and generate_py_call_args ~handle args =
7392   pr "(%s" handle;
7393   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
7394   pr ")"
7395
7396 (* Useful if you need the longdesc POD text as plain text.  Returns a
7397  * list of lines.
7398  *
7399  * Because this is very slow (the slowest part of autogeneration),
7400  * we memoize the results.
7401  *)
7402 and pod2text ~width name longdesc =
7403   let key = width, name, longdesc in
7404   try Hashtbl.find pod2text_memo key
7405   with Not_found ->
7406     let filename, chan = Filename.open_temp_file "gen" ".tmp" in
7407     fprintf chan "=head1 %s\n\n%s\n" name longdesc;
7408     close_out chan;
7409     let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
7410     let chan = Unix.open_process_in cmd in
7411     let lines = ref [] in
7412     let rec loop i =
7413       let line = input_line chan in
7414       if i = 1 then             (* discard the first line of output *)
7415         loop (i+1)
7416       else (
7417         let line = triml line in
7418         lines := line :: !lines;
7419         loop (i+1)
7420       ) in
7421     let lines = try loop 1 with End_of_file -> List.rev !lines in
7422     Unix.unlink filename;
7423     (match Unix.close_process_in chan with
7424      | Unix.WEXITED 0 -> ()
7425      | Unix.WEXITED i ->
7426          failwithf "pod2text: process exited with non-zero status (%d)" i
7427      | Unix.WSIGNALED i | Unix.WSTOPPED i ->
7428          failwithf "pod2text: process signalled or stopped by signal %d" i
7429     );
7430     Hashtbl.add pod2text_memo key lines;
7431     let chan = open_out pod2text_memo_filename in
7432     output_value chan pod2text_memo;
7433     close_out chan;
7434     lines
7435
7436 (* Generate ruby bindings. *)
7437 and generate_ruby_c () =
7438   generate_header CStyle LGPLv2;
7439
7440   pr "\
7441 #include <stdio.h>
7442 #include <stdlib.h>
7443
7444 #include <ruby.h>
7445
7446 #include \"guestfs.h\"
7447
7448 #include \"extconf.h\"
7449
7450 /* For Ruby < 1.9 */
7451 #ifndef RARRAY_LEN
7452 #define RARRAY_LEN(r) (RARRAY((r))->len)
7453 #endif
7454
7455 static VALUE m_guestfs;                 /* guestfs module */
7456 static VALUE c_guestfs;                 /* guestfs_h handle */
7457 static VALUE e_Error;                   /* used for all errors */
7458
7459 static void ruby_guestfs_free (void *p)
7460 {
7461   if (!p) return;
7462   guestfs_close ((guestfs_h *) p);
7463 }
7464
7465 static VALUE ruby_guestfs_create (VALUE m)
7466 {
7467   guestfs_h *g;
7468
7469   g = guestfs_create ();
7470   if (!g)
7471     rb_raise (e_Error, \"failed to create guestfs handle\");
7472
7473   /* Don't print error messages to stderr by default. */
7474   guestfs_set_error_handler (g, NULL, NULL);
7475
7476   /* Wrap it, and make sure the close function is called when the
7477    * handle goes away.
7478    */
7479   return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
7480 }
7481
7482 static VALUE ruby_guestfs_close (VALUE gv)
7483 {
7484   guestfs_h *g;
7485   Data_Get_Struct (gv, guestfs_h, g);
7486
7487   ruby_guestfs_free (g);
7488   DATA_PTR (gv) = NULL;
7489
7490   return Qnil;
7491 }
7492
7493 ";
7494
7495   List.iter (
7496     fun (name, style, _, _, _, _, _) ->
7497       pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
7498       List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
7499       pr ")\n";
7500       pr "{\n";
7501       pr "  guestfs_h *g;\n";
7502       pr "  Data_Get_Struct (gv, guestfs_h, g);\n";
7503       pr "  if (!g)\n";
7504       pr "    rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
7505         name;
7506       pr "\n";
7507
7508       List.iter (
7509         function
7510         | String n | FileIn n | FileOut n ->
7511             pr "  Check_Type (%sv, T_STRING);\n" n;
7512             pr "  const char *%s = StringValueCStr (%sv);\n" n n;
7513             pr "  if (!%s)\n" n;
7514             pr "    rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
7515             pr "              \"%s\", \"%s\");\n" n name
7516         | OptString n ->
7517             pr "  const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
7518         | StringList n ->
7519             pr "  char **%s;\n" n;
7520             pr "  Check_Type (%sv, T_ARRAY);\n" n;
7521             pr "  {\n";
7522             pr "    int i, len;\n";
7523             pr "    len = RARRAY_LEN (%sv);\n" n;
7524             pr "    %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
7525               n;
7526             pr "    for (i = 0; i < len; ++i) {\n";
7527             pr "      VALUE v = rb_ary_entry (%sv, i);\n" n;
7528             pr "      %s[i] = StringValueCStr (v);\n" n;
7529             pr "    }\n";
7530             pr "    %s[len] = NULL;\n" n;
7531             pr "  }\n";
7532         | Bool n ->
7533             pr "  int %s = RTEST (%sv);\n" n n
7534         | Int n ->
7535             pr "  int %s = NUM2INT (%sv);\n" n n
7536       ) (snd style);
7537       pr "\n";
7538
7539       let error_code =
7540         match fst style with
7541         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
7542         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
7543         | RConstString _ | RConstOptString _ ->
7544             pr "  const char *r;\n"; "NULL"
7545         | RString _ -> pr "  char *r;\n"; "NULL"
7546         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
7547         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
7548         | RStructList (_, typ) ->
7549             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
7550         | RBufferOut _ ->
7551             pr "  char *r;\n";
7552             pr "  size_t size;\n";
7553             "NULL" in
7554       pr "\n";
7555
7556       pr "  r = guestfs_%s " name;
7557       generate_c_call_args ~handle:"g" style;
7558       pr ";\n";
7559
7560       List.iter (
7561         function
7562         | String _ | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
7563         | StringList n ->
7564             pr "  free (%s);\n" n
7565       ) (snd style);
7566
7567       pr "  if (r == %s)\n" error_code;
7568       pr "    rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
7569       pr "\n";
7570
7571       (match fst style with
7572        | RErr ->
7573            pr "  return Qnil;\n"
7574        | RInt _ | RBool _ ->
7575            pr "  return INT2NUM (r);\n"
7576        | RInt64 _ ->
7577            pr "  return ULL2NUM (r);\n"
7578        | RConstString _ ->
7579            pr "  return rb_str_new2 (r);\n";
7580        | RConstOptString _ ->
7581            pr "  if (r)\n";
7582            pr "    return rb_str_new2 (r);\n";
7583            pr "  else\n";
7584            pr "    return Qnil;\n";
7585        | RString _ ->
7586            pr "  VALUE rv = rb_str_new2 (r);\n";
7587            pr "  free (r);\n";
7588            pr "  return rv;\n";
7589        | RStringList _ ->
7590            pr "  int i, len = 0;\n";
7591            pr "  for (i = 0; r[i] != NULL; ++i) len++;\n";
7592            pr "  VALUE rv = rb_ary_new2 (len);\n";
7593            pr "  for (i = 0; r[i] != NULL; ++i) {\n";
7594            pr "    rb_ary_push (rv, rb_str_new2 (r[i]));\n";
7595            pr "    free (r[i]);\n";
7596            pr "  }\n";
7597            pr "  free (r);\n";
7598            pr "  return rv;\n"
7599        | RStruct (_, typ) ->
7600            let cols = cols_of_struct typ in
7601            generate_ruby_struct_code typ cols
7602        | RStructList (_, typ) ->
7603            let cols = cols_of_struct typ in
7604            generate_ruby_struct_list_code typ cols
7605        | RHashtable _ ->
7606            pr "  VALUE rv = rb_hash_new ();\n";
7607            pr "  int i;\n";
7608            pr "  for (i = 0; r[i] != NULL; i+=2) {\n";
7609            pr "    rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
7610            pr "    free (r[i]);\n";
7611            pr "    free (r[i+1]);\n";
7612            pr "  }\n";
7613            pr "  free (r);\n";
7614            pr "  return rv;\n"
7615        | RBufferOut _ ->
7616            pr "  VALUE rv = rb_str_new (r, size);\n";
7617            pr "  free (r);\n";
7618            pr "  return rv;\n";
7619       );
7620
7621       pr "}\n";
7622       pr "\n"
7623   ) all_functions;
7624
7625   pr "\
7626 /* Initialize the module. */
7627 void Init__guestfs ()
7628 {
7629   m_guestfs = rb_define_module (\"Guestfs\");
7630   c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
7631   e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
7632
7633   rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
7634   rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
7635
7636 ";
7637   (* Define the rest of the methods. *)
7638   List.iter (
7639     fun (name, style, _, _, _, _, _) ->
7640       pr "  rb_define_method (c_guestfs, \"%s\",\n" name;
7641       pr "        ruby_guestfs_%s, %d);\n" name (List.length (snd style))
7642   ) all_functions;
7643
7644   pr "}\n"
7645
7646 (* Ruby code to return a struct. *)
7647 and generate_ruby_struct_code typ cols =
7648   pr "  VALUE rv = rb_hash_new ();\n";
7649   List.iter (
7650     function
7651     | name, FString ->
7652         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
7653     | name, FBuffer ->
7654         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
7655     | name, FUUID ->
7656         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
7657     | name, (FBytes|FUInt64) ->
7658         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
7659     | name, FInt64 ->
7660         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
7661     | name, FUInt32 ->
7662         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
7663     | name, FInt32 ->
7664         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
7665     | name, FOptPercent ->
7666         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
7667     | name, FChar -> (* XXX wrong? *)
7668         pr "  rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
7669   ) cols;
7670   pr "  guestfs_free_%s (r);\n" typ;
7671   pr "  return rv;\n"
7672
7673 (* Ruby code to return a struct list. *)
7674 and generate_ruby_struct_list_code typ cols =
7675   pr "  VALUE rv = rb_ary_new2 (r->len);\n";
7676   pr "  int i;\n";
7677   pr "  for (i = 0; i < r->len; ++i) {\n";
7678   pr "    VALUE hv = rb_hash_new ();\n";
7679   List.iter (
7680     function
7681     | name, FString ->
7682         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
7683     | name, FBuffer ->
7684         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
7685     | name, FUUID ->
7686         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
7687     | name, (FBytes|FUInt64) ->
7688         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
7689     | name, FInt64 ->
7690         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
7691     | name, FUInt32 ->
7692         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
7693     | name, FInt32 ->
7694         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
7695     | name, FOptPercent ->
7696         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
7697     | name, FChar -> (* XXX wrong? *)
7698         pr "    rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
7699   ) cols;
7700   pr "    rb_ary_push (rv, hv);\n";
7701   pr "  }\n";
7702   pr "  guestfs_free_%s_list (r);\n" typ;
7703   pr "  return rv;\n"
7704
7705 (* Generate Java bindings GuestFS.java file. *)
7706 and generate_java_java () =
7707   generate_header CStyle LGPLv2;
7708
7709   pr "\
7710 package com.redhat.et.libguestfs;
7711
7712 import java.util.HashMap;
7713 import com.redhat.et.libguestfs.LibGuestFSException;
7714 import com.redhat.et.libguestfs.PV;
7715 import com.redhat.et.libguestfs.VG;
7716 import com.redhat.et.libguestfs.LV;
7717 import com.redhat.et.libguestfs.Stat;
7718 import com.redhat.et.libguestfs.StatVFS;
7719 import com.redhat.et.libguestfs.IntBool;
7720 import com.redhat.et.libguestfs.Dirent;
7721
7722 /**
7723  * The GuestFS object is a libguestfs handle.
7724  *
7725  * @author rjones
7726  */
7727 public class GuestFS {
7728   // Load the native code.
7729   static {
7730     System.loadLibrary (\"guestfs_jni\");
7731   }
7732
7733   /**
7734    * The native guestfs_h pointer.
7735    */
7736   long g;
7737
7738   /**
7739    * Create a libguestfs handle.
7740    *
7741    * @throws LibGuestFSException
7742    */
7743   public GuestFS () throws LibGuestFSException
7744   {
7745     g = _create ();
7746   }
7747   private native long _create () throws LibGuestFSException;
7748
7749   /**
7750    * Close a libguestfs handle.
7751    *
7752    * You can also leave handles to be collected by the garbage
7753    * collector, but this method ensures that the resources used
7754    * by the handle are freed up immediately.  If you call any
7755    * other methods after closing the handle, you will get an
7756    * exception.
7757    *
7758    * @throws LibGuestFSException
7759    */
7760   public void close () throws LibGuestFSException
7761   {
7762     if (g != 0)
7763       _close (g);
7764     g = 0;
7765   }
7766   private native void _close (long g) throws LibGuestFSException;
7767
7768   public void finalize () throws LibGuestFSException
7769   {
7770     close ();
7771   }
7772
7773 ";
7774
7775   List.iter (
7776     fun (name, style, _, flags, _, shortdesc, longdesc) ->
7777       if not (List.mem NotInDocs flags); then (
7778         let doc = replace_str longdesc "C<guestfs_" "C<g." in
7779         let doc =
7780           if List.mem ProtocolLimitWarning flags then
7781             doc ^ "\n\n" ^ protocol_limit_warning
7782           else doc in
7783         let doc =
7784           if List.mem DangerWillRobinson flags then
7785             doc ^ "\n\n" ^ danger_will_robinson
7786           else doc in
7787         let doc =
7788           match deprecation_notice flags with
7789           | None -> doc
7790           | Some txt -> doc ^ "\n\n" ^ txt in
7791         let doc = pod2text ~width:60 name doc in
7792         let doc = List.map (            (* RHBZ#501883 *)
7793           function
7794           | "" -> "<p>"
7795           | nonempty -> nonempty
7796         ) doc in
7797         let doc = String.concat "\n   * " doc in
7798
7799         pr "  /**\n";
7800         pr "   * %s\n" shortdesc;
7801         pr "   * <p>\n";
7802         pr "   * %s\n" doc;
7803         pr "   * @throws LibGuestFSException\n";
7804         pr "   */\n";
7805         pr "  ";
7806       );
7807       generate_java_prototype ~public:true ~semicolon:false name style;
7808       pr "\n";
7809       pr "  {\n";
7810       pr "    if (g == 0)\n";
7811       pr "      throw new LibGuestFSException (\"%s: handle is closed\");\n"
7812         name;
7813       pr "    ";
7814       if fst style <> RErr then pr "return ";
7815       pr "_%s " name;
7816       generate_java_call_args ~handle:"g" (snd style);
7817       pr ";\n";
7818       pr "  }\n";
7819       pr "  ";
7820       generate_java_prototype ~privat:true ~native:true name style;
7821       pr "\n";
7822       pr "\n";
7823   ) all_functions;
7824
7825   pr "}\n"
7826
7827 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
7828 and generate_java_call_args ~handle args =
7829   pr "(%s" handle;
7830   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
7831   pr ")"
7832
7833 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
7834     ?(semicolon=true) name style =
7835   if privat then pr "private ";
7836   if public then pr "public ";
7837   if native then pr "native ";
7838
7839   (* return type *)
7840   (match fst style with
7841    | RErr -> pr "void ";
7842    | RInt _ -> pr "int ";
7843    | RInt64 _ -> pr "long ";
7844    | RBool _ -> pr "boolean ";
7845    | RConstString _ | RConstOptString _ | RString _
7846    | RBufferOut _ -> pr "String ";
7847    | RStringList _ -> pr "String[] ";
7848    | RStruct (_, typ) ->
7849        let name = java_name_of_struct typ in
7850        pr "%s " name;
7851    | RStructList (_, typ) ->
7852        let name = java_name_of_struct typ in
7853        pr "%s[] " name;
7854    | RHashtable _ -> pr "HashMap<String,String> ";
7855   );
7856
7857   if native then pr "_%s " name else pr "%s " name;
7858   pr "(";
7859   let needs_comma = ref false in
7860   if native then (
7861     pr "long g";
7862     needs_comma := true
7863   );
7864
7865   (* args *)
7866   List.iter (
7867     fun arg ->
7868       if !needs_comma then pr ", ";
7869       needs_comma := true;
7870
7871       match arg with
7872       | String n
7873       | OptString n
7874       | FileIn n
7875       | FileOut n ->
7876           pr "String %s" n
7877       | StringList n ->
7878           pr "String[] %s" n
7879       | Bool n ->
7880           pr "boolean %s" n
7881       | Int n ->
7882           pr "int %s" n
7883   ) (snd style);
7884
7885   pr ")\n";
7886   pr "    throws LibGuestFSException";
7887   if semicolon then pr ";"
7888
7889 and generate_java_struct jtyp cols =
7890   generate_header CStyle LGPLv2;
7891
7892   pr "\
7893 package com.redhat.et.libguestfs;
7894
7895 /**
7896  * Libguestfs %s structure.
7897  *
7898  * @author rjones
7899  * @see GuestFS
7900  */
7901 public class %s {
7902 " jtyp jtyp;
7903
7904   List.iter (
7905     function
7906     | name, FString
7907     | name, FUUID
7908     | name, FBuffer -> pr "  public String %s;\n" name
7909     | name, (FBytes|FUInt64|FInt64) -> pr "  public long %s;\n" name
7910     | name, (FUInt32|FInt32) -> pr "  public int %s;\n" name
7911     | name, FChar -> pr "  public char %s;\n" name
7912     | name, FOptPercent ->
7913         pr "  /* The next field is [0..100] or -1 meaning 'not present': */\n";
7914         pr "  public float %s;\n" name
7915   ) cols;
7916
7917   pr "}\n"
7918
7919 and generate_java_c () =
7920   generate_header CStyle LGPLv2;
7921
7922   pr "\
7923 #include <stdio.h>
7924 #include <stdlib.h>
7925 #include <string.h>
7926
7927 #include \"com_redhat_et_libguestfs_GuestFS.h\"
7928 #include \"guestfs.h\"
7929
7930 /* Note that this function returns.  The exception is not thrown
7931  * until after the wrapper function returns.
7932  */
7933 static void
7934 throw_exception (JNIEnv *env, const char *msg)
7935 {
7936   jclass cl;
7937   cl = (*env)->FindClass (env,
7938                           \"com/redhat/et/libguestfs/LibGuestFSException\");
7939   (*env)->ThrowNew (env, cl, msg);
7940 }
7941
7942 JNIEXPORT jlong JNICALL
7943 Java_com_redhat_et_libguestfs_GuestFS__1create
7944   (JNIEnv *env, jobject obj)
7945 {
7946   guestfs_h *g;
7947
7948   g = guestfs_create ();
7949   if (g == NULL) {
7950     throw_exception (env, \"GuestFS.create: failed to allocate handle\");
7951     return 0;
7952   }
7953   guestfs_set_error_handler (g, NULL, NULL);
7954   return (jlong) (long) g;
7955 }
7956
7957 JNIEXPORT void JNICALL
7958 Java_com_redhat_et_libguestfs_GuestFS__1close
7959   (JNIEnv *env, jobject obj, jlong jg)
7960 {
7961   guestfs_h *g = (guestfs_h *) (long) jg;
7962   guestfs_close (g);
7963 }
7964
7965 ";
7966
7967   List.iter (
7968     fun (name, style, _, _, _, _, _) ->
7969       pr "JNIEXPORT ";
7970       (match fst style with
7971        | RErr -> pr "void ";
7972        | RInt _ -> pr "jint ";
7973        | RInt64 _ -> pr "jlong ";
7974        | RBool _ -> pr "jboolean ";
7975        | RConstString _ | RConstOptString _ | RString _
7976        | RBufferOut _ -> pr "jstring ";
7977        | RStruct _ | RHashtable _ ->
7978            pr "jobject ";
7979        | RStringList _ | RStructList _ ->
7980            pr "jobjectArray ";
7981       );
7982       pr "JNICALL\n";
7983       pr "Java_com_redhat_et_libguestfs_GuestFS_";
7984       pr "%s" (replace_str ("_" ^ name) "_" "_1");
7985       pr "\n";
7986       pr "  (JNIEnv *env, jobject obj, jlong jg";
7987       List.iter (
7988         function
7989         | String n
7990         | OptString n
7991         | FileIn n
7992         | FileOut n ->
7993             pr ", jstring j%s" n
7994         | StringList n ->
7995             pr ", jobjectArray j%s" n
7996         | Bool n ->
7997             pr ", jboolean j%s" n
7998         | Int n ->
7999             pr ", jint j%s" n
8000       ) (snd style);
8001       pr ")\n";
8002       pr "{\n";
8003       pr "  guestfs_h *g = (guestfs_h *) (long) jg;\n";
8004       let error_code, no_ret =
8005         match fst style with
8006         | RErr -> pr "  int r;\n"; "-1", ""
8007         | RBool _
8008         | RInt _ -> pr "  int r;\n"; "-1", "0"
8009         | RInt64 _ -> pr "  int64_t r;\n"; "-1", "0"
8010         | RConstString _ -> pr "  const char *r;\n"; "NULL", "NULL"
8011         | RConstOptString _ -> pr "  const char *r;\n"; "NULL", "NULL"
8012         | RString _ ->
8013             pr "  jstring jr;\n";
8014             pr "  char *r;\n"; "NULL", "NULL"
8015         | RStringList _ ->
8016             pr "  jobjectArray jr;\n";
8017             pr "  int r_len;\n";
8018             pr "  jclass cl;\n";
8019             pr "  jstring jstr;\n";
8020             pr "  char **r;\n"; "NULL", "NULL"
8021         | RStruct (_, typ) ->
8022             pr "  jobject jr;\n";
8023             pr "  jclass cl;\n";
8024             pr "  jfieldID fl;\n";
8025             pr "  struct guestfs_%s *r;\n" typ; "NULL", "NULL"
8026         | RStructList (_, typ) ->
8027             pr "  jobjectArray jr;\n";
8028             pr "  jclass cl;\n";
8029             pr "  jfieldID fl;\n";
8030             pr "  jobject jfl;\n";
8031             pr "  struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
8032         | RHashtable _ -> pr "  char **r;\n"; "NULL", "NULL"
8033         | RBufferOut _ ->
8034             pr "  jstring jr;\n";
8035             pr "  char *r;\n";
8036             pr "  size_t size;\n";
8037             "NULL", "NULL" in
8038       List.iter (
8039         function
8040         | String n
8041         | OptString n
8042         | FileIn n
8043         | FileOut n ->
8044             pr "  const char *%s;\n" n
8045         | StringList n ->
8046             pr "  int %s_len;\n" n;
8047             pr "  const char **%s;\n" n
8048         | Bool n
8049         | Int n ->
8050             pr "  int %s;\n" n
8051       ) (snd style);
8052
8053       let needs_i =
8054         (match fst style with
8055          | RStringList _ | RStructList _ -> true
8056          | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
8057          | RConstOptString _
8058          | RString _ | RBufferOut _ | RStruct _ | RHashtable _ -> false) ||
8059           List.exists (function StringList _ -> true | _ -> false) (snd style) in
8060       if needs_i then
8061         pr "  int i;\n";
8062
8063       pr "\n";
8064
8065       (* Get the parameters. *)
8066       List.iter (
8067         function
8068         | String n
8069         | FileIn n
8070         | FileOut n ->
8071             pr "  %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
8072         | OptString n ->
8073             (* This is completely undocumented, but Java null becomes
8074              * a NULL parameter.
8075              *)
8076             pr "  %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
8077         | StringList n ->
8078             pr "  %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
8079             pr "  %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
8080             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
8081             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
8082               n;
8083             pr "    %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
8084             pr "  }\n";
8085             pr "  %s[%s_len] = NULL;\n" n n;
8086         | Bool n
8087         | Int n ->
8088             pr "  %s = j%s;\n" n n
8089       ) (snd style);
8090
8091       (* Make the call. *)
8092       pr "  r = guestfs_%s " name;
8093       generate_c_call_args ~handle:"g" style;
8094       pr ";\n";
8095
8096       (* Release the parameters. *)
8097       List.iter (
8098         function
8099         | String n
8100         | FileIn n
8101         | FileOut n ->
8102             pr "  (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
8103         | OptString n ->
8104             pr "  if (j%s)\n" n;
8105             pr "    (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
8106         | StringList n ->
8107             pr "  for (i = 0; i < %s_len; ++i) {\n" n;
8108             pr "    jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
8109               n;
8110             pr "    (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
8111             pr "  }\n";
8112             pr "  free (%s);\n" n
8113         | Bool n
8114         | Int n -> ()
8115       ) (snd style);
8116
8117       (* Check for errors. *)
8118       pr "  if (r == %s) {\n" error_code;
8119       pr "    throw_exception (env, guestfs_last_error (g));\n";
8120       pr "    return %s;\n" no_ret;
8121       pr "  }\n";
8122
8123       (* Return value. *)
8124       (match fst style with
8125        | RErr -> ()
8126        | RInt _ -> pr "  return (jint) r;\n"
8127        | RBool _ -> pr "  return (jboolean) r;\n"
8128        | RInt64 _ -> pr "  return (jlong) r;\n"
8129        | RConstString _ -> pr "  return (*env)->NewStringUTF (env, r);\n"
8130        | RConstOptString _ ->
8131            pr "  return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
8132        | RString _ ->
8133            pr "  jr = (*env)->NewStringUTF (env, r);\n";
8134            pr "  free (r);\n";
8135            pr "  return jr;\n"
8136        | RStringList _ ->
8137            pr "  for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
8138            pr "  cl = (*env)->FindClass (env, \"java/lang/String\");\n";
8139            pr "  jstr = (*env)->NewStringUTF (env, \"\");\n";
8140            pr "  jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
8141            pr "  for (i = 0; i < r_len; ++i) {\n";
8142            pr "    jstr = (*env)->NewStringUTF (env, r[i]);\n";
8143            pr "    (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
8144            pr "    free (r[i]);\n";
8145            pr "  }\n";
8146            pr "  free (r);\n";
8147            pr "  return jr;\n"
8148        | RStruct (_, typ) ->
8149            let jtyp = java_name_of_struct typ in
8150            let cols = cols_of_struct typ in
8151            generate_java_struct_return typ jtyp cols
8152        | RStructList (_, typ) ->
8153            let jtyp = java_name_of_struct typ in
8154            let cols = cols_of_struct typ in
8155            generate_java_struct_list_return typ jtyp cols
8156        | RHashtable _ ->
8157            (* XXX *)
8158            pr "  throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
8159            pr "  return NULL;\n"
8160        | RBufferOut _ ->
8161            pr "  jr = (*env)->NewStringUTF (env, r); /* XXX size */\n";
8162            pr "  free (r);\n";
8163            pr "  return jr;\n"
8164       );
8165
8166       pr "}\n";
8167       pr "\n"
8168   ) all_functions
8169
8170 and generate_java_struct_return typ jtyp cols =
8171   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
8172   pr "  jr = (*env)->AllocObject (env, cl);\n";
8173   List.iter (
8174     function
8175     | name, FString ->
8176         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8177         pr "  (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
8178     | name, FUUID ->
8179         pr "  {\n";
8180         pr "    char s[33];\n";
8181         pr "    memcpy (s, r->%s, 32);\n" name;
8182         pr "    s[32] = 0;\n";
8183         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8184         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
8185         pr "  }\n";
8186     | name, FBuffer ->
8187         pr "  {\n";
8188         pr "    int len = r->%s_len;\n" name;
8189         pr "    char s[len+1];\n";
8190         pr "    memcpy (s, r->%s, len);\n" name;
8191         pr "    s[len] = 0;\n";
8192         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8193         pr "    (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
8194         pr "  }\n";
8195     | name, (FBytes|FUInt64|FInt64) ->
8196         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
8197         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
8198     | name, (FUInt32|FInt32) ->
8199         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
8200         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
8201     | name, FOptPercent ->
8202         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
8203         pr "  (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
8204     | name, FChar ->
8205         pr "  fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
8206         pr "  (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
8207   ) cols;
8208   pr "  free (r);\n";
8209   pr "  return jr;\n"
8210
8211 and generate_java_struct_list_return typ jtyp cols =
8212   pr "  cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
8213   pr "  jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
8214   pr "  for (i = 0; i < r->len; ++i) {\n";
8215   pr "    jfl = (*env)->AllocObject (env, cl);\n";
8216   List.iter (
8217     function
8218     | name, FString ->
8219         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8220         pr "    (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
8221     | name, FUUID ->
8222         pr "    {\n";
8223         pr "      char s[33];\n";
8224         pr "      memcpy (s, r->val[i].%s, 32);\n" name;
8225         pr "      s[32] = 0;\n";
8226         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8227         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
8228         pr "    }\n";
8229     | name, FBuffer ->
8230         pr "    {\n";
8231         pr "      int len = r->val[i].%s_len;\n" name;
8232         pr "      char s[len+1];\n";
8233         pr "      memcpy (s, r->val[i].%s, len);\n" name;
8234         pr "      s[len] = 0;\n";
8235         pr "      fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8236         pr "      (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
8237         pr "    }\n";
8238     | name, (FBytes|FUInt64|FInt64) ->
8239         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
8240         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
8241     | name, (FUInt32|FInt32) ->
8242         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
8243         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
8244     | name, FOptPercent ->
8245         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
8246         pr "    (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
8247     | name, FChar ->
8248         pr "    fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
8249         pr "    (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
8250   ) cols;
8251   pr "    (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
8252   pr "  }\n";
8253   pr "  guestfs_free_%s_list (r);\n" typ;
8254   pr "  return jr;\n"
8255
8256 and generate_haskell_hs () =
8257   generate_header HaskellStyle LGPLv2;
8258
8259   (* XXX We only know how to generate partial FFI for Haskell
8260    * at the moment.  Please help out!
8261    *)
8262   let can_generate style =
8263     match style with
8264     | RErr, _
8265     | RInt _, _
8266     | RInt64 _, _ -> true
8267     | RBool _, _
8268     | RConstString _, _
8269     | RConstOptString _, _
8270     | RString _, _
8271     | RStringList _, _
8272     | RStruct _, _
8273     | RStructList _, _
8274     | RHashtable _, _
8275     | RBufferOut _, _ -> false in
8276
8277   pr "\
8278 {-# INCLUDE <guestfs.h> #-}
8279 {-# LANGUAGE ForeignFunctionInterface #-}
8280
8281 module Guestfs (
8282   create";
8283
8284   (* List out the names of the actions we want to export. *)
8285   List.iter (
8286     fun (name, style, _, _, _, _, _) ->
8287       if can_generate style then pr ",\n  %s" name
8288   ) all_functions;
8289
8290   pr "
8291   ) where
8292 import Foreign
8293 import Foreign.C
8294 import Foreign.C.Types
8295 import IO
8296 import Control.Exception
8297 import Data.Typeable
8298
8299 data GuestfsS = GuestfsS            -- represents the opaque C struct
8300 type GuestfsP = Ptr GuestfsS        -- guestfs_h *
8301 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
8302
8303 -- XXX define properly later XXX
8304 data PV = PV
8305 data VG = VG
8306 data LV = LV
8307 data IntBool = IntBool
8308 data Stat = Stat
8309 data StatVFS = StatVFS
8310 data Hashtable = Hashtable
8311
8312 foreign import ccall unsafe \"guestfs_create\" c_create
8313   :: IO GuestfsP
8314 foreign import ccall unsafe \"&guestfs_close\" c_close
8315   :: FunPtr (GuestfsP -> IO ())
8316 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
8317   :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
8318
8319 create :: IO GuestfsH
8320 create = do
8321   p <- c_create
8322   c_set_error_handler p nullPtr nullPtr
8323   h <- newForeignPtr c_close p
8324   return h
8325
8326 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
8327   :: GuestfsP -> IO CString
8328
8329 -- last_error :: GuestfsH -> IO (Maybe String)
8330 -- last_error h = do
8331 --   str <- withForeignPtr h (\\p -> c_last_error p)
8332 --   maybePeek peekCString str
8333
8334 last_error :: GuestfsH -> IO (String)
8335 last_error h = do
8336   str <- withForeignPtr h (\\p -> c_last_error p)
8337   if (str == nullPtr)
8338     then return \"no error\"
8339     else peekCString str
8340
8341 ";
8342
8343   (* Generate wrappers for each foreign function. *)
8344   List.iter (
8345     fun (name, style, _, _, _, _, _) ->
8346       if can_generate style then (
8347         pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
8348         pr "  :: ";
8349         generate_haskell_prototype ~handle:"GuestfsP" style;
8350         pr "\n";
8351         pr "\n";
8352         pr "%s :: " name;
8353         generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
8354         pr "\n";
8355         pr "%s %s = do\n" name
8356           (String.concat " " ("h" :: List.map name_of_argt (snd style)));
8357         pr "  r <- ";
8358         (* Convert pointer arguments using with* functions. *)
8359         List.iter (
8360           function
8361           | FileIn n
8362           | FileOut n
8363           | String n -> pr "withCString %s $ \\%s -> " n n
8364           | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
8365           | StringList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
8366           | Bool _ | Int _ -> ()
8367         ) (snd style);
8368         (* Convert integer arguments. *)
8369         let args =
8370           List.map (
8371             function
8372             | Bool n -> sprintf "(fromBool %s)" n
8373             | Int n -> sprintf "(fromIntegral %s)" n
8374             | FileIn n | FileOut n | String n | OptString n | StringList n -> n
8375           ) (snd style) in
8376         pr "withForeignPtr h (\\p -> c_%s %s)\n" name
8377           (String.concat " " ("p" :: args));
8378         (match fst style with
8379          | RErr | RInt _ | RInt64 _ | RBool _ ->
8380              pr "  if (r == -1)\n";
8381              pr "    then do\n";
8382              pr "      err <- last_error h\n";
8383              pr "      fail err\n";
8384          | RConstString _ | RConstOptString _ | RString _
8385          | RStringList _ | RStruct _
8386          | RStructList _ | RHashtable _ | RBufferOut _ ->
8387              pr "  if (r == nullPtr)\n";
8388              pr "    then do\n";
8389              pr "      err <- last_error h\n";
8390              pr "      fail err\n";
8391         );
8392         (match fst style with
8393          | RErr ->
8394              pr "    else return ()\n"
8395          | RInt _ ->
8396              pr "    else return (fromIntegral r)\n"
8397          | RInt64 _ ->
8398              pr "    else return (fromIntegral r)\n"
8399          | RBool _ ->
8400              pr "    else return (toBool r)\n"
8401          | RConstString _
8402          | RConstOptString _
8403          | RString _
8404          | RStringList _
8405          | RStruct _
8406          | RStructList _
8407          | RHashtable _
8408          | RBufferOut _ ->
8409              pr "    else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
8410         );
8411         pr "\n";
8412       )
8413   ) all_functions
8414
8415 and generate_haskell_prototype ~handle ?(hs = false) style =
8416   pr "%s -> " handle;
8417   let string = if hs then "String" else "CString" in
8418   let int = if hs then "Int" else "CInt" in
8419   let bool = if hs then "Bool" else "CInt" in
8420   let int64 = if hs then "Integer" else "Int64" in
8421   List.iter (
8422     fun arg ->
8423       (match arg with
8424        | String _ -> pr "%s" string
8425        | OptString _ -> if hs then pr "Maybe String" else pr "CString"
8426        | StringList _ -> if hs then pr "[String]" else pr "Ptr CString"
8427        | Bool _ -> pr "%s" bool
8428        | Int _ -> pr "%s" int
8429        | FileIn _ -> pr "%s" string
8430        | FileOut _ -> pr "%s" string
8431       );
8432       pr " -> ";
8433   ) (snd style);
8434   pr "IO (";
8435   (match fst style with
8436    | RErr -> if not hs then pr "CInt"
8437    | RInt _ -> pr "%s" int
8438    | RInt64 _ -> pr "%s" int64
8439    | RBool _ -> pr "%s" bool
8440    | RConstString _ -> pr "%s" string
8441    | RConstOptString _ -> pr "Maybe %s" string
8442    | RString _ -> pr "%s" string
8443    | RStringList _ -> pr "[%s]" string
8444    | RStruct (_, typ) ->
8445        let name = java_name_of_struct typ in
8446        pr "%s" name
8447    | RStructList (_, typ) ->
8448        let name = java_name_of_struct typ in
8449        pr "[%s]" name
8450    | RHashtable _ -> pr "Hashtable"
8451    | RBufferOut _ -> pr "%s" string
8452   );
8453   pr ")"
8454
8455 and generate_bindtests () =
8456   generate_header CStyle LGPLv2;
8457
8458   pr "\
8459 #include <stdio.h>
8460 #include <stdlib.h>
8461 #include <inttypes.h>
8462 #include <string.h>
8463
8464 #include \"guestfs.h\"
8465 #include \"guestfs_protocol.h\"
8466
8467 #define error guestfs_error
8468 #define safe_calloc guestfs_safe_calloc
8469 #define safe_malloc guestfs_safe_malloc
8470
8471 static void
8472 print_strings (char * const* const argv)
8473 {
8474   int argc;
8475
8476   printf (\"[\");
8477   for (argc = 0; argv[argc] != NULL; ++argc) {
8478     if (argc > 0) printf (\", \");
8479     printf (\"\\\"%%s\\\"\", argv[argc]);
8480   }
8481   printf (\"]\\n\");
8482 }
8483
8484 /* The test0 function prints its parameters to stdout. */
8485 ";
8486
8487   let test0, tests =
8488     match test_functions with
8489     | [] -> assert false
8490     | test0 :: tests -> test0, tests in
8491
8492   let () =
8493     let (name, style, _, _, _, _, _) = test0 in
8494     generate_prototype ~extern:false ~semicolon:false ~newline:true
8495       ~handle:"g" ~prefix:"guestfs_" name style;
8496     pr "{\n";
8497     List.iter (
8498       function
8499       | String n
8500       | FileIn n
8501       | FileOut n -> pr "  printf (\"%%s\\n\", %s);\n" n
8502       | OptString n -> pr "  printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
8503       | StringList n -> pr "  print_strings (%s);\n" n
8504       | Bool n -> pr "  printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
8505       | Int n -> pr "  printf (\"%%d\\n\", %s);\n" n
8506     ) (snd style);
8507     pr "  /* Java changes stdout line buffering so we need this: */\n";
8508     pr "  fflush (stdout);\n";
8509     pr "  return 0;\n";
8510     pr "}\n";
8511     pr "\n" in
8512
8513   List.iter (
8514     fun (name, style, _, _, _, _, _) ->
8515       if String.sub name (String.length name - 3) 3 <> "err" then (
8516         pr "/* Test normal return. */\n";
8517         generate_prototype ~extern:false ~semicolon:false ~newline:true
8518           ~handle:"g" ~prefix:"guestfs_" name style;
8519         pr "{\n";
8520         (match fst style with
8521          | RErr ->
8522              pr "  return 0;\n"
8523          | RInt _ ->
8524              pr "  int r;\n";
8525              pr "  sscanf (val, \"%%d\", &r);\n";
8526              pr "  return r;\n"
8527          | RInt64 _ ->
8528              pr "  int64_t r;\n";
8529              pr "  sscanf (val, \"%%\" SCNi64, &r);\n";
8530              pr "  return r;\n"
8531          | RBool _ ->
8532              pr "  return strcmp (val, \"true\") == 0;\n"
8533          | RConstString _
8534          | RConstOptString _ ->
8535              (* Can't return the input string here.  Return a static
8536               * string so we ensure we get a segfault if the caller
8537               * tries to free it.
8538               *)
8539              pr "  return \"static string\";\n"
8540          | RString _ ->
8541              pr "  return strdup (val);\n"
8542          | RStringList _ ->
8543              pr "  char **strs;\n";
8544              pr "  int n, i;\n";
8545              pr "  sscanf (val, \"%%d\", &n);\n";
8546              pr "  strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
8547              pr "  for (i = 0; i < n; ++i) {\n";
8548              pr "    strs[i] = safe_malloc (g, 16);\n";
8549              pr "    snprintf (strs[i], 16, \"%%d\", i);\n";
8550              pr "  }\n";
8551              pr "  strs[n] = NULL;\n";
8552              pr "  return strs;\n"
8553          | RStruct (_, typ) ->
8554              pr "  struct guestfs_%s *r;\n" typ;
8555              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
8556              pr "  return r;\n"
8557          | RStructList (_, typ) ->
8558              pr "  struct guestfs_%s_list *r;\n" typ;
8559              pr "  r = safe_calloc (g, sizeof *r, 1);\n";
8560              pr "  sscanf (val, \"%%d\", &r->len);\n";
8561              pr "  r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
8562              pr "  return r;\n"
8563          | RHashtable _ ->
8564              pr "  char **strs;\n";
8565              pr "  int n, i;\n";
8566              pr "  sscanf (val, \"%%d\", &n);\n";
8567              pr "  strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
8568              pr "  for (i = 0; i < n; ++i) {\n";
8569              pr "    strs[i*2] = safe_malloc (g, 16);\n";
8570              pr "    strs[i*2+1] = safe_malloc (g, 16);\n";
8571              pr "    snprintf (strs[i*2], 16, \"%%d\", i);\n";
8572              pr "    snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
8573              pr "  }\n";
8574              pr "  strs[n*2] = NULL;\n";
8575              pr "  return strs;\n"
8576          | RBufferOut _ ->
8577              pr "  return strdup (val);\n"
8578         );
8579         pr "}\n";
8580         pr "\n"
8581       ) else (
8582         pr "/* Test error return. */\n";
8583         generate_prototype ~extern:false ~semicolon:false ~newline:true
8584           ~handle:"g" ~prefix:"guestfs_" name style;
8585         pr "{\n";
8586         pr "  error (g, \"error\");\n";
8587         (match fst style with
8588          | RErr | RInt _ | RInt64 _ | RBool _ ->
8589              pr "  return -1;\n"
8590          | RConstString _ | RConstOptString _
8591          | RString _ | RStringList _ | RStruct _
8592          | RStructList _
8593          | RHashtable _
8594          | RBufferOut _ ->
8595              pr "  return NULL;\n"
8596         );
8597         pr "}\n";
8598         pr "\n"
8599       )
8600   ) tests
8601
8602 and generate_ocaml_bindtests () =
8603   generate_header OCamlStyle GPLv2;
8604
8605   pr "\
8606 let () =
8607   let g = Guestfs.create () in
8608 ";
8609
8610   let mkargs args =
8611     String.concat " " (
8612       List.map (
8613         function
8614         | CallString s -> "\"" ^ s ^ "\""
8615         | CallOptString None -> "None"
8616         | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
8617         | CallStringList xs ->
8618             "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
8619         | CallInt i when i >= 0 -> string_of_int i
8620         | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
8621         | CallBool b -> string_of_bool b
8622       ) args
8623     )
8624   in
8625
8626   generate_lang_bindtests (
8627     fun f args -> pr "  Guestfs.%s g %s;\n" f (mkargs args)
8628   );
8629
8630   pr "print_endline \"EOF\"\n"
8631
8632 and generate_perl_bindtests () =
8633   pr "#!/usr/bin/perl -w\n";
8634   generate_header HashStyle GPLv2;
8635
8636   pr "\
8637 use strict;
8638
8639 use Sys::Guestfs;
8640
8641 my $g = Sys::Guestfs->new ();
8642 ";
8643
8644   let mkargs args =
8645     String.concat ", " (
8646       List.map (
8647         function
8648         | CallString s -> "\"" ^ s ^ "\""
8649         | CallOptString None -> "undef"
8650         | CallOptString (Some s) -> sprintf "\"%s\"" s
8651         | CallStringList xs ->
8652             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8653         | CallInt i -> string_of_int i
8654         | CallBool b -> if b then "1" else "0"
8655       ) args
8656     )
8657   in
8658
8659   generate_lang_bindtests (
8660     fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
8661   );
8662
8663   pr "print \"EOF\\n\"\n"
8664
8665 and generate_python_bindtests () =
8666   generate_header HashStyle GPLv2;
8667
8668   pr "\
8669 import guestfs
8670
8671 g = guestfs.GuestFS ()
8672 ";
8673
8674   let mkargs args =
8675     String.concat ", " (
8676       List.map (
8677         function
8678         | CallString s -> "\"" ^ s ^ "\""
8679         | CallOptString None -> "None"
8680         | CallOptString (Some s) -> sprintf "\"%s\"" s
8681         | CallStringList xs ->
8682             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8683         | CallInt i -> string_of_int i
8684         | CallBool b -> if b then "1" else "0"
8685       ) args
8686     )
8687   in
8688
8689   generate_lang_bindtests (
8690     fun f args -> pr "g.%s (%s)\n" f (mkargs args)
8691   );
8692
8693   pr "print \"EOF\"\n"
8694
8695 and generate_ruby_bindtests () =
8696   generate_header HashStyle GPLv2;
8697
8698   pr "\
8699 require 'guestfs'
8700
8701 g = Guestfs::create()
8702 ";
8703
8704   let mkargs args =
8705     String.concat ", " (
8706       List.map (
8707         function
8708         | CallString s -> "\"" ^ s ^ "\""
8709         | CallOptString None -> "nil"
8710         | CallOptString (Some s) -> sprintf "\"%s\"" s
8711         | CallStringList xs ->
8712             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8713         | CallInt i -> string_of_int i
8714         | CallBool b -> string_of_bool b
8715       ) args
8716     )
8717   in
8718
8719   generate_lang_bindtests (
8720     fun f args -> pr "g.%s(%s)\n" f (mkargs args)
8721   );
8722
8723   pr "print \"EOF\\n\"\n"
8724
8725 and generate_java_bindtests () =
8726   generate_header CStyle GPLv2;
8727
8728   pr "\
8729 import com.redhat.et.libguestfs.*;
8730
8731 public class Bindtests {
8732     public static void main (String[] argv)
8733     {
8734         try {
8735             GuestFS g = new GuestFS ();
8736 ";
8737
8738   let mkargs args =
8739     String.concat ", " (
8740       List.map (
8741         function
8742         | CallString s -> "\"" ^ s ^ "\""
8743         | CallOptString None -> "null"
8744         | CallOptString (Some s) -> sprintf "\"%s\"" s
8745         | CallStringList xs ->
8746             "new String[]{" ^
8747               String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
8748         | CallInt i -> string_of_int i
8749         | CallBool b -> string_of_bool b
8750       ) args
8751     )
8752   in
8753
8754   generate_lang_bindtests (
8755     fun f args -> pr "            g.%s (%s);\n" f (mkargs args)
8756   );
8757
8758   pr "
8759             System.out.println (\"EOF\");
8760         }
8761         catch (Exception exn) {
8762             System.err.println (exn);
8763             System.exit (1);
8764         }
8765     }
8766 }
8767 "
8768
8769 and generate_haskell_bindtests () =
8770   generate_header HaskellStyle GPLv2;
8771
8772   pr "\
8773 module Bindtests where
8774 import qualified Guestfs
8775
8776 main = do
8777   g <- Guestfs.create
8778 ";
8779
8780   let mkargs args =
8781     String.concat " " (
8782       List.map (
8783         function
8784         | CallString s -> "\"" ^ s ^ "\""
8785         | CallOptString None -> "Nothing"
8786         | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
8787         | CallStringList xs ->
8788             "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
8789         | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
8790         | CallInt i -> string_of_int i
8791         | CallBool true -> "True"
8792         | CallBool false -> "False"
8793       ) args
8794     )
8795   in
8796
8797   generate_lang_bindtests (
8798     fun f args -> pr "  Guestfs.%s g %s\n" f (mkargs args)
8799   );
8800
8801   pr "  putStrLn \"EOF\"\n"
8802
8803 (* Language-independent bindings tests - we do it this way to
8804  * ensure there is parity in testing bindings across all languages.
8805  *)
8806 and generate_lang_bindtests call =
8807   call "test0" [CallString "abc"; CallOptString (Some "def");
8808                 CallStringList []; CallBool false;
8809                 CallInt 0; CallString "123"; CallString "456"];
8810   call "test0" [CallString "abc"; CallOptString None;
8811                 CallStringList []; CallBool false;
8812                 CallInt 0; CallString "123"; CallString "456"];
8813   call "test0" [CallString ""; CallOptString (Some "def");
8814                 CallStringList []; CallBool false;
8815                 CallInt 0; CallString "123"; CallString "456"];
8816   call "test0" [CallString ""; CallOptString (Some "");
8817                 CallStringList []; CallBool false;
8818                 CallInt 0; CallString "123"; CallString "456"];
8819   call "test0" [CallString "abc"; CallOptString (Some "def");
8820                 CallStringList ["1"]; CallBool false;
8821                 CallInt 0; CallString "123"; CallString "456"];
8822   call "test0" [CallString "abc"; CallOptString (Some "def");
8823                 CallStringList ["1"; "2"]; CallBool false;
8824                 CallInt 0; CallString "123"; CallString "456"];
8825   call "test0" [CallString "abc"; CallOptString (Some "def");
8826                 CallStringList ["1"]; CallBool true;
8827                 CallInt 0; CallString "123"; CallString "456"];
8828   call "test0" [CallString "abc"; CallOptString (Some "def");
8829                 CallStringList ["1"]; CallBool false;
8830                 CallInt (-1); CallString "123"; CallString "456"];
8831   call "test0" [CallString "abc"; CallOptString (Some "def");
8832                 CallStringList ["1"]; CallBool false;
8833                 CallInt (-2); CallString "123"; CallString "456"];
8834   call "test0" [CallString "abc"; CallOptString (Some "def");
8835                 CallStringList ["1"]; CallBool false;
8836                 CallInt 1; CallString "123"; CallString "456"];
8837   call "test0" [CallString "abc"; CallOptString (Some "def");
8838                 CallStringList ["1"]; CallBool false;
8839                 CallInt 2; CallString "123"; CallString "456"];
8840   call "test0" [CallString "abc"; CallOptString (Some "def");
8841                 CallStringList ["1"]; CallBool false;
8842                 CallInt 4095; CallString "123"; CallString "456"];
8843   call "test0" [CallString "abc"; CallOptString (Some "def");
8844                 CallStringList ["1"]; CallBool false;
8845                 CallInt 0; CallString ""; CallString ""]
8846
8847 (* XXX Add here tests of the return and error functions. *)
8848
8849 (* This is used to generate the src/MAX_PROC_NR file which
8850  * contains the maximum procedure number, a surrogate for the
8851  * ABI version number.  See src/Makefile.am for the details.
8852  *)
8853 and generate_max_proc_nr () =
8854   let proc_nrs = List.map (
8855     fun (_, _, proc_nr, _, _, _, _) -> proc_nr
8856   ) daemon_functions in
8857
8858   let max_proc_nr = List.fold_left max 0 proc_nrs in
8859
8860   pr "%d\n" max_proc_nr
8861
8862 let output_to filename =
8863   let filename_new = filename ^ ".new" in
8864   chan := open_out filename_new;
8865   let close () =
8866     close_out !chan;
8867     chan := stdout;
8868
8869     (* Is the new file different from the current file? *)
8870     if Sys.file_exists filename && files_equal filename filename_new then
8871       Unix.unlink filename_new          (* same, so skip it *)
8872     else (
8873       (* different, overwrite old one *)
8874       (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
8875       Unix.rename filename_new filename;
8876       Unix.chmod filename 0o444;
8877       printf "written %s\n%!" filename;
8878     )
8879   in
8880   close
8881
8882 (* Main program. *)
8883 let () =
8884   check_functions ();
8885
8886   if not (Sys.file_exists "HACKING") then (
8887     eprintf "\
8888 You are probably running this from the wrong directory.
8889 Run it from the top source directory using the command
8890   src/generator.ml
8891 ";
8892     exit 1
8893   );
8894
8895   let close = output_to "src/guestfs_protocol.x" in
8896   generate_xdr ();
8897   close ();
8898
8899   let close = output_to "src/guestfs-structs.h" in
8900   generate_structs_h ();
8901   close ();
8902
8903   let close = output_to "src/guestfs-actions.h" in
8904   generate_actions_h ();
8905   close ();
8906
8907   let close = output_to "src/guestfs-actions.c" in
8908   generate_client_actions ();
8909   close ();
8910
8911   let close = output_to "daemon/actions.h" in
8912   generate_daemon_actions_h ();
8913   close ();
8914
8915   let close = output_to "daemon/stubs.c" in
8916   generate_daemon_actions ();
8917   close ();
8918
8919   let close = output_to "daemon/names.c" in
8920   generate_daemon_names ();
8921   close ();
8922
8923   let close = output_to "capitests/tests.c" in
8924   generate_tests ();
8925   close ();
8926
8927   let close = output_to "src/guestfs-bindtests.c" in
8928   generate_bindtests ();
8929   close ();
8930
8931   let close = output_to "fish/cmds.c" in
8932   generate_fish_cmds ();
8933   close ();
8934
8935   let close = output_to "fish/completion.c" in
8936   generate_fish_completion ();
8937   close ();
8938
8939   let close = output_to "guestfs-structs.pod" in
8940   generate_structs_pod ();
8941   close ();
8942
8943   let close = output_to "guestfs-actions.pod" in
8944   generate_actions_pod ();
8945   close ();
8946
8947   let close = output_to "guestfish-actions.pod" in
8948   generate_fish_actions_pod ();
8949   close ();
8950
8951   let close = output_to "ocaml/guestfs.mli" in
8952   generate_ocaml_mli ();
8953   close ();
8954
8955   let close = output_to "ocaml/guestfs.ml" in
8956   generate_ocaml_ml ();
8957   close ();
8958
8959   let close = output_to "ocaml/guestfs_c_actions.c" in
8960   generate_ocaml_c ();
8961   close ();
8962
8963   let close = output_to "ocaml/bindtests.ml" in
8964   generate_ocaml_bindtests ();
8965   close ();
8966
8967   let close = output_to "perl/Guestfs.xs" in
8968   generate_perl_xs ();
8969   close ();
8970
8971   let close = output_to "perl/lib/Sys/Guestfs.pm" in
8972   generate_perl_pm ();
8973   close ();
8974
8975   let close = output_to "perl/bindtests.pl" in
8976   generate_perl_bindtests ();
8977   close ();
8978
8979   let close = output_to "python/guestfs-py.c" in
8980   generate_python_c ();
8981   close ();
8982
8983   let close = output_to "python/guestfs.py" in
8984   generate_python_py ();
8985   close ();
8986
8987   let close = output_to "python/bindtests.py" in
8988   generate_python_bindtests ();
8989   close ();
8990
8991   let close = output_to "ruby/ext/guestfs/_guestfs.c" in
8992   generate_ruby_c ();
8993   close ();
8994
8995   let close = output_to "ruby/bindtests.rb" in
8996   generate_ruby_bindtests ();
8997   close ();
8998
8999   let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
9000   generate_java_java ();
9001   close ();
9002
9003   List.iter (
9004     fun (typ, jtyp) ->
9005       let cols = cols_of_struct typ in
9006       let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
9007       let close = output_to filename in
9008       generate_java_struct jtyp cols;
9009       close ();
9010   ) java_structs;
9011
9012   let close = output_to "java/Makefile.inc" in
9013   pr "java_built_sources =";
9014   List.iter (
9015     fun (typ, jtyp) ->
9016         pr " com/redhat/et/libguestfs/%s.java" jtyp;
9017   ) java_structs;
9018   pr " com/redhat/et/libguestfs/GuestFS.java\n";
9019   close ();
9020
9021   let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
9022   generate_java_c ();
9023   close ();
9024
9025   let close = output_to "java/Bindtests.java" in
9026   generate_java_bindtests ();
9027   close ();
9028
9029   let close = output_to "haskell/Guestfs.hs" in
9030   generate_haskell_hs ();
9031   close ();
9032
9033   let close = output_to "haskell/Bindtests.hs" in
9034   generate_haskell_bindtests ();
9035   close ();
9036
9037   let close = output_to "src/MAX_PROC_NR" in
9038   generate_max_proc_nr ();
9039   close ();
9040
9041   (* Always generate this file last, and unconditionally.  It's used
9042    * by the Makefile to know when we must re-run the generator.
9043    *)
9044   let chan = open_out "src/stamp-generator" in
9045   fprintf chan "1\n";
9046   close_out chan