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