3 * Copyright (C) 2009 Red Hat Inc.
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.
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.
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
20 (* This script generates a large amount of code and documentation for
21 * all the daemon actions.
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.
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.
31 * IMPORTANT: This script should NOT print any warnings. If it prints
32 * warnings, you should treat them as errors.
40 type style = ret * args
42 (* "RErr" as a return value means an int used as a simple error
43 * indication, ie. 0 or -1.
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).
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).
59 (* "RBool" is a bool return value which can be true/false or
64 (* "RConstString" is a string that refers to a constant value.
65 * The return value must NOT be NULL (since NULL indicates
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.
72 | RConstString of string
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!
78 | RConstOptString of string
80 (* "RString" is a returned string. It must NOT be NULL, since
81 * a NULL return indicates an error. The caller frees this.
85 (* "RStringList" is a list of strings. No string in the list
86 * can be NULL. The caller frees the strings and the array.
88 | RStringList of string
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.
95 | RStruct of string * string (* name of retval, name of struct *)
97 (* "RStructList" is a function which returns either a list/array
98 * of structures (could be zero-length), or an error indication.
100 | RStructList of string * string (* name of retval, name of struct *)
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.
109 | RHashtable of string
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.
117 * Other programming languages support strings with arbitrary 8 bit
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
124 | RBufferOut of string
126 and args = argt list (* Function parameters, guestfs handle is implicit. *)
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.
136 | String of string (* const char *name, cannot be NULL *)
137 | Device of string (* /dev device name, cannot be NULL *)
138 | Pathname of string (* file name, cannot be NULL *)
139 | OptString of string (* const char *name, may be NULL *)
140 | StringList of string(* list of strings (each string cannot be NULL) *)
141 | Bool of string (* boolean *)
142 | Int of string (* int (smallish ints, signed, <= 31 bits) *)
143 (* These are treated as filenames (simple string parameters) in
144 * the C API and bindings. But in the RPC protocol, we transfer
145 * the actual file content up to or down from the daemon.
146 * FileIn: local machine -> daemon (in request)
147 * FileOut: daemon -> local machine (in reply)
148 * In guestfish (only), the special name "-" means read from
149 * stdin or write to stdout.
154 (* Opaque buffer which can contain arbitrary 8 bit data.
155 * In the C API, this is expressed as <char *, int> pair.
156 * Most other languages have a string type which can contain
157 * ASCII NUL. We use whatever type is appropriate for each
159 * Buffers are limited by the total message size. To transfer
160 * large blocks of data, use FileIn/FileOut parameters instead.
161 * To return an arbitrary buffer, use RBufferOut.
167 | ProtocolLimitWarning (* display warning about protocol size limits *)
168 | DangerWillRobinson (* flags particularly dangerous commands *)
169 | FishAlias of string (* provide an alias for this cmd in guestfish *)
170 | FishAction of string (* call this function in guestfish *)
171 | NotInFish (* do not export via guestfish *)
172 | NotInDocs (* do not add this function to documentation *)
173 | DeprecatedBy of string (* function is deprecated, use .. instead *)
175 (* You can supply zero or as many tests as you want per API call.
177 * Note that the test environment has 3 block devices, of size 500MB,
178 * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and
179 * a fourth squashfs block device with some known files on it (/dev/sdd).
181 * Note for partitioning purposes, the 500MB device has 1015 cylinders.
182 * Number of cylinders was 63 for IDE emulated disks with precisely
183 * the same size. How exactly this is calculated is a mystery.
185 * The squashfs block device (/dev/sdd) comes from images/test.sqsh.
187 * To be able to run the tests in a reasonable amount of time,
188 * the virtual machine and block devices are reused between tests.
189 * So don't try testing kill_subprocess :-x
191 * Between each test we blockdev-setrw, umount-all, lvm-remove-all.
193 * Don't assume anything about the previous contents of the block
194 * devices. Use 'Init*' to create some initial scenarios.
196 * You can add a prerequisite clause to any individual test. This
197 * is a run-time check, which, if it fails, causes the test to be
198 * skipped. Useful if testing a command which might not work on
199 * all variations of libguestfs builds. A test that has prerequisite
200 * of 'Always' is run unconditionally.
202 * In addition, packagers can skip individual tests by setting the
203 * environment variables: eg:
204 * SKIP_TEST_<CMD>_<NUM>=1 SKIP_TEST_COMMAND_3=1 (skips test #3 of command)
205 * SKIP_TEST_<CMD>=1 SKIP_TEST_ZEROFREE=1 (skips all zerofree tests)
207 type tests = (test_init * test_prereq * test) list
209 (* Run the command sequence and just expect nothing to fail. *)
212 (* Run the command sequence and expect the output of the final
213 * command to be the string.
215 | TestOutput of seq * string
217 (* Run the command sequence and expect the output of the final
218 * command to be the list of strings.
220 | TestOutputList of seq * string list
222 (* Run the command sequence and expect the output of the final
223 * command to be the list of block devices (could be either
224 * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th
225 * character of each string).
227 | TestOutputListOfDevices of seq * string list
229 (* Run the command sequence and expect the output of the final
230 * command to be the integer.
232 | TestOutputInt of seq * int
234 (* Run the command sequence and expect the output of the final
235 * command to be <op> <int>, eg. ">=", "1".
237 | TestOutputIntOp of seq * string * int
239 (* Run the command sequence and expect the output of the final
240 * command to be a true value (!= 0 or != NULL).
242 | TestOutputTrue of seq
244 (* Run the command sequence and expect the output of the final
245 * command to be a false value (== 0 or == NULL, but not an error).
247 | TestOutputFalse of seq
249 (* Run the command sequence and expect the output of the final
250 * command to be a list of the given length (but don't care about
253 | TestOutputLength of seq * int
255 (* Run the command sequence and expect the output of the final
256 * command to be a buffer (RBufferOut), ie. string + size.
258 | TestOutputBuffer of seq * string
260 (* Run the command sequence and expect the output of the final
261 * command to be a structure.
263 | TestOutputStruct of seq * test_field_compare list
265 (* Run the command sequence and expect the final command (only)
268 | TestLastFail of seq
270 and test_field_compare =
271 | CompareWithInt of string * int
272 | CompareWithIntOp of string * string * int
273 | CompareWithString of string * string
274 | CompareFieldsIntEq of string * string
275 | CompareFieldsStrEq of string * string
277 (* Test prerequisites. *)
279 (* Test always runs. *)
282 (* Test is currently disabled - eg. it fails, or it tests some
283 * unimplemented feature.
287 (* 'string' is some C code (a function body) that should return
288 * true or false. The test will run if the code returns true.
292 (* As for 'If' but the test runs _unless_ the code returns true. *)
295 (* Some initial scenarios for testing. *)
297 (* Do nothing, block devices could contain random stuff including
298 * LVM PVs, and some filesystems might be mounted. This is usually
303 (* Block devices are empty and no filesystems are mounted. *)
306 (* /dev/sda contains a single partition /dev/sda1, with random
307 * content. /dev/sdb and /dev/sdc may have random content.
312 (* /dev/sda contains a single partition /dev/sda1, which is formatted
313 * as ext2, empty [except for lost+found] and mounted on /.
314 * /dev/sdb and /dev/sdc may have random content.
320 * /dev/sda1 (is a PV):
321 * /dev/VG/LV (size 8MB):
322 * formatted as ext2, empty [except for lost+found], mounted on /
323 * /dev/sdb and /dev/sdc may have random content.
327 (* /dev/sdd (the squashfs, see images/ directory in source)
332 (* Sequence of commands for testing. *)
334 and cmd = string list
336 (* Note about long descriptions: When referring to another
337 * action, use the format C<guestfs_other> (ie. the full name of
338 * the C function). This will be replaced as appropriate in other
341 * Apart from that, long descriptions are just perldoc paragraphs.
344 (* These test functions are used in the language binding tests. *)
346 let test_all_args = [
349 StringList "strlist";
356 let test_all_rets = [
357 (* except for RErr, which is tested thoroughly elsewhere *)
358 "test0rint", RInt "valout";
359 "test0rint64", RInt64 "valout";
360 "test0rbool", RBool "valout";
361 "test0rconststring", RConstString "valout";
362 "test0rconstoptstring", RConstOptString "valout";
363 "test0rstring", RString "valout";
364 "test0rstringlist", RStringList "valout";
365 "test0rstruct", RStruct ("valout", "lvm_pv");
366 "test0rstructlist", RStructList ("valout", "lvm_pv");
367 "test0rhashtable", RHashtable "valout";
370 let test_functions = [
371 ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs],
373 "internal test function - do not use",
375 This is an internal test function which is used to test whether
376 the automatically generated bindings can handle every possible
377 parameter type correctly.
379 It echos the contents of each parameter to stdout.
381 You probably don't want to call this function.");
385 [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs],
387 "internal test function - do not use",
389 This is an internal test function which is used to test whether
390 the automatically generated bindings can handle every possible
391 return type correctly.
393 It converts string C<val> to the return type.
395 You probably don't want to call this function.");
396 (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs],
398 "internal test function - do not use",
400 This is an internal test function which is used to test whether
401 the automatically generated bindings can handle every possible
402 return type correctly.
404 This function always returns an error.
406 You probably don't want to call this function.")]
410 (* non_daemon_functions are any functions which don't get processed
411 * in the daemon, eg. functions for setting and getting local
412 * configuration values.
415 let non_daemon_functions = test_functions @ [
416 ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"],
418 "launch the qemu subprocess",
420 Internally libguestfs is implemented by running a virtual machine
423 You should call this after configuring the handle
424 (eg. adding drives) but before performing any actions.");
426 ("wait_ready", (RErr, []), -1, [NotInFish],
428 "wait until the qemu subprocess launches",
430 Internally libguestfs is implemented by running a virtual machine
433 You should call this after C<guestfs_launch> to wait for the launch
436 ("kill_subprocess", (RErr, []), -1, [],
438 "kill the qemu subprocess",
440 This kills the qemu subprocess. You should never need to call this.");
442 ("add_drive", (RErr, [String "filename"]), -1, [FishAlias "add"],
444 "add an image to examine or modify",
446 This function adds a virtual machine disk image C<filename> to the
447 guest. The first time you call this function, the disk appears as IDE
448 disk 0 (C</dev/sda>) in the guest, the second time as C</dev/sdb>, and
451 You don't necessarily need to be root when using libguestfs. However
452 you obviously do need sufficient permissions to access the filename
453 for whatever operations you want to perform (ie. read access if you
454 just want to read the image or write access if you want to modify the
457 This is equivalent to the qemu parameter
458 C<-drive file=filename,cache=off,if=...>.
459 C<cache=off> is omitted in cases where it is not supported by
460 the underlying filesystem.
462 Note that this call checks for the existence of C<filename>. This
463 stops you from specifying other types of drive which are supported
464 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
465 the general C<guestfs_config> call instead.");
467 ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"],
469 "add a CD-ROM disk image to examine",
471 This function adds a virtual CD-ROM disk image to the guest.
473 This is equivalent to the qemu parameter C<-cdrom filename>.
475 Note that this call checks for the existence of C<filename>. This
476 stops you from specifying other types of drive which are supported
477 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
478 the general C<guestfs_config> call instead.");
480 ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"],
482 "add a drive in snapshot mode (read-only)",
484 This adds a drive in snapshot mode, making it effectively
487 Note that writes to the device are allowed, and will be seen for
488 the duration of the guestfs handle, but they are written
489 to a temporary file which is discarded as soon as the guestfs
490 handle is closed. We don't currently have any method to enable
491 changes to be committed, although qemu can support this.
493 This is equivalent to the qemu parameter
494 C<-drive file=filename,snapshot=on,if=...>.
496 Note that this call checks for the existence of C<filename>. This
497 stops you from specifying other types of drive which are supported
498 by qemu such as C<nbd:> and C<http:> URLs. To specify those, use
499 the general C<guestfs_config> call instead.");
501 ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [],
503 "add qemu parameters",
505 This can be used to add arbitrary qemu command line parameters
506 of the form C<-param value>. Actually it's not quite arbitrary - we
507 prevent you from setting some parameters which would interfere with
508 parameters that we use.
510 The first character of C<param> string must be a C<-> (dash).
512 C<value> can be NULL.");
514 ("set_qemu", (RErr, [String "qemu"]), -1, [FishAlias "qemu"],
516 "set the qemu binary",
518 Set the qemu binary that we will use.
520 The default is chosen when the library was compiled by the
523 You can also override this by setting the C<LIBGUESTFS_QEMU>
524 environment variable.
526 Setting C<qemu> to C<NULL> restores the default qemu binary.");
528 ("get_qemu", (RConstString "qemu", []), -1, [],
529 [InitNone, Always, TestRun (
531 "get the qemu binary",
533 Return the current qemu binary.
535 This is always non-NULL. If it wasn't set already, then this will
536 return the default qemu binary name.");
538 ("set_path", (RErr, [String "searchpath"]), -1, [FishAlias "path"],
540 "set the search path",
542 Set the path that libguestfs searches for kernel and initrd.img.
544 The default is C<$libdir/guestfs> unless overridden by setting
545 C<LIBGUESTFS_PATH> environment variable.
547 Setting C<path> to C<NULL> restores the default path.");
549 ("get_path", (RConstString "path", []), -1, [],
550 [InitNone, Always, TestRun (
552 "get the search path",
554 Return the current search path.
556 This is always non-NULL. If it wasn't set already, then this will
557 return the default path.");
559 ("set_append", (RErr, [OptString "append"]), -1, [FishAlias "append"],
561 "add options to kernel command line",
563 This function is used to add additional options to the
564 guest kernel command line.
566 The default is C<NULL> unless overridden by setting
567 C<LIBGUESTFS_APPEND> environment variable.
569 Setting C<append> to C<NULL> means I<no> additional options
570 are passed (libguestfs always adds a few of its own).");
572 ("get_append", (RConstOptString "append", []), -1, [],
573 (* This cannot be tested with the current framework. The
574 * function can return NULL in normal operations, which the
575 * test framework interprets as an error.
578 "get the additional kernel options",
580 Return the additional kernel options which are added to the
581 guest kernel command line.
583 If C<NULL> then no options are added.");
585 ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"],
589 If C<autosync> is true, this enables autosync. Libguestfs will make a
590 best effort attempt to run C<guestfs_umount_all> followed by
591 C<guestfs_sync> when the handle is closed
592 (also if the program exits without closing handles).
594 This is disabled by default (except in guestfish where it is
595 enabled by default).");
597 ("get_autosync", (RBool "autosync", []), -1, [],
598 [InitNone, Always, TestRun (
599 [["get_autosync"]])],
602 Get the autosync flag.");
604 ("set_verbose", (RErr, [Bool "verbose"]), -1, [FishAlias "verbose"],
608 If C<verbose> is true, this turns on verbose messages (to C<stderr>).
610 Verbose messages are disabled unless the environment variable
611 C<LIBGUESTFS_DEBUG> is defined and set to C<1>.");
613 ("get_verbose", (RBool "verbose", []), -1, [],
617 This returns the verbose messages flag.");
619 ("is_ready", (RBool "ready", []), -1, [],
620 [InitNone, Always, TestOutputTrue (
622 "is ready to accept commands",
624 This returns true iff this handle is ready to accept commands
625 (in the C<READY> state).
627 For more information on states, see L<guestfs(3)>.");
629 ("is_config", (RBool "config", []), -1, [],
630 [InitNone, Always, TestOutputFalse (
632 "is in configuration state",
634 This returns true iff this handle is being configured
635 (in the C<CONFIG> state).
637 For more information on states, see L<guestfs(3)>.");
639 ("is_launching", (RBool "launching", []), -1, [],
640 [InitNone, Always, TestOutputFalse (
641 [["is_launching"]])],
642 "is launching subprocess",
644 This returns true iff this handle is launching the subprocess
645 (in the C<LAUNCHING> state).
647 For more information on states, see L<guestfs(3)>.");
649 ("is_busy", (RBool "busy", []), -1, [],
650 [InitNone, Always, TestOutputFalse (
652 "is busy processing a command",
654 This returns true iff this handle is busy processing a command
655 (in the C<BUSY> state).
657 For more information on states, see L<guestfs(3)>.");
659 ("get_state", (RInt "state", []), -1, [],
661 "get the current state",
663 This returns the current state as an opaque integer. This is
664 only useful for printing debug and internal error messages.
666 For more information on states, see L<guestfs(3)>.");
668 ("set_busy", (RErr, []), -1, [NotInFish],
672 This sets the state to C<BUSY>. This is only used when implementing
673 actions using the low-level API.
675 For more information on states, see L<guestfs(3)>.");
677 ("set_ready", (RErr, []), -1, [NotInFish],
679 "set state to ready",
681 This sets the state to C<READY>. This is only used when implementing
682 actions using the low-level API.
684 For more information on states, see L<guestfs(3)>.");
686 ("end_busy", (RErr, []), -1, [NotInFish],
688 "leave the busy state",
690 This sets the state to C<READY>, or if in C<CONFIG> then it leaves the
691 state as is. This is only used when implementing
692 actions using the low-level API.
694 For more information on states, see L<guestfs(3)>.");
696 ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"],
697 [InitNone, Always, TestOutputInt (
698 [["set_memsize"; "500"];
699 ["get_memsize"]], 500)],
700 "set memory allocated to the qemu subprocess",
702 This sets the memory size in megabytes allocated to the
703 qemu subprocess. This only has any effect if called before
706 You can also change this by setting the environment
707 variable C<LIBGUESTFS_MEMSIZE> before the handle is
710 For more information on the architecture of libguestfs,
711 see L<guestfs(3)>.");
713 ("get_memsize", (RInt "memsize", []), -1, [],
714 [InitNone, Always, TestOutputIntOp (
715 [["get_memsize"]], ">=", 256)],
716 "get memory allocated to the qemu subprocess",
718 This gets the memory size in megabytes allocated to the
721 If C<guestfs_set_memsize> was not called
722 on this handle, and if C<LIBGUESTFS_MEMSIZE> was not set,
723 then this returns the compiled-in default value for memsize.
725 For more information on the architecture of libguestfs,
726 see L<guestfs(3)>.");
728 ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"],
729 [InitNone, Always, TestOutputIntOp (
730 [["get_pid"]], ">=", 1)],
731 "get PID of qemu subprocess",
733 Return the process ID of the qemu subprocess. If there is no
734 qemu subprocess, then this will return an error.
736 This is an internal call used for debugging and testing.");
738 ("version", (RStruct ("version", "version"), []), -1, [],
739 [InitNone, Always, TestOutputStruct (
740 [["version"]], [CompareWithInt ("major", 1)])],
741 "get the library version number",
743 Return the libguestfs version number that the program is linked
746 Note that because of dynamic linking this is not necessarily
747 the version of libguestfs that you compiled against. You can
748 compile the program, and then at runtime dynamically link
749 against a completely different C<libguestfs.so> library.
751 This call was added in version C<1.0.58>. In previous
752 versions of libguestfs there was no way to get the version
753 number. From C code you can use ELF weak linking tricks to find out if
754 this symbol exists (if it doesn't, then it's an earlier version).
756 The call returns a structure with four elements. The first
757 three (C<major>, C<minor> and C<release>) are numbers and
758 correspond to the usual version triplet. The fourth element
759 (C<extra>) is a string and is normally empty, but may be
760 used for distro-specific information.
762 To construct the original version string:
763 C<$major.$minor.$release$extra>
765 I<Note:> Don't use this call to test for availability
766 of features. Distro backports makes this unreliable.");
768 ("set_selinux", (RErr, [Bool "selinux"]), -1, [FishAlias "selinux"],
769 [InitNone, Always, TestOutputTrue (
770 [["set_selinux"; "true"];
772 "set SELinux enabled or disabled at appliance boot",
774 This sets the selinux flag that is passed to the appliance
775 at boot time. The default is C<selinux=0> (disabled).
777 Note that if SELinux is enabled, it is always in
778 Permissive mode (C<enforcing=0>).
780 For more information on the architecture of libguestfs,
781 see L<guestfs(3)>.");
783 ("get_selinux", (RBool "selinux", []), -1, [],
785 "get SELinux enabled flag",
787 This returns the current setting of the selinux flag which
788 is passed to the appliance at boot time. See C<guestfs_set_selinux>.
790 For more information on the architecture of libguestfs,
791 see L<guestfs(3)>.");
795 (* daemon_functions are any functions which cause some action
796 * to take place in the daemon.
799 let daemon_functions = [
800 ("mount", (RErr, [Device "device"; String "mountpoint"]), 1, [],
801 [InitEmpty, Always, TestOutput (
802 [["sfdiskM"; "/dev/sda"; ","];
803 ["mkfs"; "ext2"; "/dev/sda1"];
804 ["mount"; "/dev/sda1"; "/"];
805 ["write_file"; "/new"; "new file contents"; "0"];
806 ["cat"; "/new"]], "new file contents")],
807 "mount a guest disk at a position in the filesystem",
809 Mount a guest disk at a position in the filesystem. Block devices
810 are named C</dev/sda>, C</dev/sdb> and so on, as they were added to
811 the guest. If those block devices contain partitions, they will have
812 the usual names (eg. C</dev/sda1>). Also LVM C</dev/VG/LV>-style
815 The rules are the same as for L<mount(2)>: A filesystem must
816 first be mounted on C</> before others can be mounted. Other
817 filesystems can only be mounted on directories which already
820 The mounted filesystem is writable, if we have sufficient permissions
821 on the underlying device.
823 The filesystem options C<sync> and C<noatime> are set with this
824 call, in order to improve reliability.");
826 ("sync", (RErr, []), 2, [],
827 [ InitEmpty, Always, TestRun [["sync"]]],
828 "sync disks, writes are flushed through to the disk image",
830 This syncs the disk, so that any writes are flushed through to the
831 underlying disk image.
833 You should always call this if you have modified a disk image, before
834 closing the handle.");
836 ("touch", (RErr, [Pathname "path"]), 3, [],
837 [InitBasicFS, Always, TestOutputTrue (
839 ["exists"; "/new"]])],
840 "update file timestamps or create a new file",
842 Touch acts like the L<touch(1)> command. It can be used to
843 update the timestamps on a file, or, if the file does not exist,
844 to create a new zero-length file.");
846 ("cat", (RString "content", [Pathname "path"]), 4, [ProtocolLimitWarning],
847 [InitSquashFS, Always, TestOutput (
848 [["cat"; "/known-2"]], "abcdef\n")],
849 "list the contents of a file",
851 Return the contents of the file named C<path>.
853 Note that this function cannot correctly handle binary files
854 (specifically, files containing C<\\0> character which is treated
855 as end of string). For those you need to use the C<guestfs_read_file>
856 or C<guestfs_download> functions which have a more complex interface.");
858 ("ll", (RString "listing", [String "directory"]), 5, [],
859 [], (* XXX Tricky to test because it depends on the exact format
860 * of the 'ls -l' command, which changes between F10 and F11.
862 "list the files in a directory (long format)",
864 List the files in C<directory> (relative to the root directory,
865 there is no cwd) in the format of 'ls -la'.
867 This command is mostly useful for interactive sessions. It
868 is I<not> intended that you try to parse the output string.");
870 ("ls", (RStringList "listing", [String "directory"]), 6, [],
871 [InitBasicFS, Always, TestOutputList (
874 ["touch"; "/newest"];
875 ["ls"; "/"]], ["lost+found"; "new"; "newer"; "newest"])],
876 "list the files in a directory",
878 List the files in C<directory> (relative to the root directory,
879 there is no cwd). The '.' and '..' entries are not returned, but
880 hidden files are shown.
882 This command is mostly useful for interactive sessions. Programs
883 should probably use C<guestfs_readdir> instead.");
885 ("list_devices", (RStringList "devices", []), 7, [],
886 [InitEmpty, Always, TestOutputListOfDevices (
887 [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])],
888 "list the block devices",
890 List all the block devices.
892 The full block device names are returned, eg. C</dev/sda>");
894 ("list_partitions", (RStringList "partitions", []), 8, [],
895 [InitBasicFS, Always, TestOutputListOfDevices (
896 [["list_partitions"]], ["/dev/sda1"]);
897 InitEmpty, Always, TestOutputListOfDevices (
898 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
899 ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
900 "list the partitions",
902 List all the partitions detected on all block devices.
904 The full partition device names are returned, eg. C</dev/sda1>
906 This does not return logical volumes. For that you will need to
907 call C<guestfs_lvs>.");
909 ("pvs", (RStringList "physvols", []), 9, [],
910 [InitBasicFSonLVM, Always, TestOutputListOfDevices (
911 [["pvs"]], ["/dev/sda1"]);
912 InitEmpty, Always, TestOutputListOfDevices (
913 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
914 ["pvcreate"; "/dev/sda1"];
915 ["pvcreate"; "/dev/sda2"];
916 ["pvcreate"; "/dev/sda3"];
917 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
918 "list the LVM physical volumes (PVs)",
920 List all the physical volumes detected. This is the equivalent
921 of the L<pvs(8)> command.
923 This returns a list of just the device names that contain
924 PVs (eg. C</dev/sda2>).
926 See also C<guestfs_pvs_full>.");
928 ("vgs", (RStringList "volgroups", []), 10, [],
929 [InitBasicFSonLVM, Always, TestOutputList (
931 InitEmpty, Always, TestOutputList (
932 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
933 ["pvcreate"; "/dev/sda1"];
934 ["pvcreate"; "/dev/sda2"];
935 ["pvcreate"; "/dev/sda3"];
936 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
937 ["vgcreate"; "VG2"; "/dev/sda3"];
938 ["vgs"]], ["VG1"; "VG2"])],
939 "list the LVM volume groups (VGs)",
941 List all the volumes groups detected. This is the equivalent
942 of the L<vgs(8)> command.
944 This returns a list of just the volume group names that were
945 detected (eg. C<VolGroup00>).
947 See also C<guestfs_vgs_full>.");
949 ("lvs", (RStringList "logvols", []), 11, [],
950 [InitBasicFSonLVM, Always, TestOutputList (
951 [["lvs"]], ["/dev/VG/LV"]);
952 InitEmpty, Always, TestOutputList (
953 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
954 ["pvcreate"; "/dev/sda1"];
955 ["pvcreate"; "/dev/sda2"];
956 ["pvcreate"; "/dev/sda3"];
957 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
958 ["vgcreate"; "VG2"; "/dev/sda3"];
959 ["lvcreate"; "LV1"; "VG1"; "50"];
960 ["lvcreate"; "LV2"; "VG1"; "50"];
961 ["lvcreate"; "LV3"; "VG2"; "50"];
962 ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])],
963 "list the LVM logical volumes (LVs)",
965 List all the logical volumes detected. This is the equivalent
966 of the L<lvs(8)> command.
968 This returns a list of the logical volume device names
969 (eg. C</dev/VolGroup00/LogVol00>).
971 See also C<guestfs_lvs_full>.");
973 ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [],
974 [], (* XXX how to test? *)
975 "list the LVM physical volumes (PVs)",
977 List all the physical volumes detected. This is the equivalent
978 of the L<pvs(8)> command. The \"full\" version includes all fields.");
980 ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [],
981 [], (* XXX how to test? *)
982 "list the LVM volume groups (VGs)",
984 List all the volumes groups detected. This is the equivalent
985 of the L<vgs(8)> command. The \"full\" version includes all fields.");
987 ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [],
988 [], (* XXX how to test? *)
989 "list the LVM logical volumes (LVs)",
991 List all the logical volumes detected. This is the equivalent
992 of the L<lvs(8)> command. The \"full\" version includes all fields.");
994 ("read_lines", (RStringList "lines", [Pathname "path"]), 15, [],
995 [InitSquashFS, Always, TestOutputList (
996 [["read_lines"; "/known-4"]], ["abc"; "def"; "ghi"]);
997 InitSquashFS, Always, TestOutputList (
998 [["read_lines"; "/empty"]], [])],
999 "read file as lines",
1001 Return the contents of the file named C<path>.
1003 The file contents are returned as a list of lines. Trailing
1004 C<LF> and C<CRLF> character sequences are I<not> returned.
1006 Note that this function cannot correctly handle binary files
1007 (specifically, files containing C<\\0> character which is treated
1008 as end of line). For those you need to use the C<guestfs_read_file>
1009 function which has a more complex interface.");
1011 ("aug_init", (RErr, [Pathname "root"; Int "flags"]), 16, [],
1012 [], (* XXX Augeas code needs tests. *)
1013 "create a new Augeas handle",
1015 Create a new Augeas handle for editing configuration files.
1016 If there was any previous Augeas handle associated with this
1017 guestfs session, then it is closed.
1019 You must call this before using any other C<guestfs_aug_*>
1022 C<root> is the filesystem root. C<root> must not be NULL,
1025 The flags are the same as the flags defined in
1026 E<lt>augeas.hE<gt>, the logical I<or> of the following
1031 =item C<AUG_SAVE_BACKUP> = 1
1033 Keep the original file with a C<.augsave> extension.
1035 =item C<AUG_SAVE_NEWFILE> = 2
1037 Save changes into a file with extension C<.augnew>, and
1038 do not overwrite original. Overrides C<AUG_SAVE_BACKUP>.
1040 =item C<AUG_TYPE_CHECK> = 4
1042 Typecheck lenses (can be expensive).
1044 =item C<AUG_NO_STDINC> = 8
1046 Do not use standard load path for modules.
1048 =item C<AUG_SAVE_NOOP> = 16
1050 Make save a no-op, just record what would have been changed.
1052 =item C<AUG_NO_LOAD> = 32
1054 Do not load the tree in C<guestfs_aug_init>.
1058 To close the handle, you can call C<guestfs_aug_close>.
1060 To find out more about Augeas, see L<http://augeas.net/>.");
1062 ("aug_close", (RErr, []), 26, [],
1063 [], (* XXX Augeas code needs tests. *)
1064 "close the current Augeas handle",
1066 Close the current Augeas handle and free up any resources
1067 used by it. After calling this, you have to call
1068 C<guestfs_aug_init> again before you can use any other
1069 Augeas functions.");
1071 ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [],
1072 [], (* XXX Augeas code needs tests. *)
1073 "define an Augeas variable",
1075 Defines an Augeas variable C<name> whose value is the result
1076 of evaluating C<expr>. If C<expr> is NULL, then C<name> is
1079 On success this returns the number of nodes in C<expr>, or
1080 C<0> if C<expr> evaluates to something which is not a nodeset.");
1082 ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [],
1083 [], (* XXX Augeas code needs tests. *)
1084 "define an Augeas node",
1086 Defines a variable C<name> whose value is the result of
1089 If C<expr> evaluates to an empty nodeset, a node is created,
1090 equivalent to calling C<guestfs_aug_set> C<expr>, C<value>.
1091 C<name> will be the nodeset containing that single node.
1093 On success this returns a pair containing the
1094 number of nodes in the nodeset, and a boolean flag
1095 if a node was created.");
1097 ("aug_get", (RString "val", [String "augpath"]), 19, [],
1098 [], (* XXX Augeas code needs tests. *)
1099 "look up the value of an Augeas path",
1101 Look up the value associated with C<path>. If C<path>
1102 matches exactly one node, the C<value> is returned.");
1104 ("aug_set", (RErr, [String "augpath"; String "val"]), 20, [],
1105 [], (* XXX Augeas code needs tests. *)
1106 "set Augeas path to value",
1108 Set the value associated with C<path> to C<value>.");
1110 ("aug_insert", (RErr, [String "augpath"; String "label"; Bool "before"]), 21, [],
1111 [], (* XXX Augeas code needs tests. *)
1112 "insert a sibling Augeas node",
1114 Create a new sibling C<label> for C<path>, inserting it into
1115 the tree before or after C<path> (depending on the boolean
1118 C<path> must match exactly one existing node in the tree, and
1119 C<label> must be a label, ie. not contain C</>, C<*> or end
1120 with a bracketed index C<[N]>.");
1122 ("aug_rm", (RInt "nrnodes", [String "augpath"]), 22, [],
1123 [], (* XXX Augeas code needs tests. *)
1124 "remove an Augeas path",
1126 Remove C<path> and all of its children.
1128 On success this returns the number of entries which were removed.");
1130 ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [],
1131 [], (* XXX Augeas code needs tests. *)
1134 Move the node C<src> to C<dest>. C<src> must match exactly
1135 one node. C<dest> is overwritten if it exists.");
1137 ("aug_match", (RStringList "matches", [String "augpath"]), 24, [],
1138 [], (* XXX Augeas code needs tests. *)
1139 "return Augeas nodes which match augpath",
1141 Returns a list of paths which match the path expression C<path>.
1142 The returned paths are sufficiently qualified so that they match
1143 exactly one node in the current tree.");
1145 ("aug_save", (RErr, []), 25, [],
1146 [], (* XXX Augeas code needs tests. *)
1147 "write all pending Augeas changes to disk",
1149 This writes all pending changes to disk.
1151 The flags which were passed to C<guestfs_aug_init> affect exactly
1152 how files are saved.");
1154 ("aug_load", (RErr, []), 27, [],
1155 [], (* XXX Augeas code needs tests. *)
1156 "load files into the tree",
1158 Load files into the tree.
1160 See C<aug_load> in the Augeas documentation for the full gory
1163 ("aug_ls", (RStringList "matches", [String "augpath"]), 28, [],
1164 [], (* XXX Augeas code needs tests. *)
1165 "list Augeas nodes under augpath",
1167 This is just a shortcut for listing C<guestfs_aug_match>
1168 C<path/*> and sorting the resulting nodes into alphabetical order.");
1170 ("rm", (RErr, [Pathname "path"]), 29, [],
1171 [InitBasicFS, Always, TestRun
1174 InitBasicFS, Always, TestLastFail
1176 InitBasicFS, Always, TestLastFail
1181 Remove the single file C<path>.");
1183 ("rmdir", (RErr, [Pathname "path"]), 30, [],
1184 [InitBasicFS, Always, TestRun
1187 InitBasicFS, Always, TestLastFail
1188 [["rmdir"; "/new"]];
1189 InitBasicFS, Always, TestLastFail
1191 ["rmdir"; "/new"]]],
1192 "remove a directory",
1194 Remove the single directory C<path>.");
1196 ("rm_rf", (RErr, [Pathname "path"]), 31, [],
1197 [InitBasicFS, Always, TestOutputFalse
1199 ["mkdir"; "/new/foo"];
1200 ["touch"; "/new/foo/bar"];
1202 ["exists"; "/new"]]],
1203 "remove a file or directory recursively",
1205 Remove the file or directory C<path>, recursively removing the
1206 contents if its a directory. This is like the C<rm -rf> shell
1209 ("mkdir", (RErr, [Pathname "path"]), 32, [],
1210 [InitBasicFS, Always, TestOutputTrue
1212 ["is_dir"; "/new"]];
1213 InitBasicFS, Always, TestLastFail
1214 [["mkdir"; "/new/foo/bar"]]],
1215 "create a directory",
1217 Create a directory named C<path>.");
1219 ("mkdir_p", (RErr, [Pathname "path"]), 33, [],
1220 [InitBasicFS, Always, TestOutputTrue
1221 [["mkdir_p"; "/new/foo/bar"];
1222 ["is_dir"; "/new/foo/bar"]];
1223 InitBasicFS, Always, TestOutputTrue
1224 [["mkdir_p"; "/new/foo/bar"];
1225 ["is_dir"; "/new/foo"]];
1226 InitBasicFS, Always, TestOutputTrue
1227 [["mkdir_p"; "/new/foo/bar"];
1228 ["is_dir"; "/new"]];
1229 (* Regression tests for RHBZ#503133: *)
1230 InitBasicFS, Always, TestRun
1232 ["mkdir_p"; "/new"]];
1233 InitBasicFS, Always, TestLastFail
1235 ["mkdir_p"; "/new"]]],
1236 "create a directory and parents",
1238 Create a directory named C<path>, creating any parent directories
1239 as necessary. This is like the C<mkdir -p> shell command.");
1241 ("chmod", (RErr, [Int "mode"; Pathname "path"]), 34, [],
1242 [], (* XXX Need stat command to test *)
1245 Change the mode (permissions) of C<path> to C<mode>. Only
1246 numeric modes are supported.");
1248 ("chown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 35, [],
1249 [], (* XXX Need stat command to test *)
1250 "change file owner and group",
1252 Change the file owner to C<owner> and group to C<group>.
1254 Only numeric uid and gid are supported. If you want to use
1255 names, you will need to locate and parse the password file
1256 yourself (Augeas support makes this relatively easy).");
1258 ("exists", (RBool "existsflag", [Pathname "path"]), 36, [],
1259 [InitSquashFS, Always, TestOutputTrue (
1260 [["exists"; "/empty"]]);
1261 InitSquashFS, Always, TestOutputTrue (
1262 [["exists"; "/directory"]])],
1263 "test if file or directory exists",
1265 This returns C<true> if and only if there is a file, directory
1266 (or anything) with the given C<path> name.
1268 See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>.");
1270 ("is_file", (RBool "fileflag", [Pathname "path"]), 37, [],
1271 [InitSquashFS, Always, TestOutputTrue (
1272 [["is_file"; "/known-1"]]);
1273 InitSquashFS, Always, TestOutputFalse (
1274 [["is_file"; "/directory"]])],
1275 "test if file exists",
1277 This returns C<true> if and only if there is a file
1278 with the given C<path> name. Note that it returns false for
1279 other objects like directories.
1281 See also C<guestfs_stat>.");
1283 ("is_dir", (RBool "dirflag", [Pathname "path"]), 38, [],
1284 [InitSquashFS, Always, TestOutputFalse (
1285 [["is_dir"; "/known-3"]]);
1286 InitSquashFS, Always, TestOutputTrue (
1287 [["is_dir"; "/directory"]])],
1288 "test if file exists",
1290 This returns C<true> if and only if there is a directory
1291 with the given C<path> name. Note that it returns false for
1292 other objects like files.
1294 See also C<guestfs_stat>.");
1296 ("pvcreate", (RErr, [Device "device"]), 39, [],
1297 [InitEmpty, Always, TestOutputListOfDevices (
1298 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1299 ["pvcreate"; "/dev/sda1"];
1300 ["pvcreate"; "/dev/sda2"];
1301 ["pvcreate"; "/dev/sda3"];
1302 ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])],
1303 "create an LVM physical volume",
1305 This creates an LVM physical volume on the named C<device>,
1306 where C<device> should usually be a partition name such
1309 ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [],
1310 [InitEmpty, Always, TestOutputList (
1311 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1312 ["pvcreate"; "/dev/sda1"];
1313 ["pvcreate"; "/dev/sda2"];
1314 ["pvcreate"; "/dev/sda3"];
1315 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1316 ["vgcreate"; "VG2"; "/dev/sda3"];
1317 ["vgs"]], ["VG1"; "VG2"])],
1318 "create an LVM volume group",
1320 This creates an LVM volume group called C<volgroup>
1321 from the non-empty list of physical volumes C<physvols>.");
1323 ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [],
1324 [InitEmpty, Always, TestOutputList (
1325 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1326 ["pvcreate"; "/dev/sda1"];
1327 ["pvcreate"; "/dev/sda2"];
1328 ["pvcreate"; "/dev/sda3"];
1329 ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"];
1330 ["vgcreate"; "VG2"; "/dev/sda3"];
1331 ["lvcreate"; "LV1"; "VG1"; "50"];
1332 ["lvcreate"; "LV2"; "VG1"; "50"];
1333 ["lvcreate"; "LV3"; "VG2"; "50"];
1334 ["lvcreate"; "LV4"; "VG2"; "50"];
1335 ["lvcreate"; "LV5"; "VG2"; "50"];
1337 ["/dev/VG1/LV1"; "/dev/VG1/LV2";
1338 "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])],
1339 "create an LVM volume group",
1341 This creates an LVM volume group called C<logvol>
1342 on the volume group C<volgroup>, with C<size> megabytes.");
1344 ("mkfs", (RErr, [String "fstype"; Device "device"]), 42, [],
1345 [InitEmpty, Always, TestOutput (
1346 [["sfdiskM"; "/dev/sda"; ","];
1347 ["mkfs"; "ext2"; "/dev/sda1"];
1348 ["mount"; "/dev/sda1"; "/"];
1349 ["write_file"; "/new"; "new file contents"; "0"];
1350 ["cat"; "/new"]], "new file contents")],
1351 "make a filesystem",
1353 This creates a filesystem on C<device> (usually a partition
1354 or LVM logical volume). The filesystem type is C<fstype>, for
1357 ("sfdisk", (RErr, [Device "device";
1358 Int "cyls"; Int "heads"; Int "sectors";
1359 StringList "lines"]), 43, [DangerWillRobinson],
1361 "create partitions on a block device",
1363 This is a direct interface to the L<sfdisk(8)> program for creating
1364 partitions on block devices.
1366 C<device> should be a block device, for example C</dev/sda>.
1368 C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads
1369 and sectors on the device, which are passed directly to sfdisk as
1370 the I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any
1371 of these, then the corresponding parameter is omitted. Usually for
1372 'large' disks, you can just pass C<0> for these, but for small
1373 (floppy-sized) disks, sfdisk (or rather, the kernel) cannot work
1374 out the right geometry and you will need to tell it.
1376 C<lines> is a list of lines that we feed to C<sfdisk>. For more
1377 information refer to the L<sfdisk(8)> manpage.
1379 To create a single partition occupying the whole disk, you would
1380 pass C<lines> as a single element list, when the single element being
1381 the string C<,> (comma).
1383 See also: C<guestfs_sfdisk_l>, C<guestfs_sfdisk_N>");
1385 ("write_file", (RErr, [Pathname "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning],
1386 [InitBasicFS, Always, TestOutput (
1387 [["write_file"; "/new"; "new file contents"; "0"];
1388 ["cat"; "/new"]], "new file contents");
1389 InitBasicFS, Always, TestOutput (
1390 [["write_file"; "/new"; "\nnew file contents\n"; "0"];
1391 ["cat"; "/new"]], "\nnew file contents\n");
1392 InitBasicFS, Always, TestOutput (
1393 [["write_file"; "/new"; "\n\n"; "0"];
1394 ["cat"; "/new"]], "\n\n");
1395 InitBasicFS, Always, TestOutput (
1396 [["write_file"; "/new"; ""; "0"];
1397 ["cat"; "/new"]], "");
1398 InitBasicFS, Always, TestOutput (
1399 [["write_file"; "/new"; "\n\n\n"; "0"];
1400 ["cat"; "/new"]], "\n\n\n");
1401 InitBasicFS, Always, TestOutput (
1402 [["write_file"; "/new"; "\n"; "0"];
1403 ["cat"; "/new"]], "\n")],
1406 This call creates a file called C<path>. The contents of the
1407 file is the string C<content> (which can contain any 8 bit data),
1408 with length C<size>.
1410 As a special case, if C<size> is C<0>
1411 then the length is calculated using C<strlen> (so in this case
1412 the content cannot contain embedded ASCII NULs).
1414 I<NB.> Owing to a bug, writing content containing ASCII NUL
1415 characters does I<not> work, even if the length is specified.
1416 We hope to resolve this bug in a future version. In the meantime
1417 use C<guestfs_upload>.");
1419 ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"],
1420 [InitEmpty, Always, TestOutputListOfDevices (
1421 [["sfdiskM"; "/dev/sda"; ","];
1422 ["mkfs"; "ext2"; "/dev/sda1"];
1423 ["mount"; "/dev/sda1"; "/"];
1424 ["mounts"]], ["/dev/sda1"]);
1425 InitEmpty, Always, TestOutputList (
1426 [["sfdiskM"; "/dev/sda"; ","];
1427 ["mkfs"; "ext2"; "/dev/sda1"];
1428 ["mount"; "/dev/sda1"; "/"];
1431 "unmount a filesystem",
1433 This unmounts the given filesystem. The filesystem may be
1434 specified either by its mountpoint (path) or the device which
1435 contains the filesystem.");
1437 ("mounts", (RStringList "devices", []), 46, [],
1438 [InitBasicFS, Always, TestOutputListOfDevices (
1439 [["mounts"]], ["/dev/sda1"])],
1440 "show mounted filesystems",
1442 This returns the list of currently mounted filesystems. It returns
1443 the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).
1445 Some internal mounts are not shown.
1447 See also: C<guestfs_mountpoints>");
1449 ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"],
1450 [InitBasicFS, Always, TestOutputList (
1453 (* check that umount_all can unmount nested mounts correctly: *)
1454 InitEmpty, Always, TestOutputList (
1455 [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"];
1456 ["mkfs"; "ext2"; "/dev/sda1"];
1457 ["mkfs"; "ext2"; "/dev/sda2"];
1458 ["mkfs"; "ext2"; "/dev/sda3"];
1459 ["mount"; "/dev/sda1"; "/"];
1461 ["mount"; "/dev/sda2"; "/mp1"];
1462 ["mkdir"; "/mp1/mp2"];
1463 ["mount"; "/dev/sda3"; "/mp1/mp2"];
1464 ["mkdir"; "/mp1/mp2/mp3"];
1467 "unmount all filesystems",
1469 This unmounts all mounted filesystems.
1471 Some internal mounts are not unmounted by this call.");
1473 ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson],
1475 "remove all LVM LVs, VGs and PVs",
1477 This command removes all LVM logical volumes, volume groups
1478 and physical volumes.");
1480 ("file", (RString "description", [Pathname "path"]), 49, [],
1481 [InitSquashFS, Always, TestOutput (
1482 [["file"; "/empty"]], "empty");
1483 InitSquashFS, Always, TestOutput (
1484 [["file"; "/known-1"]], "ASCII text");
1485 InitSquashFS, Always, TestLastFail (
1486 [["file"; "/notexists"]])],
1487 "determine file type",
1489 This call uses the standard L<file(1)> command to determine
1490 the type or contents of the file. This also works on devices,
1491 for example to find out whether a partition contains a filesystem.
1493 This call will also transparently look inside various types
1496 The exact command which runs is C<file -zbsL path>. Note in
1497 particular that the filename is not prepended to the output
1498 (the C<-b> option).");
1500 ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning],
1501 [InitBasicFS, Always, TestOutput (
1502 [["upload"; "test-command"; "/test-command"];
1503 ["chmod"; "0o755"; "/test-command"];
1504 ["command"; "/test-command 1"]], "Result1");
1505 InitBasicFS, Always, TestOutput (
1506 [["upload"; "test-command"; "/test-command"];
1507 ["chmod"; "0o755"; "/test-command"];
1508 ["command"; "/test-command 2"]], "Result2\n");
1509 InitBasicFS, Always, TestOutput (
1510 [["upload"; "test-command"; "/test-command"];
1511 ["chmod"; "0o755"; "/test-command"];
1512 ["command"; "/test-command 3"]], "\nResult3");
1513 InitBasicFS, Always, TestOutput (
1514 [["upload"; "test-command"; "/test-command"];
1515 ["chmod"; "0o755"; "/test-command"];
1516 ["command"; "/test-command 4"]], "\nResult4\n");
1517 InitBasicFS, Always, TestOutput (
1518 [["upload"; "test-command"; "/test-command"];
1519 ["chmod"; "0o755"; "/test-command"];
1520 ["command"; "/test-command 5"]], "\nResult5\n\n");
1521 InitBasicFS, Always, TestOutput (
1522 [["upload"; "test-command"; "/test-command"];
1523 ["chmod"; "0o755"; "/test-command"];
1524 ["command"; "/test-command 6"]], "\n\nResult6\n\n");
1525 InitBasicFS, Always, TestOutput (
1526 [["upload"; "test-command"; "/test-command"];
1527 ["chmod"; "0o755"; "/test-command"];
1528 ["command"; "/test-command 7"]], "");
1529 InitBasicFS, Always, TestOutput (
1530 [["upload"; "test-command"; "/test-command"];
1531 ["chmod"; "0o755"; "/test-command"];
1532 ["command"; "/test-command 8"]], "\n");
1533 InitBasicFS, Always, TestOutput (
1534 [["upload"; "test-command"; "/test-command"];
1535 ["chmod"; "0o755"; "/test-command"];
1536 ["command"; "/test-command 9"]], "\n\n");
1537 InitBasicFS, Always, TestOutput (
1538 [["upload"; "test-command"; "/test-command"];
1539 ["chmod"; "0o755"; "/test-command"];
1540 ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n");
1541 InitBasicFS, Always, TestOutput (
1542 [["upload"; "test-command"; "/test-command"];
1543 ["chmod"; "0o755"; "/test-command"];
1544 ["command"; "/test-command 11"]], "Result11-1\nResult11-2");
1545 InitBasicFS, Always, TestLastFail (
1546 [["upload"; "test-command"; "/test-command"];
1547 ["chmod"; "0o755"; "/test-command"];
1548 ["command"; "/test-command"]])],
1549 "run a command from the guest filesystem",
1551 This call runs a command from the guest filesystem. The
1552 filesystem must be mounted, and must contain a compatible
1553 operating system (ie. something Linux, with the same
1554 or compatible processor architecture).
1556 The single parameter is an argv-style list of arguments.
1557 The first element is the name of the program to run.
1558 Subsequent elements are parameters. The list must be
1559 non-empty (ie. must contain a program name). Note that
1560 the command runs directly, and is I<not> invoked via
1561 the shell (see C<guestfs_sh>).
1563 The return value is anything printed to I<stdout> by
1566 If the command returns a non-zero exit status, then
1567 this function returns an error message. The error message
1568 string is the content of I<stderr> from the command.
1570 The C<$PATH> environment variable will contain at least
1571 C</usr/bin> and C</bin>. If you require a program from
1572 another location, you should provide the full path in the
1575 Shared libraries and data files required by the program
1576 must be available on filesystems which are mounted in the
1577 correct places. It is the caller's responsibility to ensure
1578 all filesystems that are needed are mounted at the right
1581 ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning],
1582 [InitBasicFS, Always, TestOutputList (
1583 [["upload"; "test-command"; "/test-command"];
1584 ["chmod"; "0o755"; "/test-command"];
1585 ["command_lines"; "/test-command 1"]], ["Result1"]);
1586 InitBasicFS, Always, TestOutputList (
1587 [["upload"; "test-command"; "/test-command"];
1588 ["chmod"; "0o755"; "/test-command"];
1589 ["command_lines"; "/test-command 2"]], ["Result2"]);
1590 InitBasicFS, Always, TestOutputList (
1591 [["upload"; "test-command"; "/test-command"];
1592 ["chmod"; "0o755"; "/test-command"];
1593 ["command_lines"; "/test-command 3"]], ["";"Result3"]);
1594 InitBasicFS, Always, TestOutputList (
1595 [["upload"; "test-command"; "/test-command"];
1596 ["chmod"; "0o755"; "/test-command"];
1597 ["command_lines"; "/test-command 4"]], ["";"Result4"]);
1598 InitBasicFS, Always, TestOutputList (
1599 [["upload"; "test-command"; "/test-command"];
1600 ["chmod"; "0o755"; "/test-command"];
1601 ["command_lines"; "/test-command 5"]], ["";"Result5";""]);
1602 InitBasicFS, Always, TestOutputList (
1603 [["upload"; "test-command"; "/test-command"];
1604 ["chmod"; "0o755"; "/test-command"];
1605 ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]);
1606 InitBasicFS, Always, TestOutputList (
1607 [["upload"; "test-command"; "/test-command"];
1608 ["chmod"; "0o755"; "/test-command"];
1609 ["command_lines"; "/test-command 7"]], []);
1610 InitBasicFS, Always, TestOutputList (
1611 [["upload"; "test-command"; "/test-command"];
1612 ["chmod"; "0o755"; "/test-command"];
1613 ["command_lines"; "/test-command 8"]], [""]);
1614 InitBasicFS, Always, TestOutputList (
1615 [["upload"; "test-command"; "/test-command"];
1616 ["chmod"; "0o755"; "/test-command"];
1617 ["command_lines"; "/test-command 9"]], ["";""]);
1618 InitBasicFS, Always, TestOutputList (
1619 [["upload"; "test-command"; "/test-command"];
1620 ["chmod"; "0o755"; "/test-command"];
1621 ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]);
1622 InitBasicFS, Always, TestOutputList (
1623 [["upload"; "test-command"; "/test-command"];
1624 ["chmod"; "0o755"; "/test-command"];
1625 ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])],
1626 "run a command, returning lines",
1628 This is the same as C<guestfs_command>, but splits the
1629 result into a list of lines.
1631 See also: C<guestfs_sh_lines>");
1633 ("stat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 52, [],
1634 [InitSquashFS, Always, TestOutputStruct (
1635 [["stat"; "/empty"]], [CompareWithInt ("size", 0)])],
1636 "get file information",
1638 Returns file information for the given C<path>.
1640 This is the same as the C<stat(2)> system call.");
1642 ("lstat", (RStruct ("statbuf", "stat"), [Pathname "path"]), 53, [],
1643 [InitSquashFS, Always, TestOutputStruct (
1644 [["lstat"; "/empty"]], [CompareWithInt ("size", 0)])],
1645 "get file information for a symbolic link",
1647 Returns file information for the given C<path>.
1649 This is the same as C<guestfs_stat> except that if C<path>
1650 is a symbolic link, then the link is stat-ed, not the file it
1653 This is the same as the C<lstat(2)> system call.");
1655 ("statvfs", (RStruct ("statbuf", "statvfs"), [Pathname "path"]), 54, [],
1656 [InitSquashFS, Always, TestOutputStruct (
1657 [["statvfs"; "/"]], [CompareWithInt ("namemax", 256)])],
1658 "get file system statistics",
1660 Returns file system statistics for any mounted file system.
1661 C<path> should be a file or directory in the mounted file system
1662 (typically it is the mount point itself, but it doesn't need to be).
1664 This is the same as the C<statvfs(2)> system call.");
1666 ("tune2fs_l", (RHashtable "superblock", [Device "device"]), 55, [],
1668 "get ext2/ext3/ext4 superblock details",
1670 This returns the contents of the ext2, ext3 or ext4 filesystem
1671 superblock on C<device>.
1673 It is the same as running C<tune2fs -l device>. See L<tune2fs(8)>
1674 manpage for more details. The list of fields returned isn't
1675 clearly defined, and depends on both the version of C<tune2fs>
1676 that libguestfs was built against, and the filesystem itself.");
1678 ("blockdev_setro", (RErr, [Device "device"]), 56, [],
1679 [InitEmpty, Always, TestOutputTrue (
1680 [["blockdev_setro"; "/dev/sda"];
1681 ["blockdev_getro"; "/dev/sda"]])],
1682 "set block device to read-only",
1684 Sets the block device named C<device> to read-only.
1686 This uses the L<blockdev(8)> command.");
1688 ("blockdev_setrw", (RErr, [Device "device"]), 57, [],
1689 [InitEmpty, Always, TestOutputFalse (
1690 [["blockdev_setrw"; "/dev/sda"];
1691 ["blockdev_getro"; "/dev/sda"]])],
1692 "set block device to read-write",
1694 Sets the block device named C<device> to read-write.
1696 This uses the L<blockdev(8)> command.");
1698 ("blockdev_getro", (RBool "ro", [Device "device"]), 58, [],
1699 [InitEmpty, Always, TestOutputTrue (
1700 [["blockdev_setro"; "/dev/sda"];
1701 ["blockdev_getro"; "/dev/sda"]])],
1702 "is block device set to read-only",
1704 Returns a boolean indicating if the block device is read-only
1705 (true if read-only, false if not).
1707 This uses the L<blockdev(8)> command.");
1709 ("blockdev_getss", (RInt "sectorsize", [Device "device"]), 59, [],
1710 [InitEmpty, Always, TestOutputInt (
1711 [["blockdev_getss"; "/dev/sda"]], 512)],
1712 "get sectorsize of block device",
1714 This returns the size of sectors on a block device.
1715 Usually 512, but can be larger for modern devices.
1717 (Note, this is not the size in sectors, use C<guestfs_blockdev_getsz>
1720 This uses the L<blockdev(8)> command.");
1722 ("blockdev_getbsz", (RInt "blocksize", [Device "device"]), 60, [],
1723 [InitEmpty, Always, TestOutputInt (
1724 [["blockdev_getbsz"; "/dev/sda"]], 4096)],
1725 "get blocksize of block device",
1727 This returns the block size of a device.
1729 (Note this is different from both I<size in blocks> and
1730 I<filesystem block size>).
1732 This uses the L<blockdev(8)> command.");
1734 ("blockdev_setbsz", (RErr, [Device "device"; Int "blocksize"]), 61, [],
1736 "set blocksize of block device",
1738 This sets the block size of a device.
1740 (Note this is different from both I<size in blocks> and
1741 I<filesystem block size>).
1743 This uses the L<blockdev(8)> command.");
1745 ("blockdev_getsz", (RInt64 "sizeinsectors", [Device "device"]), 62, [],
1746 [InitEmpty, Always, TestOutputInt (
1747 [["blockdev_getsz"; "/dev/sda"]], 1024000)],
1748 "get total size of device in 512-byte sectors",
1750 This returns the size of the device in units of 512-byte sectors
1751 (even if the sectorsize isn't 512 bytes ... weird).
1753 See also C<guestfs_blockdev_getss> for the real sector size of
1754 the device, and C<guestfs_blockdev_getsize64> for the more
1755 useful I<size in bytes>.
1757 This uses the L<blockdev(8)> command.");
1759 ("blockdev_getsize64", (RInt64 "sizeinbytes", [Device "device"]), 63, [],
1760 [InitEmpty, Always, TestOutputInt (
1761 [["blockdev_getsize64"; "/dev/sda"]], 524288000)],
1762 "get total size of device in bytes",
1764 This returns the size of the device in bytes.
1766 See also C<guestfs_blockdev_getsz>.
1768 This uses the L<blockdev(8)> command.");
1770 ("blockdev_flushbufs", (RErr, [Device "device"]), 64, [],
1771 [InitEmpty, Always, TestRun
1772 [["blockdev_flushbufs"; "/dev/sda"]]],
1773 "flush device buffers",
1775 This tells the kernel to flush internal buffers associated
1778 This uses the L<blockdev(8)> command.");
1780 ("blockdev_rereadpt", (RErr, [Device "device"]), 65, [],
1781 [InitEmpty, Always, TestRun
1782 [["blockdev_rereadpt"; "/dev/sda"]]],
1783 "reread partition table",
1785 Reread the partition table on C<device>.
1787 This uses the L<blockdev(8)> command.");
1789 ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
1790 [InitBasicFS, Always, TestOutput (
1791 (* Pick a file from cwd which isn't likely to change. *)
1792 [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1793 ["checksum"; "md5"; "/COPYING.LIB"]],
1794 Digest.to_hex (Digest.file "COPYING.LIB"))],
1795 "upload a file from the local machine",
1797 Upload local file C<filename> to C<remotefilename> on the
1800 C<filename> can also be a named pipe.
1802 See also C<guestfs_download>.");
1804 ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
1805 [InitBasicFS, Always, TestOutput (
1806 (* Pick a file from cwd which isn't likely to change. *)
1807 [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
1808 ["download"; "/COPYING.LIB"; "testdownload.tmp"];
1809 ["upload"; "testdownload.tmp"; "/upload"];
1810 ["checksum"; "md5"; "/upload"]],
1811 Digest.to_hex (Digest.file "COPYING.LIB"))],
1812 "download a file to the local machine",
1814 Download file C<remotefilename> and save it as C<filename>
1815 on the local machine.
1817 C<filename> can also be a named pipe.
1819 See also C<guestfs_upload>, C<guestfs_cat>.");
1821 ("checksum", (RString "checksum", [String "csumtype"; Pathname "path"]), 68, [],
1822 [InitSquashFS, Always, TestOutput (
1823 [["checksum"; "crc"; "/known-3"]], "2891671662");
1824 InitSquashFS, Always, TestLastFail (
1825 [["checksum"; "crc"; "/notexists"]]);
1826 InitSquashFS, Always, TestOutput (
1827 [["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c");
1828 InitSquashFS, Always, TestOutput (
1829 [["checksum"; "sha1"; "/known-3"]], "b7ebccc3ee418311091c3eda0a45b83c0a770f15");
1830 InitSquashFS, Always, TestOutput (
1831 [["checksum"; "sha224"; "/known-3"]], "d2cd1774b28f3659c14116be0a6dc2bb5c4b350ce9cd5defac707741");
1832 InitSquashFS, Always, TestOutput (
1833 [["checksum"; "sha256"; "/known-3"]], "75bb71b90cd20cb13f86d2bea8dad63ac7194e7517c3b52b8d06ff52d3487d30");
1834 InitSquashFS, Always, TestOutput (
1835 [["checksum"; "sha384"; "/known-3"]], "5fa7883430f357b5d7b7271d3a1d2872b51d73cba72731de6863d3dea55f30646af2799bef44d5ea776a5ec7941ac640");
1836 InitSquashFS, Always, TestOutput (
1837 [["checksum"; "sha512"; "/known-3"]], "2794062c328c6b216dca90443b7f7134c5f40e56bd0ed7853123275a09982a6f992e6ca682f9d2fba34a4c5e870d8fe077694ff831e3032a004ee077e00603f6")],
1838 "compute MD5, SHAx or CRC checksum of file",
1840 This call computes the MD5, SHAx or CRC checksum of the
1843 The type of checksum to compute is given by the C<csumtype>
1844 parameter which must have one of the following values:
1850 Compute the cyclic redundancy check (CRC) specified by POSIX
1851 for the C<cksum> command.
1855 Compute the MD5 hash (using the C<md5sum> program).
1859 Compute the SHA1 hash (using the C<sha1sum> program).
1863 Compute the SHA224 hash (using the C<sha224sum> program).
1867 Compute the SHA256 hash (using the C<sha256sum> program).
1871 Compute the SHA384 hash (using the C<sha384sum> program).
1875 Compute the SHA512 hash (using the C<sha512sum> program).
1879 The checksum is returned as a printable string.");
1881 ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [],
1882 [InitBasicFS, Always, TestOutput (
1883 [["tar_in"; "../images/helloworld.tar"; "/"];
1884 ["cat"; "/hello"]], "hello\n")],
1885 "unpack tarfile to directory",
1887 This command uploads and unpacks local file C<tarfile> (an
1888 I<uncompressed> tar file) into C<directory>.
1890 To upload a compressed tarball, use C<guestfs_tgz_in>.");
1892 ("tar_out", (RErr, [String "directory"; FileOut "tarfile"]), 70, [],
1894 "pack directory into tarfile",
1896 This command packs the contents of C<directory> and downloads
1897 it to local file C<tarfile>.
1899 To download a compressed tarball, use C<guestfs_tgz_out>.");
1901 ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [],
1902 [InitBasicFS, Always, TestOutput (
1903 [["tgz_in"; "../images/helloworld.tar.gz"; "/"];
1904 ["cat"; "/hello"]], "hello\n")],
1905 "unpack compressed tarball to directory",
1907 This command uploads and unpacks local file C<tarball> (a
1908 I<gzip compressed> tar file) into C<directory>.
1910 To upload an uncompressed tarball, use C<guestfs_tar_in>.");
1912 ("tgz_out", (RErr, [String "directory"; FileOut "tarball"]), 72, [],
1914 "pack directory into compressed tarball",
1916 This command packs the contents of C<directory> and downloads
1917 it to local file C<tarball>.
1919 To download an uncompressed tarball, use C<guestfs_tar_out>.");
1921 ("mount_ro", (RErr, [Device "device"; String "mountpoint"]), 73, [],
1922 [InitBasicFS, Always, TestLastFail (
1924 ["mount_ro"; "/dev/sda1"; "/"];
1925 ["touch"; "/new"]]);
1926 InitBasicFS, Always, TestOutput (
1927 [["write_file"; "/new"; "data"; "0"];
1929 ["mount_ro"; "/dev/sda1"; "/"];
1930 ["cat"; "/new"]], "data")],
1931 "mount a guest disk, read-only",
1933 This is the same as the C<guestfs_mount> command, but it
1934 mounts the filesystem with the read-only (I<-o ro>) flag.");
1936 ("mount_options", (RErr, [String "options"; Device "device"; String "mountpoint"]), 74, [],
1938 "mount a guest disk with mount options",
1940 This is the same as the C<guestfs_mount> command, but it
1941 allows you to set the mount options as for the
1942 L<mount(8)> I<-o> flag.");
1944 ("mount_vfs", (RErr, [String "options"; String "vfstype"; Device "device"; String "mountpoint"]), 75, [],
1946 "mount a guest disk with mount options and vfstype",
1948 This is the same as the C<guestfs_mount> command, but it
1949 allows you to set both the mount options and the vfstype
1950 as for the L<mount(8)> I<-o> and I<-t> flags.");
1952 ("debug", (RString "result", [String "subcmd"; StringList "extraargs"]), 76, [],
1954 "debugging and internals",
1956 The C<guestfs_debug> command exposes some internals of
1957 C<guestfsd> (the guestfs daemon) that runs inside the
1960 There is no comprehensive help for this command. You have
1961 to look at the file C<daemon/debug.c> in the libguestfs source
1962 to find out what you can do.");
1964 ("lvremove", (RErr, [Device "device"]), 77, [],
1965 [InitEmpty, Always, TestOutputList (
1966 [["sfdiskM"; "/dev/sda"; ","];
1967 ["pvcreate"; "/dev/sda1"];
1968 ["vgcreate"; "VG"; "/dev/sda1"];
1969 ["lvcreate"; "LV1"; "VG"; "50"];
1970 ["lvcreate"; "LV2"; "VG"; "50"];
1971 ["lvremove"; "/dev/VG/LV1"];
1972 ["lvs"]], ["/dev/VG/LV2"]);
1973 InitEmpty, Always, TestOutputList (
1974 [["sfdiskM"; "/dev/sda"; ","];
1975 ["pvcreate"; "/dev/sda1"];
1976 ["vgcreate"; "VG"; "/dev/sda1"];
1977 ["lvcreate"; "LV1"; "VG"; "50"];
1978 ["lvcreate"; "LV2"; "VG"; "50"];
1979 ["lvremove"; "/dev/VG"];
1981 InitEmpty, Always, TestOutputList (
1982 [["sfdiskM"; "/dev/sda"; ","];
1983 ["pvcreate"; "/dev/sda1"];
1984 ["vgcreate"; "VG"; "/dev/sda1"];
1985 ["lvcreate"; "LV1"; "VG"; "50"];
1986 ["lvcreate"; "LV2"; "VG"; "50"];
1987 ["lvremove"; "/dev/VG"];
1989 "remove an LVM logical volume",
1991 Remove an LVM logical volume C<device>, where C<device> is
1992 the path to the LV, such as C</dev/VG/LV>.
1994 You can also remove all LVs in a volume group by specifying
1995 the VG name, C</dev/VG>.");
1997 ("vgremove", (RErr, [String "vgname"]), 78, [],
1998 [InitEmpty, Always, TestOutputList (
1999 [["sfdiskM"; "/dev/sda"; ","];
2000 ["pvcreate"; "/dev/sda1"];
2001 ["vgcreate"; "VG"; "/dev/sda1"];
2002 ["lvcreate"; "LV1"; "VG"; "50"];
2003 ["lvcreate"; "LV2"; "VG"; "50"];
2006 InitEmpty, Always, TestOutputList (
2007 [["sfdiskM"; "/dev/sda"; ","];
2008 ["pvcreate"; "/dev/sda1"];
2009 ["vgcreate"; "VG"; "/dev/sda1"];
2010 ["lvcreate"; "LV1"; "VG"; "50"];
2011 ["lvcreate"; "LV2"; "VG"; "50"];
2014 "remove an LVM volume group",
2016 Remove an LVM volume group C<vgname>, (for example C<VG>).
2018 This also forcibly removes all logical volumes in the volume
2021 ("pvremove", (RErr, [Device "device"]), 79, [],
2022 [InitEmpty, Always, TestOutputListOfDevices (
2023 [["sfdiskM"; "/dev/sda"; ","];
2024 ["pvcreate"; "/dev/sda1"];
2025 ["vgcreate"; "VG"; "/dev/sda1"];
2026 ["lvcreate"; "LV1"; "VG"; "50"];
2027 ["lvcreate"; "LV2"; "VG"; "50"];
2029 ["pvremove"; "/dev/sda1"];
2031 InitEmpty, Always, TestOutputListOfDevices (
2032 [["sfdiskM"; "/dev/sda"; ","];
2033 ["pvcreate"; "/dev/sda1"];
2034 ["vgcreate"; "VG"; "/dev/sda1"];
2035 ["lvcreate"; "LV1"; "VG"; "50"];
2036 ["lvcreate"; "LV2"; "VG"; "50"];
2038 ["pvremove"; "/dev/sda1"];
2040 InitEmpty, Always, TestOutputListOfDevices (
2041 [["sfdiskM"; "/dev/sda"; ","];
2042 ["pvcreate"; "/dev/sda1"];
2043 ["vgcreate"; "VG"; "/dev/sda1"];
2044 ["lvcreate"; "LV1"; "VG"; "50"];
2045 ["lvcreate"; "LV2"; "VG"; "50"];
2047 ["pvremove"; "/dev/sda1"];
2049 "remove an LVM physical volume",
2051 This wipes a physical volume C<device> so that LVM will no longer
2054 The implementation uses the C<pvremove> command which refuses to
2055 wipe physical volumes that contain any volume groups, so you have
2056 to remove those first.");
2058 ("set_e2label", (RErr, [Device "device"; String "label"]), 80, [],
2059 [InitBasicFS, Always, TestOutput (
2060 [["set_e2label"; "/dev/sda1"; "testlabel"];
2061 ["get_e2label"; "/dev/sda1"]], "testlabel")],
2062 "set the ext2/3/4 filesystem label",
2064 This sets the ext2/3/4 filesystem label of the filesystem on
2065 C<device> to C<label>. Filesystem labels are limited to
2068 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label>
2069 to return the existing label on a filesystem.");
2071 ("get_e2label", (RString "label", [Device "device"]), 81, [],
2073 "get the ext2/3/4 filesystem label",
2075 This returns the ext2/3/4 filesystem label of the filesystem on
2078 ("set_e2uuid", (RErr, [Device "device"; String "uuid"]), 82, [],
2079 [InitBasicFS, Always, TestOutput (
2080 [["set_e2uuid"; "/dev/sda1"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"];
2081 ["get_e2uuid"; "/dev/sda1"]], "a3a61220-882b-4f61-89f4-cf24dcc7297d");
2082 InitBasicFS, Always, TestOutput (
2083 [["set_e2uuid"; "/dev/sda1"; "clear"];
2084 ["get_e2uuid"; "/dev/sda1"]], "");
2085 (* We can't predict what UUIDs will be, so just check the commands run. *)
2086 InitBasicFS, Always, TestRun (
2087 [["set_e2uuid"; "/dev/sda1"; "random"]]);
2088 InitBasicFS, Always, TestRun (
2089 [["set_e2uuid"; "/dev/sda1"; "time"]])],
2090 "set the ext2/3/4 filesystem UUID",
2092 This sets the ext2/3/4 filesystem UUID of the filesystem on
2093 C<device> to C<uuid>. The format of the UUID and alternatives
2094 such as C<clear>, C<random> and C<time> are described in the
2095 L<tune2fs(8)> manpage.
2097 You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid>
2098 to return the existing UUID of a filesystem.");
2100 ("get_e2uuid", (RString "uuid", [Device "device"]), 83, [],
2102 "get the ext2/3/4 filesystem UUID",
2104 This returns the ext2/3/4 filesystem UUID of the filesystem on
2107 ("fsck", (RInt "status", [String "fstype"; Device "device"]), 84, [],
2108 [InitBasicFS, Always, TestOutputInt (
2109 [["umount"; "/dev/sda1"];
2110 ["fsck"; "ext2"; "/dev/sda1"]], 0);
2111 InitBasicFS, Always, TestOutputInt (
2112 [["umount"; "/dev/sda1"];
2113 ["zero"; "/dev/sda1"];
2114 ["fsck"; "ext2"; "/dev/sda1"]], 8)],
2115 "run the filesystem checker",
2117 This runs the filesystem checker (fsck) on C<device> which
2118 should have filesystem type C<fstype>.
2120 The returned integer is the status. See L<fsck(8)> for the
2121 list of status codes from C<fsck>.
2129 Multiple status codes can be summed together.
2133 A non-zero return code can mean \"success\", for example if
2134 errors have been corrected on the filesystem.
2138 Checking or repairing NTFS volumes is not supported
2143 This command is entirely equivalent to running C<fsck -a -t fstype device>.");
2145 ("zero", (RErr, [Device "device"]), 85, [],
2146 [InitBasicFS, Always, TestOutput (
2147 [["umount"; "/dev/sda1"];
2148 ["zero"; "/dev/sda1"];
2149 ["file"; "/dev/sda1"]], "data")],
2150 "write zeroes to the device",
2152 This command writes zeroes over the first few blocks of C<device>.
2154 How many blocks are zeroed isn't specified (but it's I<not> enough
2155 to securely wipe the device). It should be sufficient to remove
2156 any partition tables, filesystem superblocks and so on.
2158 See also: C<guestfs_scrub_device>.");
2160 ("grub_install", (RErr, [Pathname "root"; Device "device"]), 86, [],
2161 (* Test disabled because grub-install incompatible with virtio-blk driver.
2162 * See also: https://bugzilla.redhat.com/show_bug.cgi?id=479760
2164 [InitBasicFS, Disabled, TestOutputTrue (
2165 [["grub_install"; "/"; "/dev/sda1"];
2166 ["is_dir"; "/boot"]])],
2169 This command installs GRUB (the Grand Unified Bootloader) on
2170 C<device>, with the root directory being C<root>.");
2172 ("cp", (RErr, [String "src"; String "dest"]), 87, [],
2173 [InitBasicFS, Always, TestOutput (
2174 [["write_file"; "/old"; "file content"; "0"];
2175 ["cp"; "/old"; "/new"];
2176 ["cat"; "/new"]], "file content");
2177 InitBasicFS, Always, TestOutputTrue (
2178 [["write_file"; "/old"; "file content"; "0"];
2179 ["cp"; "/old"; "/new"];
2180 ["is_file"; "/old"]]);
2181 InitBasicFS, Always, TestOutput (
2182 [["write_file"; "/old"; "file content"; "0"];
2184 ["cp"; "/old"; "/dir/new"];
2185 ["cat"; "/dir/new"]], "file content")],
2188 This copies a file from C<src> to C<dest> where C<dest> is
2189 either a destination filename or destination directory.");
2191 ("cp_a", (RErr, [String "src"; String "dest"]), 88, [],
2192 [InitBasicFS, Always, TestOutput (
2193 [["mkdir"; "/olddir"];
2194 ["mkdir"; "/newdir"];
2195 ["write_file"; "/olddir/file"; "file content"; "0"];
2196 ["cp_a"; "/olddir"; "/newdir"];
2197 ["cat"; "/newdir/olddir/file"]], "file content")],
2198 "copy a file or directory recursively",
2200 This copies a file or directory from C<src> to C<dest>
2201 recursively using the C<cp -a> command.");
2203 ("mv", (RErr, [String "src"; String "dest"]), 89, [],
2204 [InitBasicFS, Always, TestOutput (
2205 [["write_file"; "/old"; "file content"; "0"];
2206 ["mv"; "/old"; "/new"];
2207 ["cat"; "/new"]], "file content");
2208 InitBasicFS, Always, TestOutputFalse (
2209 [["write_file"; "/old"; "file content"; "0"];
2210 ["mv"; "/old"; "/new"];
2211 ["is_file"; "/old"]])],
2214 This moves a file from C<src> to C<dest> where C<dest> is
2215 either a destination filename or destination directory.");
2217 ("drop_caches", (RErr, [Int "whattodrop"]), 90, [],
2218 [InitEmpty, Always, TestRun (
2219 [["drop_caches"; "3"]])],
2220 "drop kernel page cache, dentries and inodes",
2222 This instructs the guest kernel to drop its page cache,
2223 and/or dentries and inode caches. The parameter C<whattodrop>
2224 tells the kernel what precisely to drop, see
2225 L<http://linux-mm.org/Drop_Caches>
2227 Setting C<whattodrop> to 3 should drop everything.
2229 This automatically calls L<sync(2)> before the operation,
2230 so that the maximum guest memory is freed.");
2232 ("dmesg", (RString "kmsgs", []), 91, [],
2233 [InitEmpty, Always, TestRun (
2235 "return kernel messages",
2237 This returns the kernel messages (C<dmesg> output) from
2238 the guest kernel. This is sometimes useful for extended
2239 debugging of problems.
2241 Another way to get the same information is to enable
2242 verbose messages with C<guestfs_set_verbose> or by setting
2243 the environment variable C<LIBGUESTFS_DEBUG=1> before
2244 running the program.");
2246 ("ping_daemon", (RErr, []), 92, [],
2247 [InitEmpty, Always, TestRun (
2248 [["ping_daemon"]])],
2249 "ping the guest daemon",
2251 This is a test probe into the guestfs daemon running inside
2252 the qemu subprocess. Calling this function checks that the
2253 daemon responds to the ping message, without affecting the daemon
2254 or attached block device(s) in any other way.");
2256 ("equal", (RBool "equality", [Pathname "file1"; Pathname "file2"]), 93, [],
2257 [InitBasicFS, Always, TestOutputTrue (
2258 [["write_file"; "/file1"; "contents of a file"; "0"];
2259 ["cp"; "/file1"; "/file2"];
2260 ["equal"; "/file1"; "/file2"]]);
2261 InitBasicFS, Always, TestOutputFalse (
2262 [["write_file"; "/file1"; "contents of a file"; "0"];
2263 ["write_file"; "/file2"; "contents of another file"; "0"];
2264 ["equal"; "/file1"; "/file2"]]);
2265 InitBasicFS, Always, TestLastFail (
2266 [["equal"; "/file1"; "/file2"]])],
2267 "test if two files have equal contents",
2269 This compares the two files C<file1> and C<file2> and returns
2270 true if their content is exactly equal, or false otherwise.
2272 The external L<cmp(1)> program is used for the comparison.");
2274 ("strings", (RStringList "stringsout", [Pathname "path"]), 94, [ProtocolLimitWarning],
2275 [InitSquashFS, Always, TestOutputList (
2276 [["strings"; "/known-5"]], ["abcdefghi"; "jklmnopqr"]);
2277 InitSquashFS, Always, TestOutputList (
2278 [["strings"; "/empty"]], [])],
2279 "print the printable strings in a file",
2281 This runs the L<strings(1)> command on a file and returns
2282 the list of printable strings found.");
2284 ("strings_e", (RStringList "stringsout", [String "encoding"; Pathname "path"]), 95, [ProtocolLimitWarning],
2285 [InitSquashFS, Always, TestOutputList (
2286 [["strings_e"; "b"; "/known-5"]], []);
2287 InitBasicFS, Disabled, TestOutputList (
2288 [["write_file"; "/new"; "\000h\000e\000l\000l\000o\000\n\000w\000o\000r\000l\000d\000\n"; "24"];
2289 ["strings_e"; "b"; "/new"]], ["hello"; "world"])],
2290 "print the printable strings in a file",
2292 This is like the C<guestfs_strings> command, but allows you to
2293 specify the encoding.
2295 See the L<strings(1)> manpage for the full list of encodings.
2297 Commonly useful encodings are C<l> (lower case L) which will
2298 show strings inside Windows/x86 files.
2300 The returned strings are transcoded to UTF-8.");
2302 ("hexdump", (RString "dump", [Pathname "path"]), 96, [ProtocolLimitWarning],
2303 [InitSquashFS, Always, TestOutput (
2304 [["hexdump"; "/known-4"]], "00000000 61 62 63 0a 64 65 66 0a 67 68 69 |abc.def.ghi|\n0000000b\n");
2305 (* Test for RHBZ#501888c2 regression which caused large hexdump
2306 * commands to segfault.
2308 InitSquashFS, Always, TestRun (
2309 [["hexdump"; "/100krandom"]])],
2310 "dump a file in hexadecimal",
2312 This runs C<hexdump -C> on the given C<path>. The result is
2313 the human-readable, canonical hex dump of the file.");
2315 ("zerofree", (RErr, [Device "device"]), 97, [],
2316 [InitNone, Always, TestOutput (
2317 [["sfdiskM"; "/dev/sda"; ","];
2318 ["mkfs"; "ext3"; "/dev/sda1"];
2319 ["mount"; "/dev/sda1"; "/"];
2320 ["write_file"; "/new"; "test file"; "0"];
2321 ["umount"; "/dev/sda1"];
2322 ["zerofree"; "/dev/sda1"];
2323 ["mount"; "/dev/sda1"; "/"];
2324 ["cat"; "/new"]], "test file")],
2325 "zero unused inodes and disk blocks on ext2/3 filesystem",
2327 This runs the I<zerofree> program on C<device>. This program
2328 claims to zero unused inodes and disk blocks on an ext2/3
2329 filesystem, thus making it possible to compress the filesystem
2332 You should B<not> run this program if the filesystem is
2335 It is possible that using this program can damage the filesystem
2336 or data on the filesystem.");
2338 ("pvresize", (RErr, [Device "device"]), 98, [],
2340 "resize an LVM physical volume",
2342 This resizes (expands or shrinks) an existing LVM physical
2343 volume to match the new size of the underlying device.");
2345 ("sfdisk_N", (RErr, [Device "device"; Int "partnum";
2346 Int "cyls"; Int "heads"; Int "sectors";
2347 String "line"]), 99, [DangerWillRobinson],
2349 "modify a single partition on a block device",
2351 This runs L<sfdisk(8)> option to modify just the single
2352 partition C<n> (note: C<n> counts from 1).
2354 For other parameters, see C<guestfs_sfdisk>. You should usually
2355 pass C<0> for the cyls/heads/sectors parameters.");
2357 ("sfdisk_l", (RString "partitions", [Device "device"]), 100, [],
2359 "display the partition table",
2361 This displays the partition table on C<device>, in the
2362 human-readable output of the L<sfdisk(8)> command. It is
2363 not intended to be parsed.");
2365 ("sfdisk_kernel_geometry", (RString "partitions", [Device "device"]), 101, [],
2367 "display the kernel geometry",
2369 This displays the kernel's idea of the geometry of C<device>.
2371 The result is in human-readable format, and not designed to
2374 ("sfdisk_disk_geometry", (RString "partitions", [Device "device"]), 102, [],
2376 "display the disk geometry from the partition table",
2378 This displays the disk geometry of C<device> read from the
2379 partition table. Especially in the case where the underlying
2380 block device has been resized, this can be different from the
2381 kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>).
2383 The result is in human-readable format, and not designed to
2386 ("vg_activate_all", (RErr, [Bool "activate"]), 103, [],
2388 "activate or deactivate all volume groups",
2390 This command activates or (if C<activate> is false) deactivates
2391 all logical volumes in all volume groups.
2392 If activated, then they are made known to the
2393 kernel, ie. they appear as C</dev/mapper> devices. If deactivated,
2394 then those devices disappear.
2396 This command is the same as running C<vgchange -a y|n>");
2398 ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [],
2400 "activate or deactivate some volume groups",
2402 This command activates or (if C<activate> is false) deactivates
2403 all logical volumes in the listed volume groups C<volgroups>.
2404 If activated, then they are made known to the
2405 kernel, ie. they appear as C</dev/mapper> devices. If deactivated,
2406 then those devices disappear.
2408 This command is the same as running C<vgchange -a y|n volgroups...>
2410 Note that if C<volgroups> is an empty list then B<all> volume groups
2411 are activated or deactivated.");
2413 ("lvresize", (RErr, [Device "device"; Int "mbytes"]), 105, [],
2414 [InitNone, Always, TestOutput (
2415 [["sfdiskM"; "/dev/sda"; ","];
2416 ["pvcreate"; "/dev/sda1"];
2417 ["vgcreate"; "VG"; "/dev/sda1"];
2418 ["lvcreate"; "LV"; "VG"; "10"];
2419 ["mkfs"; "ext2"; "/dev/VG/LV"];
2420 ["mount"; "/dev/VG/LV"; "/"];
2421 ["write_file"; "/new"; "test content"; "0"];
2423 ["lvresize"; "/dev/VG/LV"; "20"];
2424 ["e2fsck_f"; "/dev/VG/LV"];
2425 ["resize2fs"; "/dev/VG/LV"];
2426 ["mount"; "/dev/VG/LV"; "/"];
2427 ["cat"; "/new"]], "test content")],
2428 "resize an LVM logical volume",
2430 This resizes (expands or shrinks) an existing LVM logical
2431 volume to C<mbytes>. When reducing, data in the reduced part
2434 ("resize2fs", (RErr, [Device "device"]), 106, [],
2435 [], (* lvresize tests this *)
2436 "resize an ext2/ext3 filesystem",
2438 This resizes an ext2 or ext3 filesystem to match the size of
2439 the underlying device.
2441 I<Note:> It is sometimes required that you run C<guestfs_e2fsck_f>
2442 on the C<device> before calling this command. For unknown reasons
2443 C<resize2fs> sometimes gives an error about this and sometimes not.
2444 In any case, it is always safe to call C<guestfs_e2fsck_f> before
2445 calling this function.");
2447 ("find", (RStringList "names", [Pathname "directory"]), 107, [],
2448 [InitBasicFS, Always, TestOutputList (
2449 [["find"; "/"]], ["lost+found"]);
2450 InitBasicFS, Always, TestOutputList (
2454 ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]);
2455 InitBasicFS, Always, TestOutputList (
2456 [["mkdir_p"; "/a/b/c"];
2457 ["touch"; "/a/b/c/d"];
2458 ["find"; "/a/b/"]], ["c"; "c/d"])],
2459 "find all files and directories",
2461 This command lists out all files and directories, recursively,
2462 starting at C<directory>. It is essentially equivalent to
2463 running the shell command C<find directory -print> but some
2464 post-processing happens on the output, described below.
2466 This returns a list of strings I<without any prefix>. Thus
2467 if the directory structure was:
2473 then the returned list from C<guestfs_find> C</tmp> would be
2481 If C<directory> is not a directory, then this command returns
2484 The returned list is sorted.");
2486 ("e2fsck_f", (RErr, [Device "device"]), 108, [],
2487 [], (* lvresize tests this *)
2488 "check an ext2/ext3 filesystem",
2490 This runs C<e2fsck -p -f device>, ie. runs the ext2/ext3
2491 filesystem checker on C<device>, noninteractively (C<-p>),
2492 even if the filesystem appears to be clean (C<-f>).
2494 This command is only needed because of C<guestfs_resize2fs>
2495 (q.v.). Normally you should use C<guestfs_fsck>.");
2497 ("sleep", (RErr, [Int "secs"]), 109, [],
2498 [InitNone, Always, TestRun (
2500 "sleep for some seconds",
2502 Sleep for C<secs> seconds.");
2504 ("ntfs_3g_probe", (RInt "status", [Bool "rw"; Device "device"]), 110, [],
2505 [InitNone, Always, TestOutputInt (
2506 [["sfdiskM"; "/dev/sda"; ","];
2507 ["mkfs"; "ntfs"; "/dev/sda1"];
2508 ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0);
2509 InitNone, Always, TestOutputInt (
2510 [["sfdiskM"; "/dev/sda"; ","];
2511 ["mkfs"; "ext2"; "/dev/sda1"];
2512 ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)],
2513 "probe NTFS volume",
2515 This command runs the L<ntfs-3g.probe(8)> command which probes
2516 an NTFS C<device> for mountability. (Not all NTFS volumes can
2517 be mounted read-write, and some cannot be mounted at all).
2519 C<rw> is a boolean flag. Set it to true if you want to test
2520 if the volume can be mounted read-write. Set it to false if
2521 you want to test if the volume can be mounted read-only.
2523 The return value is an integer which C<0> if the operation
2524 would succeed, or some non-zero value documented in the
2525 L<ntfs-3g.probe(8)> manual page.");
2527 ("sh", (RString "output", [String "command"]), 111, [],
2528 [], (* XXX needs tests *)
2529 "run a command via the shell",
2531 This call runs a command from the guest filesystem via the
2534 This is like C<guestfs_command>, but passes the command to:
2536 /bin/sh -c \"command\"
2538 Depending on the guest's shell, this usually results in
2539 wildcards being expanded, shell expressions being interpolated
2542 All the provisos about C<guestfs_command> apply to this call.");
2544 ("sh_lines", (RStringList "lines", [String "command"]), 112, [],
2545 [], (* XXX needs tests *)
2546 "run a command via the shell returning lines",
2548 This is the same as C<guestfs_sh>, but splits the result
2549 into a list of lines.
2551 See also: C<guestfs_command_lines>");
2553 ("glob_expand", (RStringList "paths", [Pathname "pattern"]), 113, [],
2554 (* Use Pathname here, and hence ABS_PATH (pattern,... in generated
2555 * code in stubs.c, since all valid glob patterns must start with "/".
2556 * There is no concept of "cwd" in libguestfs, hence no "."-relative names.
2558 [InitBasicFS, Always, TestOutputList (
2559 [["mkdir_p"; "/a/b/c"];
2560 ["touch"; "/a/b/c/d"];
2561 ["touch"; "/a/b/c/e"];
2562 ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2563 InitBasicFS, Always, TestOutputList (
2564 [["mkdir_p"; "/a/b/c"];
2565 ["touch"; "/a/b/c/d"];
2566 ["touch"; "/a/b/c/e"];
2567 ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]);
2568 InitBasicFS, Always, TestOutputList (
2569 [["mkdir_p"; "/a/b/c"];
2570 ["touch"; "/a/b/c/d"];
2571 ["touch"; "/a/b/c/e"];
2572 ["glob_expand"; "/a/*/x/*"]], [])],
2573 "expand a wildcard path",
2575 This command searches for all the pathnames matching
2576 C<pattern> according to the wildcard expansion rules
2579 If no paths match, then this returns an empty list
2580 (note: not an error).
2582 It is just a wrapper around the C L<glob(3)> function
2583 with flags C<GLOB_MARK|GLOB_BRACE>.
2584 See that manual page for more details.");
2586 ("scrub_device", (RErr, [Device "device"]), 114, [DangerWillRobinson],
2587 [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *)
2588 [["scrub_device"; "/dev/sdc"]])],
2589 "scrub (securely wipe) a device",
2591 This command writes patterns over C<device> to make data retrieval
2594 It is an interface to the L<scrub(1)> program. See that
2595 manual page for more details.");
2597 ("scrub_file", (RErr, [String "file"]), 115, [],
2598 [InitBasicFS, Always, TestRun (
2599 [["write_file"; "/file"; "content"; "0"];
2600 ["scrub_file"; "/file"]])],
2601 "scrub (securely wipe) a file",
2603 This command writes patterns over a file to make data retrieval
2606 The file is I<removed> after scrubbing.
2608 It is an interface to the L<scrub(1)> program. See that
2609 manual page for more details.");
2611 ("scrub_freespace", (RErr, [String "dir"]), 116, [],
2612 [], (* XXX needs testing *)
2613 "scrub (securely wipe) free space",
2615 This command creates the directory C<dir> and then fills it
2616 with files until the filesystem is full, and scrubs the files
2617 as for C<guestfs_scrub_file>, and deletes them.
2618 The intention is to scrub any free space on the partition
2621 It is an interface to the L<scrub(1)> program. See that
2622 manual page for more details.");
2624 (* FIXME: make this a WritableString? *)
2625 ("mkdtemp", (RString "dir", [String "template"]), 117, [],
2626 [InitBasicFS, Always, TestRun (
2628 ["mkdtemp"; "/tmp/tmpXXXXXX"]])],
2629 "create a temporary directory",
2631 This command creates a temporary directory. The
2632 C<template> parameter should be a full pathname for the
2633 temporary directory name with the final six characters being
2636 For example: \"/tmp/myprogXXXXXX\" or \"/Temp/myprogXXXXXX\",
2637 the second one being suitable for Windows filesystems.
2639 The name of the temporary directory that was created
2642 The temporary directory is created with mode 0700
2643 and is owned by root.
2645 The caller is responsible for deleting the temporary
2646 directory and its contents after use.
2648 See also: L<mkdtemp(3)>");
2650 ("wc_l", (RInt "lines", [Pathname "path"]), 118, [],
2651 [InitSquashFS, Always, TestOutputInt (
2652 [["wc_l"; "/10klines"]], 10000)],
2653 "count lines in a file",
2655 This command counts the lines in a file, using the
2656 C<wc -l> external command.");
2658 ("wc_w", (RInt "words", [Pathname "path"]), 119, [],
2659 [InitSquashFS, Always, TestOutputInt (
2660 [["wc_w"; "/10klines"]], 10000)],
2661 "count words in a file",
2663 This command counts the words in a file, using the
2664 C<wc -w> external command.");
2666 ("wc_c", (RInt "chars", [Pathname "path"]), 120, [],
2667 [InitSquashFS, Always, TestOutputInt (
2668 [["wc_c"; "/100kallspaces"]], 102400)],
2669 "count characters in a file",
2671 This command counts the characters in a file, using the
2672 C<wc -c> external command.");
2674 ("head", (RStringList "lines", [Pathname "path"]), 121, [ProtocolLimitWarning],
2675 [InitSquashFS, Always, TestOutputList (
2676 [["head"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz";"3abcdefghijklmnopqrstuvwxyz";"4abcdefghijklmnopqrstuvwxyz";"5abcdefghijklmnopqrstuvwxyz";"6abcdefghijklmnopqrstuvwxyz";"7abcdefghijklmnopqrstuvwxyz";"8abcdefghijklmnopqrstuvwxyz";"9abcdefghijklmnopqrstuvwxyz"])],
2677 "return first 10 lines of a file",
2679 This command returns up to the first 10 lines of a file as
2680 a list of strings.");
2682 ("head_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 122, [ProtocolLimitWarning],
2683 [InitSquashFS, Always, TestOutputList (
2684 [["head_n"; "3"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2685 InitSquashFS, Always, TestOutputList (
2686 [["head_n"; "-9997"; "/10klines"]], ["0abcdefghijklmnopqrstuvwxyz";"1abcdefghijklmnopqrstuvwxyz";"2abcdefghijklmnopqrstuvwxyz"]);
2687 InitSquashFS, Always, TestOutputList (
2688 [["head_n"; "0"; "/10klines"]], [])],
2689 "return first N lines of a file",
2691 If the parameter C<nrlines> is a positive number, this returns the first
2692 C<nrlines> lines of the file C<path>.
2694 If the parameter C<nrlines> is a negative number, this returns lines
2695 from the file C<path>, excluding the last C<nrlines> lines.
2697 If the parameter C<nrlines> is zero, this returns an empty list.");
2699 ("tail", (RStringList "lines", [Pathname "path"]), 123, [ProtocolLimitWarning],
2700 [InitSquashFS, Always, TestOutputList (
2701 [["tail"; "/10klines"]], ["9990abcdefghijklmnopqrstuvwxyz";"9991abcdefghijklmnopqrstuvwxyz";"9992abcdefghijklmnopqrstuvwxyz";"9993abcdefghijklmnopqrstuvwxyz";"9994abcdefghijklmnopqrstuvwxyz";"9995abcdefghijklmnopqrstuvwxyz";"9996abcdefghijklmnopqrstuvwxyz";"9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"])],
2702 "return last 10 lines of a file",
2704 This command returns up to the last 10 lines of a file as
2705 a list of strings.");
2707 ("tail_n", (RStringList "lines", [Int "nrlines"; Pathname "path"]), 124, [ProtocolLimitWarning],
2708 [InitSquashFS, Always, TestOutputList (
2709 [["tail_n"; "3"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2710 InitSquashFS, Always, TestOutputList (
2711 [["tail_n"; "-9998"; "/10klines"]], ["9997abcdefghijklmnopqrstuvwxyz";"9998abcdefghijklmnopqrstuvwxyz";"9999abcdefghijklmnopqrstuvwxyz"]);
2712 InitSquashFS, Always, TestOutputList (
2713 [["tail_n"; "0"; "/10klines"]], [])],
2714 "return last N lines of a file",
2716 If the parameter C<nrlines> is a positive number, this returns the last
2717 C<nrlines> lines of the file C<path>.
2719 If the parameter C<nrlines> is a negative number, this returns lines
2720 from the file C<path>, starting with the C<-nrlines>th line.
2722 If the parameter C<nrlines> is zero, this returns an empty list.");
2724 ("df", (RString "output", []), 125, [],
2725 [], (* XXX Tricky to test because it depends on the exact format
2726 * of the 'df' command and other imponderables.
2728 "report file system disk space usage",
2730 This command runs the C<df> command to report disk space used.
2732 This command is mostly useful for interactive sessions. It
2733 is I<not> intended that you try to parse the output string.
2734 Use C<statvfs> from programs.");
2736 ("df_h", (RString "output", []), 126, [],
2737 [], (* XXX Tricky to test because it depends on the exact format
2738 * of the 'df' command and other imponderables.
2740 "report file system disk space usage (human readable)",
2742 This command runs the C<df -h> command to report disk space used
2743 in human-readable format.
2745 This command is mostly useful for interactive sessions. It
2746 is I<not> intended that you try to parse the output string.
2747 Use C<statvfs> from programs.");
2749 ("du", (RInt64 "sizekb", [Pathname "path"]), 127, [],
2750 [InitSquashFS, Always, TestOutputInt (
2751 [["du"; "/directory"]], 0 (* squashfs doesn't have blocks *))],
2752 "estimate file space usage",
2754 This command runs the C<du -s> command to estimate file space
2757 C<path> can be a file or a directory. If C<path> is a directory
2758 then the estimate includes the contents of the directory and all
2759 subdirectories (recursively).
2761 The result is the estimated size in I<kilobytes>
2762 (ie. units of 1024 bytes).");
2764 ("initrd_list", (RStringList "filenames", [Pathname "path"]), 128, [],
2765 [InitSquashFS, Always, TestOutputList (
2766 [["initrd_list"; "/initrd"]], ["empty";"known-1";"known-2";"known-3";"known-4"; "known-5"])],
2767 "list files in an initrd",
2769 This command lists out files contained in an initrd.
2771 The files are listed without any initial C</> character. The
2772 files are listed in the order they appear (not necessarily
2773 alphabetical). Directory names are listed as separate items.
2775 Old Linux kernels (2.4 and earlier) used a compressed ext2
2776 filesystem as initrd. We I<only> support the newer initramfs
2777 format (compressed cpio files).");
2779 ("mount_loop", (RErr, [String "file"; String "mountpoint"]), 129, [],
2781 "mount a file using the loop device",
2783 This command lets you mount C<file> (a filesystem image
2784 in a file) on a mount point. It is entirely equivalent to
2785 the command C<mount -o loop file mountpoint>.");
2787 ("mkswap", (RErr, [Device "device"]), 130, [],
2788 [InitEmpty, Always, TestRun (
2789 [["sfdiskM"; "/dev/sda"; ","];
2790 ["mkswap"; "/dev/sda1"]])],
2791 "create a swap partition",
2793 Create a swap partition on C<device>.");
2795 ("mkswap_L", (RErr, [String "label"; Device "device"]), 131, [],
2796 [InitEmpty, Always, TestRun (
2797 [["sfdiskM"; "/dev/sda"; ","];
2798 ["mkswap_L"; "hello"; "/dev/sda1"]])],
2799 "create a swap partition with a label",
2801 Create a swap partition on C<device> with label C<label>.
2803 Note that you cannot attach a swap label to a block device
2804 (eg. C</dev/sda>), just to a partition. This appears to be
2805 a limitation of the kernel or swap tools.");
2807 ("mkswap_U", (RErr, [String "uuid"; Device "device"]), 132, [],
2808 [InitEmpty, Always, TestRun (
2809 [["sfdiskM"; "/dev/sda"; ","];
2810 ["mkswap_U"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"; "/dev/sda1"]])],
2811 "create a swap partition with an explicit UUID",
2813 Create a swap partition on C<device> with UUID C<uuid>.");
2815 ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 133, [],
2816 [InitBasicFS, Always, TestOutputStruct (
2817 [["mknod"; "0o10777"; "0"; "0"; "/node"];
2818 (* NB: default umask 022 means 0777 -> 0755 in these tests *)
2819 ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)]);
2820 InitBasicFS, Always, TestOutputStruct (
2821 [["mknod"; "0o60777"; "66"; "99"; "/node"];
2822 ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2823 "make block, character or FIFO devices",
2825 This call creates block or character special devices, or
2826 named pipes (FIFOs).
2828 The C<mode> parameter should be the mode, using the standard
2829 constants. C<devmajor> and C<devminor> are the
2830 device major and minor numbers, only used when creating block
2831 and character special devices.");
2833 ("mkfifo", (RErr, [Int "mode"; Pathname "path"]), 134, [],
2834 [InitBasicFS, Always, TestOutputStruct (
2835 [["mkfifo"; "0o777"; "/node"];
2836 ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])],
2837 "make FIFO (named pipe)",
2839 This call creates a FIFO (named pipe) called C<path> with
2840 mode C<mode>. It is just a convenient wrapper around
2841 C<guestfs_mknod>.");
2843 ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 135, [],
2844 [InitBasicFS, Always, TestOutputStruct (
2845 [["mknod_b"; "0o777"; "99"; "66"; "/node"];
2846 ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])],
2847 "make block device node",
2849 This call creates a block device node called C<path> with
2850 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2851 It is just a convenient wrapper around C<guestfs_mknod>.");
2853 ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 136, [],
2854 [InitBasicFS, Always, TestOutputStruct (
2855 [["mknod_c"; "0o777"; "99"; "66"; "/node"];
2856 ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])],
2857 "make char device node",
2859 This call creates a char device node called C<path> with
2860 mode C<mode> and device major/minor C<devmajor> and C<devminor>.
2861 It is just a convenient wrapper around C<guestfs_mknod>.");
2863 ("umask", (RInt "oldmask", [Int "mask"]), 137, [],
2864 [], (* XXX umask is one of those stateful things that we should
2865 * reset between each test.
2867 "set file mode creation mask (umask)",
2869 This function sets the mask used for creating new files and
2870 device nodes to C<mask & 0777>.
2872 Typical umask values would be C<022> which creates new files
2873 with permissions like \"-rw-r--r--\" or \"-rwxr-xr-x\", and
2874 C<002> which creates new files with permissions like
2875 \"-rw-rw-r--\" or \"-rwxrwxr-x\".
2877 The default umask is C<022>. This is important because it
2878 means that directories and device nodes will be created with
2879 C<0644> or C<0755> mode even if you specify C<0777>.
2881 See also L<umask(2)>, C<guestfs_mknod>, C<guestfs_mkdir>.
2883 This call returns the previous umask.");
2885 ("readdir", (RStructList ("entries", "dirent"), [String "dir"]), 138, [],
2887 "read directories entries",
2889 This returns the list of directory entries in directory C<dir>.
2891 All entries in the directory are returned, including C<.> and
2892 C<..>. The entries are I<not> sorted, but returned in the same
2893 order as the underlying filesystem.
2895 Also this call returns basic file type information about each
2896 file. The C<ftyp> field will contain one of the following characters:
2934 The L<readdir(3)> returned a C<d_type> field with an
2939 This function is primarily intended for use by programs. To
2940 get a simple list of names, use C<guestfs_ls>. To get a printable
2941 directory for human consumption, use C<guestfs_ll>.");
2943 ("sfdiskM", (RErr, [Device "device"; StringList "lines"]), 139, [DangerWillRobinson],
2945 "create partitions on a block device",
2947 This is a simplified interface to the C<guestfs_sfdisk>
2948 command, where partition sizes are specified in megabytes
2949 only (rounded to the nearest cylinder) and you don't need
2950 to specify the cyls, heads and sectors parameters which
2951 were rarely if ever used anyway.
2953 See also C<guestfs_sfdisk> and the L<sfdisk(8)> manpage.");
2955 ("zfile", (RString "description", [String "method"; Pathname "path"]), 140, [DeprecatedBy "file"],
2957 "determine file type inside a compressed file",
2959 This command runs C<file> after first decompressing C<path>
2962 C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
2964 Since 1.0.63, use C<guestfs_file> instead which can now
2965 process compressed files.");
2967 ("getxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 141, [],
2969 "list extended attributes of a file or directory",
2971 This call lists the extended attributes of the file or directory
2974 At the system call level, this is a combination of the
2975 L<listxattr(2)> and L<getxattr(2)> calls.
2977 See also: C<guestfs_lgetxattrs>, L<attr(5)>.");
2979 ("lgetxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 142, [],
2981 "list extended attributes of a file or directory",
2983 This is the same as C<guestfs_getxattrs>, but if C<path>
2984 is a symbolic link, then it returns the extended attributes
2985 of the link itself.");
2987 ("setxattr", (RErr, [String "xattr";
2988 String "val"; Int "vallen"; (* will be BufferIn *)
2989 Pathname "path"]), 143, [],
2991 "set extended attribute of a file or directory",
2993 This call sets the extended attribute named C<xattr>
2994 of the file C<path> to the value C<val> (of length C<vallen>).
2995 The value is arbitrary 8 bit data.
2997 See also: C<guestfs_lsetxattr>, L<attr(5)>.");
2999 ("lsetxattr", (RErr, [String "xattr";
3000 String "val"; Int "vallen"; (* will be BufferIn *)
3001 Pathname "path"]), 144, [],
3003 "set extended attribute of a file or directory",
3005 This is the same as C<guestfs_setxattr>, but if C<path>
3006 is a symbolic link, then it sets an extended attribute
3007 of the link itself.");
3009 ("removexattr", (RErr, [String "xattr"; Pathname "path"]), 145, [],
3011 "remove extended attribute of a file or directory",
3013 This call removes the extended attribute named C<xattr>
3014 of the file C<path>.
3016 See also: C<guestfs_lremovexattr>, L<attr(5)>.");
3018 ("lremovexattr", (RErr, [String "xattr"; Pathname "path"]), 146, [],
3020 "remove extended attribute of a file or directory",
3022 This is the same as C<guestfs_removexattr>, but if C<path>
3023 is a symbolic link, then it removes an extended attribute
3024 of the link itself.");
3026 ("mountpoints", (RHashtable "mps", []), 147, [],
3030 This call is similar to C<guestfs_mounts>. That call returns
3031 a list of devices. This one returns a hash table (map) of
3032 device name to directory where the device is mounted.");
3034 ("mkmountpoint", (RErr, [String "exemptpath"]), 148, [],
3035 (* This is a special case: while you would expect a parameter
3036 * of type "Pathname", that doesn't work, because it implies
3037 * NEED_ROOT in the generated calling code in stubs.c, and
3038 * this function cannot use NEED_ROOT.
3041 "create a mountpoint",
3043 C<guestfs_mkmountpoint> and C<guestfs_rmmountpoint> are
3044 specialized calls that can be used to create extra mountpoints
3045 before mounting the first filesystem.
3047 These calls are I<only> necessary in some very limited circumstances,
3048 mainly the case where you want to mount a mix of unrelated and/or
3049 read-only filesystems together.
3051 For example, live CDs often contain a \"Russian doll\" nest of
3052 filesystems, an ISO outer layer, with a squashfs image inside, with
3053 an ext2/3 image inside that. You can unpack this as follows
3056 add-ro Fedora-11-i686-Live.iso
3059 mkmountpoint /squash
3062 mount-loop /cd/LiveOS/squashfs.img /squash
3063 mount-loop /squash/LiveOS/ext3fs.img /ext3
3065 The inner filesystem is now unpacked under the /ext3 mountpoint.");
3067 ("rmmountpoint", (RErr, [String "exemptpath"]), 149, [],
3069 "remove a mountpoint",
3071 This calls removes a mountpoint that was previously created
3072 with C<guestfs_mkmountpoint>. See C<guestfs_mkmountpoint>
3073 for full details.");
3075 ("read_file", (RBufferOut "content", [Pathname "path"]), 150, [ProtocolLimitWarning],
3076 [InitSquashFS, Always, TestOutputBuffer (
3077 [["read_file"; "/known-4"]], "abc\ndef\nghi")],
3080 This calls returns the contents of the file C<path> as a
3083 Unlike C<guestfs_cat>, this function can correctly
3084 handle files that contain embedded ASCII NUL characters.
3085 However unlike C<guestfs_download>, this function is limited
3086 in the total size of file that can be handled.");
3088 ("grep", (RStringList "lines", [String "regex"; Pathname "path"]), 151, [ProtocolLimitWarning],
3089 [InitSquashFS, Always, TestOutputList (
3090 [["grep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"]);
3091 InitSquashFS, Always, TestOutputList (
3092 [["grep"; "nomatch"; "/test-grep.txt"]], [])],
3093 "return lines matching a pattern",
3095 This calls the external C<grep> program and returns the
3098 ("egrep", (RStringList "lines", [String "regex"; Pathname "path"]), 152, [ProtocolLimitWarning],
3099 [InitSquashFS, Always, TestOutputList (
3100 [["egrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3101 "return lines matching a pattern",
3103 This calls the external C<egrep> program and returns the
3106 ("fgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 153, [ProtocolLimitWarning],
3107 [InitSquashFS, Always, TestOutputList (
3108 [["fgrep"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"])],
3109 "return lines matching a pattern",
3111 This calls the external C<fgrep> program and returns the
3114 ("grepi", (RStringList "lines", [String "regex"; Pathname "path"]), 154, [ProtocolLimitWarning],
3115 [InitSquashFS, Always, TestOutputList (
3116 [["grepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3117 "return lines matching a pattern",
3119 This calls the external C<grep -i> program and returns the
3122 ("egrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 155, [ProtocolLimitWarning],
3123 [InitSquashFS, Always, TestOutputList (
3124 [["egrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3125 "return lines matching a pattern",
3127 This calls the external C<egrep -i> program and returns the
3130 ("fgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 156, [ProtocolLimitWarning],
3131 [InitSquashFS, Always, TestOutputList (
3132 [["fgrepi"; "abc"; "/test-grep.txt"]], ["abc"; "abc123"; "ABC"])],
3133 "return lines matching a pattern",
3135 This calls the external C<fgrep -i> program and returns the
3138 ("zgrep", (RStringList "lines", [String "regex"; Pathname "path"]), 157, [ProtocolLimitWarning],
3139 [InitSquashFS, Always, TestOutputList (
3140 [["zgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3141 "return lines matching a pattern",
3143 This calls the external C<zgrep> program and returns the
3146 ("zegrep", (RStringList "lines", [String "regex"; Pathname "path"]), 158, [ProtocolLimitWarning],
3147 [InitSquashFS, Always, TestOutputList (
3148 [["zegrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3149 "return lines matching a pattern",
3151 This calls the external C<zegrep> program and returns the
3154 ("zfgrep", (RStringList "lines", [String "pattern"; Pathname "path"]), 159, [ProtocolLimitWarning],
3155 [InitSquashFS, Always, TestOutputList (
3156 [["zfgrep"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"])],
3157 "return lines matching a pattern",
3159 This calls the external C<zfgrep> program and returns the
3162 ("zgrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 160, [ProtocolLimitWarning],
3163 [InitSquashFS, Always, TestOutputList (
3164 [["zgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3165 "return lines matching a pattern",
3167 This calls the external C<zgrep -i> program and returns the
3170 ("zegrepi", (RStringList "lines", [String "regex"; Pathname "path"]), 161, [ProtocolLimitWarning],
3171 [InitSquashFS, Always, TestOutputList (
3172 [["zegrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3173 "return lines matching a pattern",
3175 This calls the external C<zegrep -i> program and returns the
3178 ("zfgrepi", (RStringList "lines", [String "pattern"; Pathname "path"]), 162, [ProtocolLimitWarning],
3179 [InitSquashFS, Always, TestOutputList (
3180 [["zfgrepi"; "abc"; "/test-grep.txt.gz"]], ["abc"; "abc123"; "ABC"])],
3181 "return lines matching a pattern",
3183 This calls the external C<zfgrep -i> program and returns the
3186 ("realpath", (RString "rpath", [Pathname "path"]), 163, [],
3187 [InitSquashFS, Always, TestOutput (
3188 [["realpath"; "/../directory"]], "/directory")],
3189 "canonicalized absolute pathname",
3191 Return the canonicalized absolute pathname of C<path>. The
3192 returned path has no C<.>, C<..> or symbolic link path elements.");
3194 ("ln", (RErr, [String "target"; Pathname "linkname"]), 164, [],
3195 [InitBasicFS, Always, TestOutputStruct (
3198 ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3199 "create a hard link",
3201 This command creates a hard link using the C<ln> command.");
3203 ("ln_f", (RErr, [String "target"; Pathname "linkname"]), 165, [],
3204 [InitBasicFS, Always, TestOutputStruct (
3207 ["ln_f"; "/a"; "/b"];
3208 ["stat"; "/b"]], [CompareWithInt ("nlink", 2)])],
3209 "create a hard link",
3211 This command creates a hard link using the C<ln -f> command.
3212 The C<-f> option removes the link (C<linkname>) if it exists already.");
3214 ("ln_s", (RErr, [String "target"; Pathname "linkname"]), 166, [],
3215 [InitBasicFS, Always, TestOutputStruct (
3217 ["ln_s"; "a"; "/b"];
3218 ["lstat"; "/b"]], [CompareWithInt ("mode", 0o120777)])],
3219 "create a symbolic link",
3221 This command creates a symbolic link using the C<ln -s> command.");
3223 ("ln_sf", (RErr, [String "target"; Pathname "linkname"]), 167, [],
3224 [InitBasicFS, Always, TestOutput (
3225 [["mkdir_p"; "/a/b"];
3226 ["touch"; "/a/b/c"];
3227 ["ln_sf"; "../d"; "/a/b/c"];
3228 ["readlink"; "/a/b/c"]], "../d")],
3229 "create a symbolic link",
3231 This command creates a symbolic link using the C<ln -sf> command,
3232 The C<-f> option removes the link (C<linkname>) if it exists already.");
3234 ("readlink", (RString "link", [Pathname "path"]), 168, [],
3235 [] (* XXX tested above *),
3236 "read the target of a symbolic link",
3238 This command reads the target of a symbolic link.");
3240 ("fallocate", (RErr, [Pathname "path"; Int "len"]), 169, [],
3241 [InitBasicFS, Always, TestOutputStruct (
3242 [["fallocate"; "/a"; "1000000"];
3243 ["stat"; "/a"]], [CompareWithInt ("size", 1_000_000)])],
3244 "preallocate a file in the guest filesystem",
3246 This command preallocates a file (containing zero bytes) named
3247 C<path> of size C<len> bytes. If the file exists already, it
3250 Do not confuse this with the guestfish-specific
3251 C<alloc> command which allocates a file in the host and
3252 attaches it as a device.");
3254 ("swapon_device", (RErr, [Device "device"]), 170, [],
3255 [InitPartition, Always, TestRun (
3256 [["mkswap"; "/dev/sda1"];
3257 ["swapon_device"; "/dev/sda1"];
3258 ["swapoff_device"; "/dev/sda1"]])],
3259 "enable swap on device",
3261 This command enables the libguestfs appliance to use the
3262 swap device or partition named C<device>. The increased
3263 memory is made available for all commands, for example
3264 those run using C<guestfs_command> or C<guestfs_sh>.
3266 Note that you should not swap to existing guest swap
3267 partitions unless you know what you are doing. They may
3268 contain hibernation information, or other information that
3269 the guest doesn't want you to trash. You also risk leaking
3270 information about the host to the guest this way. Instead,
3271 attach a new host device to the guest and swap on that.");
3273 ("swapoff_device", (RErr, [Device "device"]), 171, [],
3274 [], (* XXX tested by swapon_device *)
3275 "disable swap on device",
3277 This command disables the libguestfs appliance swap
3278 device or partition named C<device>.
3279 See C<guestfs_swapon_device>.");
3281 ("swapon_file", (RErr, [String "file"]), 172, [],
3282 [InitBasicFS, Always, TestRun (
3283 [["fallocate"; "/swap"; "8388608"];
3284 ["mkswap_file"; "/swap"];
3285 ["swapon_file"; "/swap"];
3286 ["swapoff_file"; "/swap"]])],
3287 "enable swap on file",
3289 This command enables swap to a file.
3290 See C<guestfs_swapon_device> for other notes.");
3292 ("swapoff_file", (RErr, [String "file"]), 173, [],
3293 [], (* XXX tested by swapon_file *)
3294 "disable swap on file",
3296 This command disables the libguestfs appliance swap on file.");
3298 ("swapon_label", (RErr, [String "label"]), 174, [],
3299 [InitEmpty, Always, TestRun (
3300 [["sfdiskM"; "/dev/sdb"; ","];
3301 ["mkswap_L"; "swapit"; "/dev/sdb1"];
3302 ["swapon_label"; "swapit"];
3303 ["swapoff_label"; "swapit"];
3304 ["zero"; "/dev/sdb"];
3305 ["blockdev_rereadpt"; "/dev/sdb"]])],
3306 "enable swap on labeled swap partition",
3308 This command enables swap to a labeled swap partition.
3309 See C<guestfs_swapon_device> for other notes.");
3311 ("swapoff_label", (RErr, [String "label"]), 175, [],
3312 [], (* XXX tested by swapon_label *)
3313 "disable swap on labeled swap partition",
3315 This command disables the libguestfs appliance swap on
3316 labeled swap partition.");
3318 ("swapon_uuid", (RErr, [String "uuid"]), 176, [],
3319 [InitEmpty, Always, TestRun (
3320 [["mkswap_U"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"; "/dev/sdb"];
3321 ["swapon_uuid"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"];
3322 ["swapoff_uuid"; "a3a61220-882b-4f61-89f4-cf24dcc7297d"]])],
3323 "enable swap on swap partition by UUID",
3325 This command enables swap to a swap partition with the given UUID.
3326 See C<guestfs_swapon_device> for other notes.");
3328 ("swapoff_uuid", (RErr, [String "uuid"]), 177, [],
3329 [], (* XXX tested by swapon_uuid *)
3330 "disable swap on swap partition by UUID",
3332 This command disables the libguestfs appliance swap partition
3333 with the given UUID.");
3335 ("mkswap_file", (RErr, [Pathname "path"]), 178, [],
3336 [InitBasicFS, Always, TestRun (
3337 [["fallocate"; "/swap"; "8388608"];
3338 ["mkswap_file"; "/swap"]])],
3339 "create a swap file",
3343 This command just writes a swap file signature to an existing
3344 file. To create the file itself, use something like C<guestfs_fallocate>.");
3346 ("inotify_init", (RErr, [Int "maxevents"]), 179, [],
3347 [InitSquashFS, Always, TestRun (
3348 [["inotify_init"; "0"]])],
3349 "create an inotify handle",
3351 This command creates a new inotify handle.
3352 The inotify subsystem can be used to notify events which happen to
3353 objects in the guest filesystem.
3355 C<maxevents> is the maximum number of events which will be
3356 queued up between calls to C<guestfs_inotify_read> or
3357 C<guestfs_inotify_files>.
3358 If this is passed as C<0>, then the kernel (or previously set)
3359 default is used. For Linux 2.6.29 the default was 16384 events.
3360 Beyond this limit, the kernel throws away events, but records
3361 the fact that it threw them away by setting a flag
3362 C<IN_Q_OVERFLOW> in the returned structure list (see
3363 C<guestfs_inotify_read>).
3365 Before any events are generated, you have to add some
3366 watches to the internal watch list. See:
3367 C<guestfs_inotify_add_watch>,
3368 C<guestfs_inotify_rm_watch> and
3369 C<guestfs_inotify_watch_all>.
3371 Queued up events should be read periodically by calling
3372 C<guestfs_inotify_read>
3373 (or C<guestfs_inotify_files> which is just a helpful
3374 wrapper around C<guestfs_inotify_read>). If you don't
3375 read the events out often enough then you risk the internal
3378 The handle should be closed after use by calling
3379 C<guestfs_inotify_close>. This also removes any
3380 watches automatically.
3382 See also L<inotify(7)> for an overview of the inotify interface
3383 as exposed by the Linux kernel, which is roughly what we expose
3384 via libguestfs. Note that there is one global inotify handle
3385 per libguestfs instance.");
3387 ("inotify_add_watch", (RInt64 "wd", [Pathname "path"; Int "mask"]), 180, [],
3388 [InitBasicFS, Always, TestOutputList (
3389 [["inotify_init"; "0"];
3390 ["inotify_add_watch"; "/"; "1073741823"];
3393 ["inotify_files"]], ["a"; "b"])],
3394 "add an inotify watch",
3396 Watch C<path> for the events listed in C<mask>.
3398 Note that if C<path> is a directory then events within that
3399 directory are watched, but this does I<not> happen recursively
3400 (in subdirectories).
3402 Note for non-C or non-Linux callers: the inotify events are
3403 defined by the Linux kernel ABI and are listed in
3404 C</usr/include/sys/inotify.h>.");
3406 ("inotify_rm_watch", (RErr, [Int(*XXX64*) "wd"]), 181, [],
3408 "remove an inotify watch",
3410 Remove a previously defined inotify watch.
3411 See C<guestfs_inotify_add_watch>.");
3413 ("inotify_read", (RStructList ("events", "inotify_event"), []), 182, [],
3415 "return list of inotify events",
3417 Return the complete queue of events that have happened
3418 since the previous read call.
3420 If no events have happened, this returns an empty list.
3422 I<Note>: In order to make sure that all events have been
3423 read, you must call this function repeatedly until it
3424 returns an empty list. The reason is that the call will
3425 read events up to the maximum appliance-to-host message
3426 size and leave remaining events in the queue.");
3428 ("inotify_files", (RStringList "paths", []), 183, [],
3430 "return list of watched files that had events",
3432 This function is a helpful wrapper around C<guestfs_inotify_read>
3433 which just returns a list of pathnames of objects that were
3434 touched. The returned pathnames are sorted and deduplicated.");
3436 ("inotify_close", (RErr, []), 184, [],
3438 "close the inotify handle",
3440 This closes the inotify handle which was previously
3441 opened by inotify_init. It removes all watches, throws
3442 away any pending events, and deallocates all resources.");
3444 ("setcon", (RErr, [String "context"]), 185, [],
3446 "set SELinux security context",
3448 This sets the SELinux security context of the daemon
3449 to the string C<context>.
3451 See the documentation about SELINUX in L<guestfs(3)>.");
3453 ("getcon", (RString "context", []), 186, [],
3455 "get SELinux security context",
3457 This gets the SELinux security context of the daemon.
3459 See the documentation about SELINUX in L<guestfs(3)>,
3460 and C<guestfs_setcon>");
3464 let all_functions = non_daemon_functions @ daemon_functions
3466 (* In some places we want the functions to be displayed sorted
3467 * alphabetically, so this is useful:
3469 let all_functions_sorted =
3470 List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) ->
3471 compare n1 n2) all_functions
3473 (* Field types for structures. *)
3475 | FChar (* C 'char' (really, a 7 bit byte). *)
3476 | FString (* nul-terminated ASCII string, NOT NULL. *)
3477 | FBuffer (* opaque buffer of bytes, (char *, int) pair *)
3482 | FBytes (* Any int measure that counts bytes. *)
3483 | FUUID (* 32 bytes long, NOT nul-terminated. *)
3484 | FOptPercent (* [0..100], or -1 meaning "not present". *)
3486 (* Because we generate extra parsing code for LVM command line tools,
3487 * we have to pull out the LVM columns separately here.
3497 "pv_attr", FString (* XXX *);
3498 "pv_pe_count", FInt64;
3499 "pv_pe_alloc_count", FInt64;
3502 "pv_mda_count", FInt64;
3503 "pv_mda_free", FBytes;
3504 (* Not in Fedora 10:
3505 "pv_mda_size", FBytes;
3512 "vg_attr", FString (* XXX *);
3515 "vg_sysid", FString;
3516 "vg_extent_size", FBytes;
3517 "vg_extent_count", FInt64;
3518 "vg_free_count", FInt64;
3523 "snap_count", FInt64;
3526 "vg_mda_count", FInt64;
3527 "vg_mda_free", FBytes;
3528 (* Not in Fedora 10:
3529 "vg_mda_size", FBytes;
3535 "lv_attr", FString (* XXX *);
3538 "lv_kernel_major", FInt64;
3539 "lv_kernel_minor", FInt64;
3541 "seg_count", FInt64;
3543 "snap_percent", FOptPercent;
3544 "copy_percent", FOptPercent;
3547 "mirror_log", FString;
3551 (* Names and fields in all structures (in RStruct and RStructList)
3555 (* The old RIntBool return type, only ever used for aug_defnode. Do
3556 * not use this struct in any new code.
3559 "i", FInt32; (* for historical compatibility *)
3560 "b", FInt32; (* for historical compatibility *)
3563 (* LVM PVs, VGs, LVs. *)
3564 "lvm_pv", lvm_pv_cols;
3565 "lvm_vg", lvm_vg_cols;
3566 "lvm_lv", lvm_lv_cols;
3568 (* Column names and types from stat structures.
3569 * NB. Can't use things like 'st_atime' because glibc header files
3570 * define some of these as macros. Ugh.
3601 (* Column names in dirent structure. *)
3604 (* 'b' 'c' 'd' 'f' (FIFO) 'l' 'r' (regular file) 's' 'u' '?' *)
3609 (* Version numbers. *)
3617 (* Extended attribute. *)
3619 "attrname", FString;
3623 (* Inotify events. *)
3627 "in_cookie", FUInt32;
3630 ] (* end of structs *)
3632 (* Ugh, Java has to be different ..
3633 * These names are also used by the Haskell bindings.
3635 let java_structs = [
3636 "int_bool", "IntBool";
3641 "statvfs", "StatVFS";
3643 "version", "Version";
3645 "inotify_event", "INotifyEvent";
3648 (* Used for testing language bindings. *)
3650 | CallString of string
3651 | CallOptString of string option
3652 | CallStringList of string list
3656 (* Used to memoize the result of pod2text. *)
3657 let pod2text_memo_filename = "src/.pod2text.data"
3658 let pod2text_memo : ((int * string * string), string list) Hashtbl.t =
3660 let chan = open_in pod2text_memo_filename in
3661 let v = input_value chan in
3665 _ -> Hashtbl.create 13
3667 (* Useful functions.
3668 * Note we don't want to use any external OCaml libraries which
3669 * makes this a bit harder than it should be.
3671 let failwithf fs = ksprintf failwith fs
3673 let replace_char s c1 c2 =
3674 let s2 = String.copy s in
3675 let r = ref false in
3676 for i = 0 to String.length s2 - 1 do
3677 if String.unsafe_get s2 i = c1 then (
3678 String.unsafe_set s2 i c2;
3682 if not !r then s else s2
3686 (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *)
3688 let triml ?(test = isspace) str =
3690 let n = ref (String.length str) in
3691 while !n > 0 && test str.[!i]; do
3696 else String.sub str !i !n
3698 let trimr ?(test = isspace) str =
3699 let n = ref (String.length str) in
3700 while !n > 0 && test str.[!n-1]; do
3703 if !n = String.length str then str
3704 else String.sub str 0 !n
3706 let trim ?(test = isspace) str =
3707 trimr ~test (triml ~test str)
3709 let rec find s sub =
3710 let len = String.length s in
3711 let sublen = String.length sub in
3713 if i <= len-sublen then (
3715 if j < sublen then (
3716 if s.[i+j] = sub.[j] then loop2 (j+1)
3722 if r = -1 then loop (i+1) else r
3728 let rec replace_str s s1 s2 =
3729 let len = String.length s in
3730 let sublen = String.length s1 in
3731 let i = find s s1 in
3734 let s' = String.sub s 0 i in
3735 let s'' = String.sub s (i+sublen) (len-i-sublen) in
3736 s' ^ s2 ^ replace_str s'' s1 s2
3739 let rec string_split sep str =
3740 let len = String.length str in
3741 let seplen = String.length sep in
3742 let i = find str sep in
3743 if i = -1 then [str]
3745 let s' = String.sub str 0 i in
3746 let s'' = String.sub str (i+seplen) (len-i-seplen) in
3747 s' :: string_split sep s''
3750 let files_equal n1 n2 =
3751 let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in
3752 match Sys.command cmd with
3755 | i -> failwithf "%s: failed with error code %d" cmd i
3757 let rec filter_map f = function
3761 | Some y -> y :: filter_map f xs
3762 | None -> filter_map f xs
3764 let rec find_map f = function
3765 | [] -> raise Not_found
3769 | None -> find_map f xs
3772 let rec loop i = function
3774 | x :: xs -> f i x; loop (i+1) xs
3779 let rec loop i = function
3781 | x :: xs -> let r = f i x in r :: loop (i+1) xs
3785 let name_of_argt = function
3786 | Pathname n | Device n | String n | OptString n | StringList n | Bool n | Int n
3787 | FileIn n | FileOut n -> n
3789 let java_name_of_struct typ =
3790 try List.assoc typ java_structs
3793 "java_name_of_struct: no java_structs entry corresponding to %s" typ
3795 let cols_of_struct typ =
3796 try List.assoc typ structs
3798 failwithf "cols_of_struct: unknown struct %s" typ
3800 let seq_of_test = function
3801 | TestRun s | TestOutput (s, _) | TestOutputList (s, _)
3802 | TestOutputListOfDevices (s, _)
3803 | TestOutputInt (s, _) | TestOutputIntOp (s, _, _)
3804 | TestOutputTrue s | TestOutputFalse s
3805 | TestOutputLength (s, _) | TestOutputBuffer (s, _)
3806 | TestOutputStruct (s, _)
3807 | TestLastFail s -> s
3809 (* Handling for function flags. *)
3810 let protocol_limit_warning =
3811 "Because of the message protocol, there is a transfer limit
3812 of somewhere between 2MB and 4MB. To transfer large files you should use
3815 let danger_will_robinson =
3816 "B<This command is dangerous. Without careful use you
3817 can easily destroy all your data>."
3819 let deprecation_notice flags =
3822 find_map (function DeprecatedBy str -> Some str | _ -> None) flags in
3824 sprintf "This function is deprecated.
3825 In new code, use the C<%s> call instead.
3827 Deprecated functions will not be removed from the API, but the
3828 fact that they are deprecated indicates that there are problems
3829 with correct use of these functions." alt in
3834 (* Check function names etc. for consistency. *)
3835 let check_functions () =
3836 let contains_uppercase str =
3837 let len = String.length str in
3839 if i >= len then false
3842 if c >= 'A' && c <= 'Z' then true
3849 (* Check function names. *)
3851 fun (name, _, _, _, _, _, _) ->
3852 if String.length name >= 7 && String.sub name 0 7 = "guestfs" then
3853 failwithf "function name %s does not need 'guestfs' prefix" name;
3855 failwithf "function name is empty";
3856 if name.[0] < 'a' || name.[0] > 'z' then
3857 failwithf "function name %s must start with lowercase a-z" name;
3858 if String.contains name '-' then
3859 failwithf "function name %s should not contain '-', use '_' instead."
3863 (* Check function parameter/return names. *)
3865 fun (name, style, _, _, _, _, _) ->
3866 let check_arg_ret_name n =
3867 if contains_uppercase n then
3868 failwithf "%s param/ret %s should not contain uppercase chars"
3870 if String.contains n '-' || String.contains n '_' then
3871 failwithf "%s param/ret %s should not contain '-' or '_'"
3874 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;
3875 if n = "int" || n = "char" || n = "short" || n = "long" then
3876 failwithf "%s has a param/ret which conflicts with a C type (eg. 'int', 'char' etc.)" name;
3877 if n = "i" || n = "n" then
3878 failwithf "%s has a param/ret called 'i' or 'n', which will cause some conflicts in the generated code" name;
3879 if n = "argv" || n = "args" then
3880 failwithf "%s has a param/ret called 'argv' or 'args', which will cause some conflicts in the generated code" name
3883 (match fst style with
3885 | RInt n | RInt64 n | RBool n
3886 | RConstString n | RConstOptString n | RString n
3887 | RStringList n | RStruct (n, _) | RStructList (n, _)
3888 | RHashtable n | RBufferOut n ->
3889 check_arg_ret_name n
3891 List.iter (fun arg -> check_arg_ret_name (name_of_argt arg)) (snd style)
3894 (* Check short descriptions. *)
3896 fun (name, _, _, _, _, shortdesc, _) ->
3897 if shortdesc.[0] <> Char.lowercase shortdesc.[0] then
3898 failwithf "short description of %s should begin with lowercase." name;
3899 let c = shortdesc.[String.length shortdesc-1] in
3900 if c = '\n' || c = '.' then
3901 failwithf "short description of %s should not end with . or \\n." name
3904 (* Check long dscriptions. *)
3906 fun (name, _, _, _, _, _, longdesc) ->
3907 if longdesc.[String.length longdesc-1] = '\n' then
3908 failwithf "long description of %s should not end with \\n." name
3911 (* Check proc_nrs. *)
3913 fun (name, _, proc_nr, _, _, _, _) ->
3914 if proc_nr <= 0 then
3915 failwithf "daemon function %s should have proc_nr > 0" name
3919 fun (name, _, proc_nr, _, _, _, _) ->
3920 if proc_nr <> -1 then
3921 failwithf "non-daemon function %s should have proc_nr -1" name
3922 ) non_daemon_functions;
3925 List.map (fun (name, _, proc_nr, _, _, _, _) -> name, proc_nr)
3928 List.sort (fun (_,nr1) (_,nr2) -> compare nr1 nr2) proc_nrs in
3929 let rec loop = function
3932 | (name1,nr1) :: ((name2,nr2) :: _ as rest) when nr1 < nr2 ->
3934 | (name1,nr1) :: (name2,nr2) :: _ ->
3935 failwithf "%s and %s have conflicting procedure numbers (%d, %d)"
3943 (* Ignore functions that have no tests. We generate a
3944 * warning when the user does 'make check' instead.
3946 | name, _, _, _, [], _, _ -> ()
3947 | name, _, _, _, tests, _, _ ->
3951 match seq_of_test test with
3953 failwithf "%s has a test containing an empty sequence" name
3954 | cmds -> List.map List.hd cmds
3956 let funcs = List.flatten funcs in
3958 let tested = List.mem name funcs in
3961 failwithf "function %s has tests but does not test itself" name
3964 (* 'pr' prints to the current output file. *)
3965 let chan = ref stdout
3966 let pr fs = ksprintf (output_string !chan) fs
3968 (* Generate a header block in a number of standard styles. *)
3969 type comment_style = CStyle | HashStyle | OCamlStyle | HaskellStyle
3970 type license = GPLv2 | LGPLv2
3972 let generate_header comment license =
3973 let c = match comment with
3974 | CStyle -> pr "/* "; " *"
3975 | HashStyle -> pr "# "; "#"
3976 | OCamlStyle -> pr "(* "; " *"
3977 | HaskellStyle -> pr "{- "; " " in
3978 pr "libguestfs generated file\n";
3979 pr "%s WARNING: THIS FILE IS GENERATED BY 'src/generator.ml'.\n" c;
3980 pr "%s ANY CHANGES YOU MAKE TO THIS FILE WILL BE LOST.\n" c;
3982 pr "%s Copyright (C) 2009 Red Hat Inc.\n" c;
3986 pr "%s This program is free software; you can redistribute it and/or modify\n" c;
3987 pr "%s it under the terms of the GNU General Public License as published by\n" c;
3988 pr "%s the Free Software Foundation; either version 2 of the License, or\n" c;
3989 pr "%s (at your option) any later version.\n" c;
3991 pr "%s This program is distributed in the hope that it will be useful,\n" c;
3992 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
3993 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" c;
3994 pr "%s GNU General Public License for more details.\n" c;
3996 pr "%s You should have received a copy of the GNU General Public License along\n" c;
3997 pr "%s with this program; if not, write to the Free Software Foundation, Inc.,\n" c;
3998 pr "%s 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n" c;
4001 pr "%s This library is free software; you can redistribute it and/or\n" c;
4002 pr "%s modify it under the terms of the GNU Lesser General Public\n" c;
4003 pr "%s License as published by the Free Software Foundation; either\n" c;
4004 pr "%s version 2 of the License, or (at your option) any later version.\n" c;
4006 pr "%s This library is distributed in the hope that it will be useful,\n" c;
4007 pr "%s but WITHOUT ANY WARRANTY; without even the implied warranty of\n" c;
4008 pr "%s MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" c;
4009 pr "%s Lesser General Public License for more details.\n" c;
4011 pr "%s You should have received a copy of the GNU Lesser General Public\n" c;
4012 pr "%s License along with this library; if not, write to the Free Software\n" c;
4013 pr "%s Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n" c;
4016 | CStyle -> pr " */\n"
4018 | OCamlStyle -> pr " *)\n"
4019 | HaskellStyle -> pr "-}\n"
4023 (* Start of main code generation functions below this line. *)
4025 (* Generate the pod documentation for the C API. *)
4026 let rec generate_actions_pod () =
4028 fun (shortname, style, _, flags, _, _, longdesc) ->
4029 if not (List.mem NotInDocs flags) then (
4030 let name = "guestfs_" ^ shortname in
4031 pr "=head2 %s\n\n" name;
4033 generate_prototype ~extern:false ~handle:"handle" name style;
4035 pr "%s\n\n" longdesc;
4036 (match fst style with
4038 pr "This function returns 0 on success or -1 on error.\n\n"
4040 pr "On error this function returns -1.\n\n"
4042 pr "On error this function returns -1.\n\n"
4044 pr "This function returns a C truth value on success or -1 on error.\n\n"
4046 pr "This function returns a string, or NULL on error.
4047 The string is owned by the guest handle and must I<not> be freed.\n\n"
4048 | RConstOptString _ ->
4049 pr "This function returns a string which may be NULL.
4050 There is way to return an error from this function.
4051 The string is owned by the guest handle and must I<not> be freed.\n\n"
4053 pr "This function returns a string, or NULL on error.
4054 I<The caller must free the returned string after use>.\n\n"
4056 pr "This function returns a NULL-terminated array of strings
4057 (like L<environ(3)>), or NULL if there was an error.
4058 I<The caller must free the strings and the array after use>.\n\n"
4059 | RStruct (_, typ) ->
4060 pr "This function returns a C<struct guestfs_%s *>,
4061 or NULL if there was an error.
4062 I<The caller must call C<guestfs_free_%s> after use>.\n\n" typ typ
4063 | RStructList (_, typ) ->
4064 pr "This function returns a C<struct guestfs_%s_list *>
4065 (see E<lt>guestfs-structs.hE<gt>),
4066 or NULL if there was an error.
4067 I<The caller must call C<guestfs_free_%s_list> after use>.\n\n" typ typ
4069 pr "This function returns a NULL-terminated array of
4070 strings, or NULL if there was an error.
4071 The array of strings will always have length C<2n+1>, where
4072 C<n> keys and values alternate, followed by the trailing NULL entry.
4073 I<The caller must free the strings and the array after use>.\n\n"
4075 pr "This function returns a buffer, or NULL on error.
4076 The size of the returned buffer is written to C<*size_r>.
4077 I<The caller must free the returned buffer after use>.\n\n"
4079 if List.mem ProtocolLimitWarning flags then
4080 pr "%s\n\n" protocol_limit_warning;
4081 if List.mem DangerWillRobinson flags then
4082 pr "%s\n\n" danger_will_robinson;
4083 match deprecation_notice flags with
4085 | Some txt -> pr "%s\n\n" txt
4087 ) all_functions_sorted
4089 and generate_structs_pod () =
4090 (* Structs documentation. *)
4093 pr "=head2 guestfs_%s\n" typ;
4095 pr " struct guestfs_%s {\n" typ;
4098 | name, FChar -> pr " char %s;\n" name
4099 | name, FUInt32 -> pr " uint32_t %s;\n" name
4100 | name, FInt32 -> pr " int32_t %s;\n" name
4101 | name, (FUInt64|FBytes) -> pr " uint64_t %s;\n" name
4102 | name, FInt64 -> pr " int64_t %s;\n" name
4103 | name, FString -> pr " char *%s;\n" name
4105 pr " /* The next two fields describe a byte array. */\n";
4106 pr " uint32_t %s_len;\n" name;
4107 pr " char *%s;\n" name
4109 pr " /* The next field is NOT nul-terminated, be careful when printing it: */\n";
4110 pr " char %s[32];\n" name
4111 | name, FOptPercent ->
4112 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
4113 pr " float %s;\n" name
4117 pr " struct guestfs_%s_list {\n" typ;
4118 pr " uint32_t len; /* Number of elements in list. */\n";
4119 pr " struct guestfs_%s *val; /* Elements. */\n" typ;
4122 pr " void guestfs_free_%s (struct guestfs_free_%s *);\n" typ typ;
4123 pr " void guestfs_free_%s_list (struct guestfs_free_%s_list *);\n"
4128 (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and
4129 * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'.
4131 * We have to use an underscore instead of a dash because otherwise
4132 * rpcgen generates incorrect code.
4134 * This header is NOT exported to clients, but see also generate_structs_h.
4136 and generate_xdr () =
4137 generate_header CStyle LGPLv2;
4139 (* This has to be defined to get around a limitation in Sun's rpcgen. *)
4140 pr "typedef string str<>;\n";
4143 (* Internal structures. *)
4147 pr "struct guestfs_int_%s {\n" typ;
4149 | name, FChar -> pr " char %s;\n" name
4150 | name, FString -> pr " string %s<>;\n" name
4151 | name, FBuffer -> pr " opaque %s<>;\n" name
4152 | name, FUUID -> pr " opaque %s[32];\n" name
4153 | name, (FInt32|FUInt32) -> pr " int %s;\n" name
4154 | name, (FInt64|FUInt64|FBytes) -> pr " hyper %s;\n" name
4155 | name, FOptPercent -> pr " float %s;\n" name
4159 pr "typedef struct guestfs_int_%s guestfs_int_%s_list<>;\n" typ typ;
4164 fun (shortname, style, _, _, _, _, _) ->
4165 let name = "guestfs_" ^ shortname in
4167 (match snd style with
4170 pr "struct %s_args {\n" name;
4173 | Pathname n | Device n | String n -> pr " string %s<>;\n" n
4174 | OptString n -> pr " str *%s;\n" n
4175 | StringList n -> pr " str %s<>;\n" n
4176 | Bool n -> pr " bool %s;\n" n
4177 | Int n -> pr " int %s;\n" n
4178 | FileIn _ | FileOut _ -> ()
4182 (match fst style with
4185 pr "struct %s_ret {\n" name;
4189 pr "struct %s_ret {\n" name;
4190 pr " hyper %s;\n" n;
4193 pr "struct %s_ret {\n" name;
4196 | RConstString _ | RConstOptString _ ->
4197 failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4199 pr "struct %s_ret {\n" name;
4200 pr " string %s<>;\n" n;
4203 pr "struct %s_ret {\n" name;
4204 pr " str %s<>;\n" n;
4206 | RStruct (n, typ) ->
4207 pr "struct %s_ret {\n" name;
4208 pr " guestfs_int_%s %s;\n" typ n;
4210 | RStructList (n, typ) ->
4211 pr "struct %s_ret {\n" name;
4212 pr " guestfs_int_%s_list %s;\n" typ n;
4215 pr "struct %s_ret {\n" name;
4216 pr " str %s<>;\n" n;
4219 pr "struct %s_ret {\n" name;
4220 pr " opaque %s<>;\n" n;
4225 (* Table of procedure numbers. *)
4226 pr "enum guestfs_procedure {\n";
4228 fun (shortname, _, proc_nr, _, _, _, _) ->
4229 pr " GUESTFS_PROC_%s = %d,\n" (String.uppercase shortname) proc_nr
4231 pr " GUESTFS_PROC_NR_PROCS\n";
4235 (* Having to choose a maximum message size is annoying for several
4236 * reasons (it limits what we can do in the API), but it (a) makes
4237 * the protocol a lot simpler, and (b) provides a bound on the size
4238 * of the daemon which operates in limited memory space. For large
4239 * file transfers you should use FTP.
4241 pr "const GUESTFS_MESSAGE_MAX = %d;\n" (4 * 1024 * 1024);
4244 (* Message header, etc. *)
4246 /* The communication protocol is now documented in the guestfs(3)
4250 const GUESTFS_PROGRAM = 0x2000F5F5;
4251 const GUESTFS_PROTOCOL_VERSION = 1;
4253 /* These constants must be larger than any possible message length. */
4254 const GUESTFS_LAUNCH_FLAG = 0xf5f55ff5;
4255 const GUESTFS_CANCEL_FLAG = 0xffffeeee;
4257 enum guestfs_message_direction {
4258 GUESTFS_DIRECTION_CALL = 0, /* client -> daemon */
4259 GUESTFS_DIRECTION_REPLY = 1 /* daemon -> client */
4262 enum guestfs_message_status {
4263 GUESTFS_STATUS_OK = 0,
4264 GUESTFS_STATUS_ERROR = 1
4267 const GUESTFS_ERROR_LEN = 256;
4269 struct guestfs_message_error {
4270 string error_message<GUESTFS_ERROR_LEN>;
4273 struct guestfs_message_header {
4274 unsigned prog; /* GUESTFS_PROGRAM */
4275 unsigned vers; /* GUESTFS_PROTOCOL_VERSION */
4276 guestfs_procedure proc; /* GUESTFS_PROC_x */
4277 guestfs_message_direction direction;
4278 unsigned serial; /* message serial number */
4279 guestfs_message_status status;
4282 const GUESTFS_MAX_CHUNK_SIZE = 8192;
4284 struct guestfs_chunk {
4285 int cancel; /* if non-zero, transfer is cancelled */
4286 /* data size is 0 bytes if the transfer has finished successfully */
4287 opaque data<GUESTFS_MAX_CHUNK_SIZE>;
4291 (* Generate the guestfs-structs.h file. *)
4292 and generate_structs_h () =
4293 generate_header CStyle LGPLv2;
4295 (* This is a public exported header file containing various
4296 * structures. The structures are carefully written to have
4297 * exactly the same in-memory format as the XDR structures that
4298 * we use on the wire to the daemon. The reason for creating
4299 * copies of these structures here is just so we don't have to
4300 * export the whole of guestfs_protocol.h (which includes much
4301 * unrelated and XDR-dependent stuff that we don't want to be
4302 * public, or required by clients).
4304 * To reiterate, we will pass these structures to and from the
4305 * client with a simple assignment or memcpy, so the format
4306 * must be identical to what rpcgen / the RFC defines.
4309 (* Public structures. *)
4312 pr "struct guestfs_%s {\n" typ;
4315 | name, FChar -> pr " char %s;\n" name
4316 | name, FString -> pr " char *%s;\n" name
4318 pr " uint32_t %s_len;\n" name;
4319 pr " char *%s;\n" name
4320 | name, FUUID -> pr " char %s[32]; /* this is NOT nul-terminated, be careful when printing */\n" name
4321 | name, FUInt32 -> pr " uint32_t %s;\n" name
4322 | name, FInt32 -> pr " int32_t %s;\n" name
4323 | name, (FUInt64|FBytes) -> pr " uint64_t %s;\n" name
4324 | name, FInt64 -> pr " int64_t %s;\n" name
4325 | name, FOptPercent -> pr " float %s; /* [0..100] or -1 */\n" name
4329 pr "struct guestfs_%s_list {\n" typ;
4330 pr " uint32_t len;\n";
4331 pr " struct guestfs_%s *val;\n" typ;
4334 pr "extern void guestfs_free_%s (struct guestfs_%s *);\n" typ typ;
4335 pr "extern void guestfs_free_%s_list (struct guestfs_%s_list *);\n" typ typ;
4339 (* Generate the guestfs-actions.h file. *)
4340 and generate_actions_h () =
4341 generate_header CStyle LGPLv2;
4343 fun (shortname, style, _, _, _, _, _) ->
4344 let name = "guestfs_" ^ shortname in
4345 generate_prototype ~single_line:true ~newline:true ~handle:"handle"
4349 (* Generate the client-side dispatch stubs. *)
4350 and generate_client_actions () =
4351 generate_header CStyle LGPLv2;
4357 #include \"guestfs.h\"
4358 #include \"guestfs_protocol.h\"
4360 #define error guestfs_error
4361 #define perrorf guestfs_perrorf
4362 #define safe_malloc guestfs_safe_malloc
4363 #define safe_realloc guestfs_safe_realloc
4364 #define safe_strdup guestfs_safe_strdup
4365 #define safe_memdup guestfs_safe_memdup
4367 /* Check the return message from a call for validity. */
4369 check_reply_header (guestfs_h *g,
4370 const struct guestfs_message_header *hdr,
4371 int proc_nr, int serial)
4373 if (hdr->prog != GUESTFS_PROGRAM) {
4374 error (g, \"wrong program (%%d/%%d)\", hdr->prog, GUESTFS_PROGRAM);
4377 if (hdr->vers != GUESTFS_PROTOCOL_VERSION) {
4378 error (g, \"wrong protocol version (%%d/%%d)\",
4379 hdr->vers, GUESTFS_PROTOCOL_VERSION);
4382 if (hdr->direction != GUESTFS_DIRECTION_REPLY) {
4383 error (g, \"unexpected message direction (%%d/%%d)\",
4384 hdr->direction, GUESTFS_DIRECTION_REPLY);
4387 if (hdr->proc != proc_nr) {
4388 error (g, \"unexpected procedure number (%%d/%%d)\", hdr->proc, proc_nr);
4391 if (hdr->serial != serial) {
4392 error (g, \"unexpected serial (%%d/%%d)\", hdr->serial, serial);
4399 /* Check we are in the right state to run a high-level action. */
4401 check_state (guestfs_h *g, const char *caller)
4403 if (!guestfs_is_ready (g)) {
4404 if (guestfs_is_config (g))
4405 error (g, \"%%s: call launch before using this function\\n(in guestfish, don't forget to use the 'run' command)\",
4407 else if (guestfs_is_launching (g))
4408 error (g, \"%%s: call wait_ready() before using this function\",
4411 error (g, \"%%s called from the wrong state, %%d != READY\",
4412 caller, guestfs_get_state (g));
4420 (* Client-side stubs for each function. *)
4422 fun (shortname, style, _, _, _, _, _) ->
4423 let name = "guestfs_" ^ shortname in
4425 (* Generate the context struct which stores the high-level
4426 * state between callback functions.
4428 pr "struct %s_ctx {\n" shortname;
4429 pr " /* This flag is set by the callbacks, so we know we've done\n";
4430 pr " * the callbacks as expected, and in the right sequence.\n";
4431 pr " * 0 = not called, 1 = reply_cb called.\n";
4433 pr " int cb_sequence;\n";
4434 pr " struct guestfs_message_header hdr;\n";
4435 pr " struct guestfs_message_error err;\n";
4436 (match fst style with
4438 | RConstString _ | RConstOptString _ ->
4439 failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4441 | RBool _ | RString _ | RStringList _
4442 | RStruct _ | RStructList _
4443 | RHashtable _ | RBufferOut _ ->
4444 pr " struct %s_ret ret;\n" name
4449 (* Generate the reply callback function. *)
4450 pr "static void %s_reply_cb (guestfs_h *g, void *data, XDR *xdr)\n" shortname;
4452 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
4453 pr " struct %s_ctx *ctx = (struct %s_ctx *) data;\n" shortname shortname;
4455 pr " /* This should definitely not happen. */\n";
4456 pr " if (ctx->cb_sequence != 0) {\n";
4457 pr " ctx->cb_sequence = 9999;\n";
4458 pr " error (g, \"%%s: internal error: reply callback called twice\", \"%s\");\n" name;
4462 pr " ml->main_loop_quit (ml, g);\n";
4464 pr " if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {\n";
4465 pr " error (g, \"%%s: failed to parse reply header\", \"%s\");\n" name;
4468 pr " if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {\n";
4469 pr " if (!xdr_guestfs_message_error (xdr, &ctx->err)) {\n";
4470 pr " error (g, \"%%s: failed to parse reply error\", \"%s\");\n"
4477 (match fst style with
4479 | RConstString _ | RConstOptString _ ->
4480 failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4482 | RBool _ | RString _ | RStringList _
4483 | RStruct _ | RStructList _
4484 | RHashtable _ | RBufferOut _ ->
4485 pr " if (!xdr_%s_ret (xdr, &ctx->ret)) {\n" name;
4486 pr " error (g, \"%%s: failed to parse reply\", \"%s\");\n" name;
4492 pr " ctx->cb_sequence = 1;\n";
4495 (* Generate the action stub. *)
4496 generate_prototype ~extern:false ~semicolon:false ~newline:true
4497 ~handle:"g" name style;
4500 match fst style with
4501 | RErr | RInt _ | RInt64 _ | RBool _ -> "-1"
4502 | RConstString _ | RConstOptString _ ->
4503 failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4504 | RString _ | RStringList _
4505 | RStruct _ | RStructList _
4506 | RHashtable _ | RBufferOut _ ->
4511 (match snd style with
4513 | _ -> pr " struct %s_args args;\n" name
4516 pr " struct %s_ctx ctx;\n" shortname;
4517 pr " guestfs_main_loop *ml = guestfs_get_main_loop (g);\n";
4518 pr " int serial;\n";
4520 pr " if (check_state (g, \"%s\") == -1) return %s;\n" name error_code;
4521 pr " guestfs_set_busy (g);\n";
4523 pr " memset (&ctx, 0, sizeof ctx);\n";
4526 (* Send the main header and arguments. *)
4527 (match snd style with
4529 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s, NULL, NULL);\n"
4530 (String.uppercase shortname)
4534 | Pathname n | Device n | String n ->
4535 pr " args.%s = (char *) %s;\n" n n
4537 pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n
4539 pr " args.%s.%s_val = (char **) %s;\n" n n n;
4540 pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n;
4542 pr " args.%s = %s;\n" n n
4544 pr " args.%s = %s;\n" n n
4545 | FileIn _ | FileOut _ -> ()
4547 pr " serial = guestfs__send_sync (g, GUESTFS_PROC_%s,\n"
4548 (String.uppercase shortname);
4549 pr " (xdrproc_t) xdr_%s_args, (char *) &args);\n"
4552 pr " if (serial == -1) {\n";
4553 pr " guestfs_end_busy (g);\n";
4554 pr " return %s;\n" error_code;
4558 (* Send any additional files (FileIn) requested. *)
4559 let need_read_reply_label = ref false in
4566 pr " r = guestfs__send_file_sync (g, %s);\n" n;
4567 pr " if (r == -1) {\n";
4568 pr " guestfs_end_busy (g);\n";
4569 pr " return %s;\n" error_code;
4571 pr " if (r == -2) /* daemon cancelled */\n";
4572 pr " goto read_reply;\n";
4573 need_read_reply_label := true;
4579 (* Wait for the reply from the remote end. *)
4580 if !need_read_reply_label then pr " read_reply:\n";
4581 pr " guestfs__switch_to_receiving (g);\n";
4582 pr " ctx.cb_sequence = 0;\n";
4583 pr " guestfs_set_reply_callback (g, %s_reply_cb, &ctx);\n" shortname;
4584 pr " (void) ml->main_loop_run (ml, g);\n";
4585 pr " guestfs_set_reply_callback (g, NULL, NULL);\n";
4586 pr " if (ctx.cb_sequence != 1) {\n";
4587 pr " error (g, \"%%s reply failed, see earlier error messages\", \"%s\");\n" name;
4588 pr " guestfs_end_busy (g);\n";
4589 pr " return %s;\n" error_code;
4593 pr " if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_%s, serial) == -1) {\n"
4594 (String.uppercase shortname);
4595 pr " guestfs_end_busy (g);\n";
4596 pr " return %s;\n" error_code;
4600 pr " if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {\n";
4601 pr " error (g, \"%%s\", ctx.err.error_message);\n";
4602 pr " free (ctx.err.error_message);\n";
4603 pr " guestfs_end_busy (g);\n";
4604 pr " return %s;\n" error_code;
4608 (* Expecting to receive further files (FileOut)? *)
4612 pr " if (guestfs__receive_file_sync (g, %s) == -1) {\n" n;
4613 pr " guestfs_end_busy (g);\n";
4614 pr " return %s;\n" error_code;
4620 pr " guestfs_end_busy (g);\n";
4622 (match fst style with
4623 | RErr -> pr " return 0;\n"
4624 | RInt n | RInt64 n | RBool n ->
4625 pr " return ctx.ret.%s;\n" n
4626 | RConstString _ | RConstOptString _ ->
4627 failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4629 pr " return ctx.ret.%s; /* caller will free */\n" n
4630 | RStringList n | RHashtable n ->
4631 pr " /* caller will free this, but we need to add a NULL entry */\n";
4632 pr " ctx.ret.%s.%s_val =\n" n n;
4633 pr " safe_realloc (g, ctx.ret.%s.%s_val,\n" n n;
4634 pr " sizeof (char *) * (ctx.ret.%s.%s_len + 1));\n"
4636 pr " ctx.ret.%s.%s_val[ctx.ret.%s.%s_len] = NULL;\n" n n n n;
4637 pr " return ctx.ret.%s.%s_val;\n" n n
4639 pr " /* caller will free this */\n";
4640 pr " return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
4641 | RStructList (n, _) ->
4642 pr " /* caller will free this */\n";
4643 pr " return safe_memdup (g, &ctx.ret.%s, sizeof (ctx.ret.%s));\n" n n
4645 pr " *size_r = ctx.ret.%s.%s_len;\n" n n;
4646 pr " return ctx.ret.%s.%s_val; /* caller will free */\n" n n
4652 (* Functions to free structures. *)
4653 pr "/* Structure-freeing functions. These rely on the fact that the\n";
4654 pr " * structure format is identical to the XDR format. See note in\n";
4655 pr " * generator.ml.\n";
4662 pr "guestfs_free_%s (struct guestfs_%s *x)\n" typ typ;
4664 pr " xdr_free ((xdrproc_t) xdr_guestfs_int_%s, (char *) x);\n" typ;
4670 pr "guestfs_free_%s_list (struct guestfs_%s_list *x)\n" typ typ;
4672 pr " xdr_free ((xdrproc_t) xdr_guestfs_int_%s_list, (char *) x);\n" typ;
4679 (* Generate daemon/actions.h. *)
4680 and generate_daemon_actions_h () =
4681 generate_header CStyle GPLv2;
4683 pr "#include \"../src/guestfs_protocol.h\"\n";
4687 fun (name, style, _, _, _, _, _) ->
4689 ~single_line:true ~newline:true ~in_daemon:true ~prefix:"do_"
4693 (* Generate the server-side stubs. *)
4694 and generate_daemon_actions () =
4695 generate_header CStyle GPLv2;
4697 pr "#include <config.h>\n";
4699 pr "#include <stdio.h>\n";
4700 pr "#include <stdlib.h>\n";
4701 pr "#include <string.h>\n";
4702 pr "#include <inttypes.h>\n";
4703 pr "#include <ctype.h>\n";
4704 pr "#include <rpc/types.h>\n";
4705 pr "#include <rpc/xdr.h>\n";
4707 pr "#include \"daemon.h\"\n";
4708 pr "#include \"../src/guestfs_protocol.h\"\n";
4709 pr "#include \"actions.h\"\n";
4713 fun (name, style, _, _, _, _, _) ->
4714 (* Generate server-side stubs. *)
4715 pr "static void %s_stub (XDR *xdr_in)\n" name;
4718 match fst style with
4719 | RErr | RInt _ -> pr " int r;\n"; "-1"
4720 | RInt64 _ -> pr " int64_t r;\n"; "-1"
4721 | RBool _ -> pr " int r;\n"; "-1"
4722 | RConstString _ | RConstOptString _ ->
4723 failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4724 | RString _ -> pr " char *r;\n"; "NULL"
4725 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
4726 | RStruct (_, typ) -> pr " guestfs_int_%s *r;\n" typ; "NULL"
4727 | RStructList (_, typ) -> pr " guestfs_int_%s_list *r;\n" typ; "NULL"
4729 pr " size_t size;\n";
4733 (match snd style with
4736 pr " struct guestfs_%s_args args;\n" name;
4742 | OptString n -> pr " char *%s;\n" n
4743 | StringList n -> pr " char **%s;\n" n
4744 | Bool n -> pr " int %s;\n" n
4745 | Int n -> pr " int %s;\n" n
4746 | FileIn _ | FileOut _ -> ()
4751 (match snd style with
4754 pr " memset (&args, 0, sizeof args);\n";
4756 pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name;
4757 pr " reply_with_error (\"%%s: daemon failed to decode procedure arguments\", \"%s\");\n" name;
4763 pr " char *%s = args.%s;\n" n n;
4764 pr " ABS_PATH (%s, goto done);\n" n;
4766 pr " char *%s = args.%s;\n" n n;
4767 pr " RESOLVE_DEVICE (%s, goto done);" n;
4768 | String n -> pr " char *%s = args.%s;\n" n n
4769 | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n
4771 pr " %s = realloc (args.%s.%s_val,\n" n n n;
4772 pr " sizeof (char *) * (args.%s.%s_len+1));\n" n n;
4773 pr " if (%s == NULL) {\n" n;
4774 pr " reply_with_perror (\"realloc\");\n";
4777 pr " %s[args.%s.%s_len] = NULL;\n" n n n;
4778 pr " args.%s.%s_val = %s;\n" n n n;
4779 | Bool n -> pr " %s = args.%s;\n" n n
4780 | Int n -> pr " %s = args.%s;\n" n n
4781 | FileIn _ | FileOut _ -> ()
4786 (* this is used at least for do_equal *)
4787 if List.exists (function Pathname _ -> true | _ -> false) (snd style) then (
4788 (* Emit NEED_ROOT just once, even when there are two or
4789 more Pathname args *)
4790 pr " NEED_ROOT (goto done);\n";
4793 (* Don't want to call the impl with any FileIn or FileOut
4794 * parameters, since these go "outside" the RPC protocol.
4797 List.filter (function FileIn _ | FileOut _ -> false | _ -> true)
4799 pr " r = do_%s " name;
4800 generate_c_call_args (fst style, args');
4803 pr " if (r == %s)\n" error_code;
4804 pr " /* do_%s has already called reply_with_error */\n" name;
4808 (* If there are any FileOut parameters, then the impl must
4809 * send its own reply.
4812 List.exists (function FileOut _ -> true | _ -> false) (snd style) in
4814 pr " /* do_%s has already sent a reply */\n" name
4816 match fst style with
4817 | RErr -> pr " reply (NULL, NULL);\n"
4818 | RInt n | RInt64 n | RBool n ->
4819 pr " struct guestfs_%s_ret ret;\n" name;
4820 pr " ret.%s = r;\n" n;
4821 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4823 | RConstString _ | RConstOptString _ ->
4824 failwithf "RConstString|RConstOptString cannot be used by daemon functions"
4826 pr " struct guestfs_%s_ret ret;\n" name;
4827 pr " ret.%s = r;\n" n;
4828 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4831 | RStringList n | RHashtable n ->
4832 pr " struct guestfs_%s_ret ret;\n" name;
4833 pr " ret.%s.%s_len = count_strings (r);\n" n n;
4834 pr " ret.%s.%s_val = r;\n" n n;
4835 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4837 pr " free_strings (r);\n"
4839 pr " struct guestfs_%s_ret ret;\n" name;
4840 pr " ret.%s = *r;\n" n;
4841 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4843 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4845 | RStructList (n, _) ->
4846 pr " struct guestfs_%s_ret ret;\n" name;
4847 pr " ret.%s = *r;\n" n;
4848 pr " reply ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4850 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n"
4853 pr " struct guestfs_%s_ret ret;\n" name;
4854 pr " ret.%s.%s_val = r;\n" n n;
4855 pr " ret.%s.%s_len = size;\n" n n;
4856 pr " reply ((xdrproc_t) &xdr_guestfs_%s_ret, (char *) &ret);\n"
4861 (* Free the args. *)
4862 (match snd style with
4867 pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n"
4874 (* Dispatch function. *)
4875 pr "void dispatch_incoming_message (XDR *xdr_in)\n";
4877 pr " switch (proc_nr) {\n";
4880 fun (name, style, _, _, _, _, _) ->
4881 pr " case GUESTFS_PROC_%s:\n" (String.uppercase name);
4882 pr " %s_stub (xdr_in);\n" name;
4887 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";
4892 (* LVM columns and tokenization functions. *)
4893 (* XXX This generates crap code. We should rethink how we
4899 pr "static const char *lvm_%s_cols = \"%s\";\n"
4900 typ (String.concat "," (List.map fst cols));
4903 pr "static int lvm_tokenize_%s (char *str, guestfs_int_lvm_%s *r)\n" typ typ;
4905 pr " char *tok, *p, *next;\n";
4909 pr " fprintf (stderr, \"%%s: <<%%s>>\\n\", __func__, str);\n";
4912 pr " if (!str) {\n";
4913 pr " fprintf (stderr, \"%%s: failed: passed a NULL string\\n\", __func__);\n";
4916 pr " if (!*str || isspace (*str)) {\n";
4917 pr " fprintf (stderr, \"%%s: failed: passed a empty string or one beginning with whitespace\\n\", __func__);\n";
4922 fun (name, coltype) ->
4923 pr " if (!tok) {\n";
4924 pr " fprintf (stderr, \"%%s: failed: string finished early, around token %%s\\n\", __func__, \"%s\");\n" name;
4927 pr " p = strchrnul (tok, ',');\n";
4928 pr " if (*p) next = p+1; else next = NULL;\n";
4929 pr " *p = '\\0';\n";
4932 pr " r->%s = strdup (tok);\n" name;
4933 pr " if (r->%s == NULL) {\n" name;
4934 pr " perror (\"strdup\");\n";
4938 pr " for (i = j = 0; i < 32; ++j) {\n";
4939 pr " if (tok[j] == '\\0') {\n";
4940 pr " fprintf (stderr, \"%%s: failed to parse UUID from '%%s'\\n\", __func__, tok);\n";
4942 pr " } else if (tok[j] != '-')\n";
4943 pr " r->%s[i++] = tok[j];\n" name;
4946 pr " if (sscanf (tok, \"%%\"SCNu64, &r->%s) != 1) {\n" name;
4947 pr " fprintf (stderr, \"%%s: failed to parse size '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4951 pr " if (sscanf (tok, \"%%\"SCNi64, &r->%s) != 1) {\n" name;
4952 pr " fprintf (stderr, \"%%s: failed to parse int '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4956 pr " if (tok[0] == '\\0')\n";
4957 pr " r->%s = -1;\n" name;
4958 pr " else if (sscanf (tok, \"%%f\", &r->%s) != 1) {\n" name;
4959 pr " fprintf (stderr, \"%%s: failed to parse float '%%s' from token %%s\\n\", __func__, tok, \"%s\");\n" name;
4962 | FBuffer | FInt32 | FUInt32 | FUInt64 | FChar ->
4963 assert false (* can never be an LVM column *)
4965 pr " tok = next;\n";
4968 pr " if (tok != NULL) {\n";
4969 pr " fprintf (stderr, \"%%s: failed: extra tokens at end of string\\n\", __func__);\n";
4976 pr "guestfs_int_lvm_%s_list *\n" typ;
4977 pr "parse_command_line_%ss (void)\n" typ;
4979 pr " char *out, *err;\n";
4980 pr " char *p, *pend;\n";
4982 pr " guestfs_int_lvm_%s_list *ret;\n" typ;
4983 pr " void *newp;\n";
4985 pr " ret = malloc (sizeof *ret);\n";
4986 pr " if (!ret) {\n";
4987 pr " reply_with_perror (\"malloc\");\n";
4988 pr " return NULL;\n";
4991 pr " ret->guestfs_int_lvm_%s_list_len = 0;\n" typ;
4992 pr " ret->guestfs_int_lvm_%s_list_val = NULL;\n" typ;
4994 pr " r = command (&out, &err,\n";
4995 pr " \"/sbin/lvm\", \"%ss\",\n" typ;
4996 pr " \"-o\", lvm_%s_cols, \"--unbuffered\", \"--noheadings\",\n" typ;
4997 pr " \"--nosuffix\", \"--separator\", \",\", \"--units\", \"b\", NULL);\n";
4998 pr " if (r == -1) {\n";
4999 pr " reply_with_error (\"%%s\", err);\n";
5000 pr " free (out);\n";
5001 pr " free (err);\n";
5002 pr " free (ret);\n";
5003 pr " return NULL;\n";
5006 pr " free (err);\n";
5008 pr " /* Tokenize each line of the output. */\n";
5011 pr " while (p) {\n";
5012 pr " pend = strchr (p, '\\n'); /* Get the next line of output. */\n";
5013 pr " if (pend) {\n";
5014 pr " *pend = '\\0';\n";
5018 pr " while (*p && isspace (*p)) /* Skip any leading whitespace. */\n";
5021 pr " if (!*p) { /* Empty line? Skip it. */\n";
5026 pr " /* Allocate some space to store this next entry. */\n";
5027 pr " newp = realloc (ret->guestfs_int_lvm_%s_list_val,\n" typ;
5028 pr " sizeof (guestfs_int_lvm_%s) * (i+1));\n" typ;
5029 pr " if (newp == NULL) {\n";
5030 pr " reply_with_perror (\"realloc\");\n";
5031 pr " free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
5032 pr " free (ret);\n";
5033 pr " free (out);\n";
5034 pr " return NULL;\n";
5036 pr " ret->guestfs_int_lvm_%s_list_val = newp;\n" typ;
5038 pr " /* Tokenize the next entry. */\n";
5039 pr " r = lvm_tokenize_%s (p, &ret->guestfs_int_lvm_%s_list_val[i]);\n" typ typ;
5040 pr " if (r == -1) {\n";
5041 pr " reply_with_error (\"failed to parse output of '%ss' command\");\n" typ;
5042 pr " free (ret->guestfs_int_lvm_%s_list_val);\n" typ;
5043 pr " free (ret);\n";
5044 pr " free (out);\n";
5045 pr " return NULL;\n";
5052 pr " ret->guestfs_int_lvm_%s_list_len = i;\n" typ;
5054 pr " free (out);\n";
5055 pr " return ret;\n";
5058 ) ["pv", lvm_pv_cols; "vg", lvm_vg_cols; "lv", lvm_lv_cols]
5060 (* Generate a list of function names, for debugging in the daemon.. *)
5061 and generate_daemon_names () =
5062 generate_header CStyle GPLv2;
5064 pr "#include <config.h>\n";
5066 pr "#include \"daemon.h\"\n";
5069 pr "/* This array is indexed by proc_nr. See guestfs_protocol.x. */\n";
5070 pr "const char *function_names[] = {\n";
5072 fun (name, _, proc_nr, _, _, _, _) -> pr " [%d] = \"%s\",\n" proc_nr name
5076 (* Generate the tests. *)
5077 and generate_tests () =
5078 generate_header CStyle GPLv2;
5085 #include <sys/types.h>
5088 #include \"guestfs.h\"
5090 static guestfs_h *g;
5091 static int suppress_error = 0;
5093 static void print_error (guestfs_h *g, void *data, const char *msg)
5095 if (!suppress_error)
5096 fprintf (stderr, \"%%s\\n\", msg);
5099 static void print_strings (char * const * const argv)
5103 for (argc = 0; argv[argc] != NULL; ++argc)
5104 printf (\"\\t%%s\\n\", argv[argc]);
5108 static void print_table (char * const * const argv)
5112 for (i = 0; argv[i] != NULL; i += 2)
5113 printf (\"%%s: %%s\\n\", argv[i], argv[i+1]);
5119 (* Generate a list of commands which are not tested anywhere. *)
5120 pr "static void no_test_warnings (void)\n";
5123 let hash : (string, bool) Hashtbl.t = Hashtbl.create 13 in
5125 fun (_, _, _, _, tests, _, _) ->
5126 let tests = filter_map (
5128 | (_, (Always|If _|Unless _), test) -> Some test
5129 | (_, Disabled, _) -> None
5131 let seq = List.concat (List.map seq_of_test tests) in
5132 let cmds_tested = List.map List.hd seq in
5133 List.iter (fun cmd -> Hashtbl.replace hash cmd true) cmds_tested
5137 fun (name, _, _, _, _, _, _) ->
5138 if not (Hashtbl.mem hash name) then
5139 pr " fprintf (stderr, \"warning: \\\"guestfs_%s\\\" has no tests\\n\");\n" name
5145 (* Generate the actual tests. Note that we generate the tests
5146 * in reverse order, deliberately, so that (in general) the
5147 * newest tests run first. This makes it quicker and easier to
5152 fun (name, _, _, _, tests, _, _) ->
5153 mapi (generate_one_test name) tests
5154 ) (List.rev all_functions) in
5155 let test_names = List.concat test_names in
5156 let nr_tests = List.length test_names in
5159 int main (int argc, char *argv[])
5163 const char *filename;
5165 int nr_tests, test_num = 0;
5167 setbuf (stdout, NULL);
5169 no_test_warnings ();
5171 g = guestfs_create ();
5173 printf (\"guestfs_create FAILED\\n\");
5177 guestfs_set_error_handler (g, print_error, NULL);
5179 guestfs_set_path (g, \"../appliance\");
5181 filename = \"test1.img\";
5182 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
5187 if (lseek (fd, %d, SEEK_SET) == -1) {
5193 if (write (fd, &c, 1) == -1) {
5199 if (close (fd) == -1) {
5204 if (guestfs_add_drive (g, filename) == -1) {
5205 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
5209 filename = \"test2.img\";
5210 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
5215 if (lseek (fd, %d, SEEK_SET) == -1) {
5221 if (write (fd, &c, 1) == -1) {
5227 if (close (fd) == -1) {
5232 if (guestfs_add_drive (g, filename) == -1) {
5233 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
5237 filename = \"test3.img\";
5238 fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666);
5243 if (lseek (fd, %d, SEEK_SET) == -1) {
5249 if (write (fd, &c, 1) == -1) {
5255 if (close (fd) == -1) {
5260 if (guestfs_add_drive (g, filename) == -1) {
5261 printf (\"guestfs_add_drive %%s FAILED\\n\", filename);
5265 if (guestfs_add_drive_ro (g, \"../images/test.sqsh\") == -1) {
5266 printf (\"guestfs_add_drive_ro ../images/test.sqsh FAILED\\n\");
5270 if (guestfs_launch (g) == -1) {
5271 printf (\"guestfs_launch FAILED\\n\");
5275 /* Set a timeout in case qemu hangs during launch (RHBZ#505329). */
5278 if (guestfs_wait_ready (g) == -1) {
5279 printf (\"guestfs_wait_ready FAILED\\n\");
5283 /* Cancel previous alarm. */
5288 " (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024) nr_tests;
5292 pr " test_num++;\n";
5293 pr " printf (\"%%3d/%%3d %s\\n\", test_num, nr_tests);\n" test_name;
5294 pr " if (%s () == -1) {\n" test_name;
5295 pr " printf (\"%s FAILED\\n\");\n" test_name;
5301 pr " guestfs_close (g);\n";
5302 pr " unlink (\"test1.img\");\n";
5303 pr " unlink (\"test2.img\");\n";
5304 pr " unlink (\"test3.img\");\n";
5307 pr " if (failed > 0) {\n";
5308 pr " printf (\"***** %%d / %%d tests FAILED *****\\n\", failed, nr_tests);\n";
5316 and generate_one_test name i (init, prereq, test) =
5317 let test_name = sprintf "test_%s_%d" name i in
5320 static int %s_skip (void)
5324 str = getenv (\"TEST_ONLY\");
5326 return strstr (str, \"%s\") == NULL;
5327 str = getenv (\"SKIP_%s\");
5328 if (str && strcmp (str, \"1\") == 0) return 1;
5329 str = getenv (\"SKIP_TEST_%s\");
5330 if (str && strcmp (str, \"1\") == 0) return 1;
5334 " test_name name (String.uppercase test_name) (String.uppercase name);
5337 | Disabled | Always -> ()
5338 | If code | Unless code ->
5339 pr "static int %s_prereq (void)\n" test_name;
5347 static int %s (void)
5350 printf (\" %%s skipped (reason: environment variable set)\\n\", \"%s\");
5354 " test_name test_name test_name;
5358 pr " printf (\" %%s skipped (reason: test disabled in generator)\\n\", \"%s\");\n" test_name
5360 pr " if (! %s_prereq ()) {\n" test_name;
5361 pr " printf (\" %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
5365 generate_one_test_body name i test_name init test;
5367 pr " if (%s_prereq ()) {\n" test_name;
5368 pr " printf (\" %%s skipped (reason: test prerequisite)\\n\", \"%s\");\n" test_name;
5372 generate_one_test_body name i test_name init test;
5374 generate_one_test_body name i test_name init test
5382 and generate_one_test_body name i test_name init test =
5384 | InitNone (* XXX at some point, InitNone and InitEmpty became
5385 * folded together as the same thing. Really we should
5386 * make InitNone do nothing at all, but the tests may
5387 * need to be checked to make sure this is OK.
5390 pr " /* InitNone|InitEmpty for %s */\n" test_name;
5391 List.iter (generate_test_command_call test_name)
5392 [["blockdev_setrw"; "/dev/sda"];
5396 pr " /* InitPartition for %s: create /dev/sda1 */\n" test_name;
5397 List.iter (generate_test_command_call test_name)
5398 [["blockdev_setrw"; "/dev/sda"];
5401 ["sfdiskM"; "/dev/sda"; ","]]
5403 pr " /* InitBasicFS for %s: create ext2 on /dev/sda1 */\n" test_name;
5404 List.iter (generate_test_command_call test_name)
5405 [["blockdev_setrw"; "/dev/sda"];
5408 ["sfdiskM"; "/dev/sda"; ","];
5409 ["mkfs"; "ext2"; "/dev/sda1"];
5410 ["mount"; "/dev/sda1"; "/"]]
5411 | InitBasicFSonLVM ->
5412 pr " /* InitBasicFSonLVM for %s: create ext2 on /dev/VG/LV */\n"
5414 List.iter (generate_test_command_call test_name)
5415 [["blockdev_setrw"; "/dev/sda"];
5418 ["sfdiskM"; "/dev/sda"; ","];
5419 ["pvcreate"; "/dev/sda1"];
5420 ["vgcreate"; "VG"; "/dev/sda1"];
5421 ["lvcreate"; "LV"; "VG"; "8"];
5422 ["mkfs"; "ext2"; "/dev/VG/LV"];
5423 ["mount"; "/dev/VG/LV"; "/"]]
5425 pr " /* InitSquashFS for %s */\n" test_name;
5426 List.iter (generate_test_command_call test_name)
5427 [["blockdev_setrw"; "/dev/sda"];
5430 ["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"]]
5433 let get_seq_last = function
5435 failwithf "%s: you cannot use [] (empty list) when expecting a command"
5438 let seq = List.rev seq in
5439 List.rev (List.tl seq), List.hd seq
5444 pr " /* TestRun for %s (%d) */\n" name i;
5445 List.iter (generate_test_command_call test_name) seq
5446 | TestOutput (seq, expected) ->
5447 pr " /* TestOutput for %s (%d) */\n" name i;
5448 pr " const char *expected = \"%s\";\n" (c_quote expected);
5449 let seq, last = get_seq_last seq in
5451 pr " if (strcmp (r, expected) != 0) {\n";
5452 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
5456 List.iter (generate_test_command_call test_name) seq;
5457 generate_test_command_call ~test test_name last
5458 | TestOutputList (seq, expected) ->
5459 pr " /* TestOutputList for %s (%d) */\n" name i;
5460 let seq, last = get_seq_last seq in
5464 pr " if (!r[%d]) {\n" i;
5465 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
5466 pr " print_strings (r);\n";
5470 pr " const char *expected = \"%s\";\n" (c_quote str);
5471 pr " if (strcmp (r[%d], expected) != 0) {\n" i;
5472 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
5477 pr " if (r[%d] != NULL) {\n" (List.length expected);
5478 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
5480 pr " print_strings (r);\n";
5484 List.iter (generate_test_command_call test_name) seq;
5485 generate_test_command_call ~test test_name last
5486 | TestOutputListOfDevices (seq, expected) ->
5487 pr " /* TestOutputListOfDevices for %s (%d) */\n" name i;
5488 let seq, last = get_seq_last seq in
5492 pr " if (!r[%d]) {\n" i;
5493 pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name;
5494 pr " print_strings (r);\n";
5498 pr " const char *expected = \"%s\";\n" (c_quote str);
5499 pr " r[%d][5] = 's';\n" i;
5500 pr " if (strcmp (r[%d], expected) != 0) {\n" i;
5501 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r[%d]);\n" test_name i;
5506 pr " if (r[%d] != NULL) {\n" (List.length expected);
5507 pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n"
5509 pr " print_strings (r);\n";
5513 List.iter (generate_test_command_call test_name) seq;
5514 generate_test_command_call ~test test_name last
5515 | TestOutputInt (seq, expected) ->
5516 pr " /* TestOutputInt for %s (%d) */\n" name i;
5517 let seq, last = get_seq_last seq in
5519 pr " if (r != %d) {\n" expected;
5520 pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\","
5526 List.iter (generate_test_command_call test_name) seq;
5527 generate_test_command_call ~test test_name last
5528 | TestOutputIntOp (seq, op, expected) ->
5529 pr " /* TestOutputIntOp for %s (%d) */\n" name i;
5530 let seq, last = get_seq_last seq in
5532 pr " if (! (r %s %d)) {\n" op expected;
5533 pr " fprintf (stderr, \"%s: expected %s %d but got %%d\\n\","
5534 test_name op expected;
5539 List.iter (generate_test_command_call test_name) seq;
5540 generate_test_command_call ~test test_name last
5541 | TestOutputTrue seq ->
5542 pr " /* TestOutputTrue for %s (%d) */\n" name i;
5543 let seq, last = get_seq_last seq in
5546 pr " fprintf (stderr, \"%s: expected true, got false\\n\");\n"
5551 List.iter (generate_test_command_call test_name) seq;
5552 generate_test_command_call ~test test_name last
5553 | TestOutputFalse seq ->
5554 pr " /* TestOutputFalse for %s (%d) */\n" name i;
5555 let seq, last = get_seq_last seq in
5558 pr " fprintf (stderr, \"%s: expected false, got true\\n\");\n"
5563 List.iter (generate_test_command_call test_name) seq;
5564 generate_test_command_call ~test test_name last
5565 | TestOutputLength (seq, expected) ->
5566 pr " /* TestOutputLength for %s (%d) */\n" name i;
5567 let seq, last = get_seq_last seq in
5570 pr " for (j = 0; j < %d; ++j)\n" expected;
5571 pr " if (r[j] == NULL) {\n";
5572 pr " fprintf (stderr, \"%s: short list returned\\n\");\n"
5574 pr " print_strings (r);\n";
5577 pr " if (r[j] != NULL) {\n";
5578 pr " fprintf (stderr, \"%s: long list returned\\n\");\n"
5580 pr " print_strings (r);\n";
5584 List.iter (generate_test_command_call test_name) seq;
5585 generate_test_command_call ~test test_name last
5586 | TestOutputBuffer (seq, expected) ->
5587 pr " /* TestOutputBuffer for %s (%d) */\n" name i;
5588 pr " const char *expected = \"%s\";\n" (c_quote expected);
5589 let seq, last = get_seq_last seq in
5590 let len = String.length expected in
5592 pr " if (size != %d) {\n" len;
5593 pr " fprintf (stderr, \"%s: returned size of buffer wrong, expected %d but got %%zu\\n\", size);\n" test_name len;
5596 pr " if (strncmp (r, expected, size) != 0) {\n";
5597 pr " fprintf (stderr, \"%s: expected \\\"%%s\\\" but got \\\"%%s\\\"\\n\", expected, r);\n" test_name;
5601 List.iter (generate_test_command_call test_name) seq;
5602 generate_test_command_call ~test test_name last
5603 | TestOutputStruct (seq, checks) ->
5604 pr " /* TestOutputStruct for %s (%d) */\n" name i;
5605 let seq, last = get_seq_last seq in
5609 | CompareWithInt (field, expected) ->
5610 pr " if (r->%s != %d) {\n" field expected;
5611 pr " fprintf (stderr, \"%s: %s was %%d, expected %d\\n\",\n"
5612 test_name field expected;
5613 pr " (int) r->%s);\n" field;
5616 | CompareWithIntOp (field, op, expected) ->
5617 pr " if (!(r->%s %s %d)) {\n" field op expected;
5618 pr " fprintf (stderr, \"%s: %s was %%d, expected %s %d\\n\",\n"
5619 test_name field op expected;
5620 pr " (int) r->%s);\n" field;
5623 | CompareWithString (field, expected) ->
5624 pr " if (strcmp (r->%s, \"%s\") != 0) {\n" field expected;
5625 pr " fprintf (stderr, \"%s: %s was \"%%s\", expected \"%s\"\\n\",\n"
5626 test_name field expected;
5627 pr " r->%s);\n" field;
5630 | CompareFieldsIntEq (field1, field2) ->
5631 pr " if (r->%s != r->%s) {\n" field1 field2;
5632 pr " fprintf (stderr, \"%s: %s (%%d) <> %s (%%d)\\n\",\n"
5633 test_name field1 field2;
5634 pr " (int) r->%s, (int) r->%s);\n" field1 field2;
5637 | CompareFieldsStrEq (field1, field2) ->
5638 pr " if (strcmp (r->%s, r->%s) != 0) {\n" field1 field2;
5639 pr " fprintf (stderr, \"%s: %s (\"%%s\") <> %s (\"%%s\")\\n\",\n"
5640 test_name field1 field2;
5641 pr " r->%s, r->%s);\n" field1 field2;
5646 List.iter (generate_test_command_call test_name) seq;
5647 generate_test_command_call ~test test_name last
5648 | TestLastFail seq ->
5649 pr " /* TestLastFail for %s (%d) */\n" name i;
5650 let seq, last = get_seq_last seq in
5651 List.iter (generate_test_command_call test_name) seq;
5652 generate_test_command_call test_name ~expect_error:true last
5654 (* Generate the code to run a command, leaving the result in 'r'.
5655 * If you expect to get an error then you should set expect_error:true.
5657 and generate_test_command_call ?(expect_error = false) ?test test_name cmd =
5659 | [] -> assert false
5661 (* Look up the command to find out what args/ret it has. *)
5664 let _, style, _, _, _, _, _ =
5665 List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in
5668 failwithf "%s: in test, command %s was not found" test_name name in
5670 if List.length (snd style) <> List.length args then
5671 failwithf "%s: in test, wrong number of args given to %s"
5678 | OptString n, "NULL" -> ()
5682 | OptString n, arg ->
5683 pr " const char *%s = \"%s\";\n" n (c_quote arg);
5686 | FileIn _, _ | FileOut _, _ -> ()
5687 | StringList n, arg ->
5688 let strs = string_split " " arg in
5691 pr " const char *%s_%d = \"%s\";\n" n i (c_quote str);
5693 pr " const char *%s[] = {\n" n;
5695 fun i _ -> pr " %s_%d,\n" n i
5699 ) (List.combine (snd style) args);
5702 match fst style with
5703 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
5704 | RInt64 _ -> pr " int64_t r;\n"; "-1"
5705 | RConstString _ | RConstOptString _ ->
5706 pr " const char *r;\n"; "NULL"
5707 | RString _ -> pr " char *r;\n"; "NULL"
5708 | RStringList _ | RHashtable _ ->
5712 | RStruct (_, typ) ->
5713 pr " struct guestfs_%s *r;\n" typ; "NULL"
5714 | RStructList (_, typ) ->
5715 pr " struct guestfs_%s_list *r;\n" typ; "NULL"
5718 pr " size_t size;\n";
5721 pr " suppress_error = %d;\n" (if expect_error then 1 else 0);
5722 pr " r = guestfs_%s (g" name;
5724 (* Generate the parameters. *)
5727 | OptString _, "NULL" -> pr ", NULL"
5733 | FileIn _, arg | FileOut _, arg ->
5734 pr ", \"%s\"" (c_quote arg)
5735 | StringList n, _ ->
5739 try int_of_string arg
5740 with Failure "int_of_string" ->
5741 failwithf "%s: expecting an int, but got '%s'" test_name arg in
5744 let b = bool_of_string arg in pr ", %d" (if b then 1 else 0)
5745 ) (List.combine (snd style) args);
5747 (match fst style with
5748 | RBufferOut _ -> pr ", &size"
5754 if not expect_error then
5755 pr " if (r == %s)\n" error_code
5757 pr " if (r != %s)\n" error_code;
5760 (* Insert the test code. *)
5766 (match fst style with
5767 | RErr | RInt _ | RInt64 _ | RBool _
5768 | RConstString _ | RConstOptString _ -> ()
5769 | RString _ | RBufferOut _ -> pr " free (r);\n"
5770 | RStringList _ | RHashtable _ ->
5771 pr " for (i = 0; r[i] != NULL; ++i)\n";
5772 pr " free (r[i]);\n";
5774 | RStruct (_, typ) ->
5775 pr " guestfs_free_%s (r);\n" typ
5776 | RStructList (_, typ) ->
5777 pr " guestfs_free_%s_list (r);\n" typ
5783 let str = replace_str str "\r" "\\r" in
5784 let str = replace_str str "\n" "\\n" in
5785 let str = replace_str str "\t" "\\t" in
5786 let str = replace_str str "\000" "\\0" in
5789 (* Generate a lot of different functions for guestfish. *)
5790 and generate_fish_cmds () =
5791 generate_header CStyle GPLv2;
5795 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5797 let all_functions_sorted =
5799 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
5800 ) all_functions_sorted in
5802 pr "#include <stdio.h>\n";
5803 pr "#include <stdlib.h>\n";
5804 pr "#include <string.h>\n";
5805 pr "#include <inttypes.h>\n";
5806 pr "#include <ctype.h>\n";
5808 pr "#include <guestfs.h>\n";
5809 pr "#include \"fish.h\"\n";
5812 (* list_commands function, which implements guestfish -h *)
5813 pr "void list_commands (void)\n";
5815 pr " printf (\" %%-16s %%s\\n\", _(\"Command\"), _(\"Description\"));\n";
5816 pr " list_builtin_commands ();\n";
5818 fun (name, _, _, flags, _, shortdesc, _) ->
5819 let name = replace_char name '_' '-' in
5820 pr " printf (\"%%-20s %%s\\n\", \"%s\", _(\"%s\"));\n"
5822 ) all_functions_sorted;
5823 pr " printf (\" %%s\\n\",";
5824 pr " _(\"Use -h <cmd> / help <cmd> to show detailed help for a command.\"));\n";
5828 (* display_command function, which implements guestfish -h cmd *)
5829 pr "void display_command (const char *cmd)\n";
5832 fun (name, style, _, flags, _, shortdesc, longdesc) ->
5833 let name2 = replace_char name '_' '-' in
5835 try find_map (function FishAlias n -> Some n | _ -> None) flags
5836 with Not_found -> name in
5837 let longdesc = replace_str longdesc "C<guestfs_" "C<" in
5839 match snd style with
5843 name2 (String.concat "> <" (List.map name_of_argt args)) in
5846 if List.mem ProtocolLimitWarning flags then
5847 ("\n\n" ^ protocol_limit_warning)
5850 (* For DangerWillRobinson commands, we should probably have
5851 * guestfish prompt before allowing you to use them (especially
5852 * in interactive mode). XXX
5856 if List.mem DangerWillRobinson flags then
5857 ("\n\n" ^ danger_will_robinson)
5862 match deprecation_notice flags with
5864 | Some txt -> "\n\n" ^ txt in
5866 let describe_alias =
5867 if name <> alias then
5868 sprintf "\n\nYou can use '%s' as an alias for this command." alias
5872 pr "strcasecmp (cmd, \"%s\") == 0" name;
5873 if name <> name2 then
5874 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
5875 if name <> alias then
5876 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
5878 pr " pod2text (\"%s\", _(\"%s\"), %S);\n"
5880 (" " ^ synopsis ^ "\n\n" ^ longdesc ^ warnings ^ describe_alias);
5883 pr " display_builtin_command (cmd);\n";
5887 (* print_* functions *)
5891 List.exists (function (_, (FUUID|FBuffer)) -> true | _ -> false) cols in
5893 pr "static void print_%s_indent (struct guestfs_%s *%s, const char *indent)\n" typ typ typ;
5902 pr " printf (\"%%s%s: %%s\\n\", indent, %s->%s);\n" name typ name
5904 pr " printf (\"%s: \");\n" name;
5905 pr " for (i = 0; i < 32; ++i)\n";
5906 pr " printf (\"%%s%%c\", indent, %s->%s[i]);\n" typ name;
5907 pr " printf (\"\\n\");\n"
5909 pr " printf (\"%%s%s: \", indent);\n" name;
5910 pr " for (i = 0; i < %s->%s_len; ++i)\n" typ name;
5911 pr " if (isprint (%s->%s[i]))\n" typ name;
5912 pr " printf (\"%%s%%c\", indent, %s->%s[i]);\n" typ name;
5914 pr " printf (\"%%s\\\\x%%02x\", indent, %s->%s[i]);\n" typ name;
5915 pr " printf (\"\\n\");\n"
5916 | name, (FUInt64|FBytes) ->
5917 pr " printf (\"%%s%s: %%\" PRIu64 \"\\n\", indent, %s->%s);\n"
5920 pr " printf (\"%%s%s: %%\" PRIi64 \"\\n\", indent, %s->%s);\n"
5923 pr " printf (\"%%s%s: %%\" PRIu32 \"\\n\", indent, %s->%s);\n"
5926 pr " printf (\"%%s%s: %%\" PRIi32 \"\\n\", indent, %s->%s);\n"
5929 pr " printf (\"%%s%s: %%c\\n\", indent, %s->%s);\n"
5931 | name, FOptPercent ->
5932 pr " if (%s->%s >= 0) printf (\"%%s%s: %%g %%%%\\n\", indent, %s->%s);\n"
5933 typ name name typ name;
5934 pr " else printf (\"%%s%s: \\n\", indent);\n" name
5938 pr "static void print_%s (struct guestfs_%s *%s)\n" typ typ typ;
5940 pr " print_%s_indent (%s, \"\");\n" typ typ;
5943 pr "static void print_%s_list (struct guestfs_%s_list *%ss)\n"
5948 pr " for (i = 0; i < %ss->len; ++i) {\n" typ;
5949 pr " printf (\"[%%d] = {\\n\", i);\n";
5950 pr " print_%s_indent (&%ss->val[i], \" \");\n" typ typ;
5951 pr " printf (\"}\\n\");\n";
5957 (* run_<action> actions *)
5959 fun (name, style, _, flags, _, _, _) ->
5960 pr "static int run_%s (const char *cmd, int argc, char *argv[])\n" name;
5962 (match fst style with
5965 | RBool _ -> pr " int r;\n"
5966 | RInt64 _ -> pr " int64_t r;\n"
5967 | RConstString _ | RConstOptString _ -> pr " const char *r;\n"
5968 | RString _ -> pr " char *r;\n"
5969 | RStringList _ | RHashtable _ -> pr " char **r;\n"
5970 | RStruct (_, typ) -> pr " struct guestfs_%s *r;\n" typ
5971 | RStructList (_, typ) -> pr " struct guestfs_%s_list *r;\n" typ
5974 pr " size_t size;\n";
5983 | FileOut n -> pr " const char *%s;\n" n
5984 | StringList n -> pr " char **%s;\n" n
5985 | Bool n -> pr " int %s;\n" n
5986 | Int n -> pr " int %s;\n" n
5989 (* Check and convert parameters. *)
5990 let argc_expected = List.length (snd style) in
5991 pr " if (argc != %d) {\n" argc_expected;
5992 pr " fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
5994 pr " fprintf (stderr, _(\"type 'help %%s' for help on %%s\\n\"), cmd, cmd);\n";
6001 | Device name | String name -> pr " %s = argv[%d];\n" name i
6003 pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n"
6006 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdin\";\n"
6009 pr " %s = strcmp (argv[%d], \"-\") != 0 ? argv[%d] : \"/dev/stdout\";\n"
6011 | StringList name ->
6012 pr " %s = parse_string_list (argv[%d]);\n" name i
6014 pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i
6016 pr " %s = atoi (argv[%d]);\n" name i
6019 (* Call C API function. *)
6021 try find_map (function FishAction n -> Some n | _ -> None) flags
6022 with Not_found -> sprintf "guestfs_%s" name in
6024 generate_c_call_args ~handle:"g" style;
6027 (* Check return value for errors and display command results. *)
6028 (match fst style with
6029 | RErr -> pr " return r;\n"
6031 pr " if (r == -1) return -1;\n";
6032 pr " printf (\"%%d\\n\", r);\n";
6035 pr " if (r == -1) return -1;\n";
6036 pr " printf (\"%%\" PRIi64 \"\\n\", r);\n";
6039 pr " if (r == -1) return -1;\n";
6040 pr " if (r) printf (\"true\\n\"); else printf (\"false\\n\");\n";
6043 pr " if (r == NULL) return -1;\n";
6044 pr " printf (\"%%s\\n\", r);\n";
6046 | RConstOptString _ ->
6047 pr " printf (\"%%s\\n\", r ? : \"(null)\");\n";
6050 pr " if (r == NULL) return -1;\n";
6051 pr " printf (\"%%s\\n\", r);\n";
6055 pr " if (r == NULL) return -1;\n";
6056 pr " print_strings (r);\n";
6057 pr " free_strings (r);\n";
6059 | RStruct (_, typ) ->
6060 pr " if (r == NULL) return -1;\n";
6061 pr " print_%s (r);\n" typ;
6062 pr " guestfs_free_%s (r);\n" typ;
6064 | RStructList (_, typ) ->
6065 pr " if (r == NULL) return -1;\n";
6066 pr " print_%s_list (r);\n" typ;
6067 pr " guestfs_free_%s_list (r);\n" typ;
6070 pr " if (r == NULL) return -1;\n";
6071 pr " print_table (r);\n";
6072 pr " free_strings (r);\n";
6075 pr " if (r == NULL) return -1;\n";
6076 pr " fwrite (r, size, 1, stdout);\n";
6084 (* run_action function *)
6085 pr "int run_action (const char *cmd, int argc, char *argv[])\n";
6088 fun (name, _, _, flags, _, _, _) ->
6089 let name2 = replace_char name '_' '-' in
6091 try find_map (function FishAlias n -> Some n | _ -> None) flags
6092 with Not_found -> name in
6094 pr "strcasecmp (cmd, \"%s\") == 0" name;
6095 if name <> name2 then
6096 pr " || strcasecmp (cmd, \"%s\") == 0" name2;
6097 if name <> alias then
6098 pr " || strcasecmp (cmd, \"%s\") == 0" alias;
6100 pr " return run_%s (cmd, argc, argv);\n" name;
6104 pr " fprintf (stderr, _(\"%%s: unknown command\\n\"), cmd);\n";
6111 (* Readline completion for guestfish. *)
6112 and generate_fish_completion () =
6113 generate_header CStyle GPLv2;
6117 fun (_, _, _, flags, _, _, _) -> not (List.mem NotInFish flags)
6127 #ifdef HAVE_LIBREADLINE
6128 #include <readline/readline.h>
6133 #ifdef HAVE_LIBREADLINE
6135 static const char *const commands[] = {
6136 BUILTIN_COMMANDS_FOR_COMPLETION,
6139 (* Get the commands, including the aliases. They don't need to be
6140 * sorted - the generator() function just does a dumb linear search.
6144 fun (name, _, _, flags, _, _, _) ->
6145 let name2 = replace_char name '_' '-' in
6147 try find_map (function FishAlias n -> Some n | _ -> None) flags
6148 with Not_found -> name in
6150 if name <> alias then [name2; alias] else [name2]
6152 let commands = List.flatten commands in
6154 List.iter (pr " \"%s\",\n") commands;
6160 generator (const char *text, int state)
6162 static int index, len;
6167 len = strlen (text);
6170 rl_attempted_completion_over = 1;
6172 while ((name = commands[index]) != NULL) {
6174 if (strncasecmp (name, text, len) == 0)
6175 return strdup (name);
6181 #endif /* HAVE_LIBREADLINE */
6183 char **do_completion (const char *text, int start, int end)
6185 char **matches = NULL;
6187 #ifdef HAVE_LIBREADLINE
6188 rl_completion_append_character = ' ';
6191 matches = rl_completion_matches (text, generator);
6192 else if (complete_dest_paths)
6193 matches = rl_completion_matches (text, complete_dest_paths_generator);
6200 (* Generate the POD documentation for guestfish. *)
6201 and generate_fish_actions_pod () =
6202 let all_functions_sorted =
6204 fun (_, _, _, flags, _, _, _) ->
6205 not (List.mem NotInFish flags || List.mem NotInDocs flags)
6206 ) all_functions_sorted in
6208 let rex = Str.regexp "C<guestfs_\\([^>]+\\)>" in
6211 fun (name, style, _, flags, _, _, longdesc) ->
6213 Str.global_substitute rex (
6216 try Str.matched_group 1 s
6218 failwithf "error substituting C<guestfs_...> in longdesc of function %s" name in
6219 "C<" ^ replace_char sub '_' '-' ^ ">"
6221 let name = replace_char name '_' '-' in
6223 try find_map (function FishAlias n -> Some n | _ -> None) flags
6224 with Not_found -> name in
6226 pr "=head2 %s" name;
6227 if name <> alias then
6234 | Pathname n | Device n | String n -> pr " %s" n
6235 | OptString n -> pr " %s" n
6236 | StringList n -> pr " '%s ...'" n
6237 | Bool _ -> pr " true|false"
6238 | Int n -> pr " %s" n
6239 | FileIn n | FileOut n -> pr " (%s|-)" n
6243 pr "%s\n\n" longdesc;
6245 if List.exists (function FileIn _ | FileOut _ -> true
6246 | _ -> false) (snd style) then
6247 pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
6249 if List.mem ProtocolLimitWarning flags then
6250 pr "%s\n\n" protocol_limit_warning;
6252 if List.mem DangerWillRobinson flags then
6253 pr "%s\n\n" danger_will_robinson;
6255 match deprecation_notice flags with
6257 | Some txt -> pr "%s\n\n" txt
6258 ) all_functions_sorted
6260 (* Generate a C function prototype. *)
6261 and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true)
6262 ?(single_line = false) ?(newline = false) ?(in_daemon = false)
6264 ?handle name style =
6265 if extern then pr "extern ";
6266 if static then pr "static ";
6267 (match fst style with
6269 | RInt _ -> pr "int "
6270 | RInt64 _ -> pr "int64_t "
6271 | RBool _ -> pr "int "
6272 | RConstString _ | RConstOptString _ -> pr "const char *"
6273 | RString _ | RBufferOut _ -> pr "char *"
6274 | RStringList _ | RHashtable _ -> pr "char **"
6275 | RStruct (_, typ) ->
6276 if not in_daemon then pr "struct guestfs_%s *" typ
6277 else pr "guestfs_int_%s *" typ
6278 | RStructList (_, typ) ->
6279 if not in_daemon then pr "struct guestfs_%s_list *" typ
6280 else pr "guestfs_int_%s_list *" typ
6282 let is_RBufferOut = match fst style with RBufferOut _ -> true | _ -> false in
6283 pr "%s%s (" prefix name;
6284 if handle = None && List.length (snd style) = 0 && not is_RBufferOut then
6287 let comma = ref false in
6290 | Some handle -> pr "guestfs_h *%s" handle; comma := true
6294 if single_line then pr ", " else pr ",\n\t\t"
6305 pr "const char *%s" n
6308 if not in_daemon then pr "char * const* const %s" n
6309 else pr "char **%s" n
6310 | Bool n -> next (); pr "int %s" n
6311 | Int n -> next (); pr "int %s" n
6314 if not in_daemon then (next (); pr "const char *%s" n)
6316 if is_RBufferOut then (next (); pr "size_t *size_r");
6319 if semicolon then pr ";";
6320 if newline then pr "\n"
6322 (* Generate C call arguments, eg "(handle, foo, bar)" *)
6323 and generate_c_call_args ?handle ?(decl = false) style =
6325 let comma = ref false in
6327 if !comma then pr ", ";
6332 | Some handle -> pr "%s" handle; comma := true
6337 pr "%s" (name_of_argt arg)
6339 (* For RBufferOut calls, add implicit &size parameter. *)
6341 match fst style with
6349 (* Generate the OCaml bindings interface. *)
6350 and generate_ocaml_mli () =
6351 generate_header OCamlStyle LGPLv2;
6354 (** For API documentation you should refer to the C API
6355 in the guestfs(3) manual page. The OCaml API uses almost
6356 exactly the same calls. *)
6359 (** A [guestfs_h] handle. *)
6361 exception Error of string
6362 (** This exception is raised when there is an error. *)
6364 val create : unit -> t
6366 val close : t -> unit
6367 (** Handles are closed by the garbage collector when they become
6368 unreferenced, but callers can also call this in order to
6369 provide predictable cleanup. *)
6372 generate_ocaml_structure_decls ();
6376 fun (name, style, _, _, _, shortdesc, _) ->
6377 generate_ocaml_prototype name style;
6378 pr "(** %s *)\n" shortdesc;
6382 (* Generate the OCaml bindings implementation. *)
6383 and generate_ocaml_ml () =
6384 generate_header OCamlStyle LGPLv2;
6388 exception Error of string
6389 external create : unit -> t = \"ocaml_guestfs_create\"
6390 external close : t -> unit = \"ocaml_guestfs_close\"
6393 Callback.register_exception \"ocaml_guestfs_error\" (Error \"\")
6397 generate_ocaml_structure_decls ();
6401 fun (name, style, _, _, _, shortdesc, _) ->
6402 generate_ocaml_prototype ~is_external:true name style;
6405 (* Generate the OCaml bindings C implementation. *)
6406 and generate_ocaml_c () =
6407 generate_header CStyle LGPLv2;
6414 #include <caml/config.h>
6415 #include <caml/alloc.h>
6416 #include <caml/callback.h>
6417 #include <caml/fail.h>
6418 #include <caml/memory.h>
6419 #include <caml/mlvalues.h>
6420 #include <caml/signals.h>
6422 #include <guestfs.h>
6424 #include \"guestfs_c.h\"
6426 /* Copy a hashtable of string pairs into an assoc-list. We return
6427 * the list in reverse order, but hashtables aren't supposed to be
6430 static CAMLprim value
6431 copy_table (char * const * argv)
6434 CAMLlocal5 (rv, pairv, kv, vv, cons);
6438 for (i = 0; argv[i] != NULL; i += 2) {
6439 kv = caml_copy_string (argv[i]);
6440 vv = caml_copy_string (argv[i+1]);
6441 pairv = caml_alloc (2, 0);
6442 Store_field (pairv, 0, kv);
6443 Store_field (pairv, 1, vv);
6444 cons = caml_alloc (2, 0);
6445 Store_field (cons, 1, rv);
6447 Store_field (cons, 0, pairv);
6455 (* Struct copy functions. *)
6458 let has_optpercent_col =
6459 List.exists (function (_, FOptPercent) -> true | _ -> false) cols in
6461 pr "static CAMLprim value\n";
6462 pr "copy_%s (const struct guestfs_%s *%s)\n" typ typ typ;
6464 pr " CAMLparam0 ();\n";
6465 if has_optpercent_col then
6466 pr " CAMLlocal3 (rv, v, v2);\n"
6468 pr " CAMLlocal2 (rv, v);\n";
6470 pr " rv = caml_alloc (%d, 0);\n" (List.length cols);
6475 pr " v = caml_copy_string (%s->%s);\n" typ name
6477 pr " v = caml_alloc_string (%s->%s_len);\n" typ name;
6478 pr " memcpy (String_val (v), %s->%s, %s->%s_len);\n"
6481 pr " v = caml_alloc_string (32);\n";
6482 pr " memcpy (String_val (v), %s->%s, 32);\n" typ name
6483 | name, (FBytes|FInt64|FUInt64) ->
6484 pr " v = caml_copy_int64 (%s->%s);\n" typ name
6485 | name, (FInt32|FUInt32) ->
6486 pr " v = caml_copy_int32 (%s->%s);\n" typ name
6487 | name, FOptPercent ->
6488 pr " if (%s->%s >= 0) { /* Some %s */\n" typ name name;
6489 pr " v2 = caml_copy_double (%s->%s);\n" typ name;
6490 pr " v = caml_alloc (1, 0);\n";
6491 pr " Store_field (v, 0, v2);\n";
6492 pr " } else /* None */\n";
6493 pr " v = Val_int (0);\n";
6495 pr " v = Val_int (%s->%s);\n" typ name
6497 pr " Store_field (rv, %d, v);\n" i
6499 pr " CAMLreturn (rv);\n";
6503 pr "static CAMLprim value\n";
6504 pr "copy_%s_list (const struct guestfs_%s_list *%ss)\n"
6507 pr " CAMLparam0 ();\n";
6508 pr " CAMLlocal2 (rv, v);\n";
6511 pr " if (%ss->len == 0)\n" typ;
6512 pr " CAMLreturn (Atom (0));\n";
6514 pr " rv = caml_alloc (%ss->len, 0);\n" typ;
6515 pr " for (i = 0; i < %ss->len; ++i) {\n" typ;
6516 pr " v = copy_%s (&%ss->val[i]);\n" typ typ;
6517 pr " caml_modify (&Field (rv, i), v);\n";
6519 pr " CAMLreturn (rv);\n";
6527 fun (name, style, _, _, _, _, _) ->
6529 "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in
6531 let needs_extra_vs =
6532 match fst style with RConstOptString _ -> true | _ -> false in
6534 pr "CAMLprim value\n";
6535 pr "ocaml_guestfs_%s (value %s" name (List.hd params);
6536 List.iter (pr ", value %s") (List.tl params);
6541 | [p1; p2; p3; p4; p5] ->
6542 pr " CAMLparam5 (%s);\n" (String.concat ", " params)
6543 | p1 :: p2 :: p3 :: p4 :: p5 :: rest ->
6544 pr " CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]);
6545 pr " CAMLxparam%d (%s);\n"
6546 (List.length rest) (String.concat ", " rest)
6548 pr " CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps)
6550 if not needs_extra_vs then
6551 pr " CAMLlocal1 (rv);\n"
6553 pr " CAMLlocal3 (rv, v, v2);\n";
6556 pr " guestfs_h *g = Guestfs_val (gv);\n";
6557 pr " if (g == NULL)\n";
6558 pr " caml_failwith (\"%s: used handle after closing it\");\n" name;
6568 pr " const char *%s = String_val (%sv);\n" n n
6570 pr " const char *%s =\n" n;
6571 pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n"
6574 pr " char **%s = ocaml_guestfs_strings_val (g, %sv);\n" n n
6576 pr " int %s = Bool_val (%sv);\n" n n
6578 pr " int %s = Int_val (%sv);\n" n n
6581 match fst style with
6582 | RErr -> pr " int r;\n"; "-1"
6583 | RInt _ -> pr " int r;\n"; "-1"
6584 | RInt64 _ -> pr " int64_t r;\n"; "-1"
6585 | RBool _ -> pr " int r;\n"; "-1"
6586 | RConstString _ | RConstOptString _ ->
6587 pr " const char *r;\n"; "NULL"
6588 | RString _ -> pr " char *r;\n"; "NULL"
6593 | RStruct (_, typ) ->
6594 pr " struct guestfs_%s *r;\n" typ; "NULL"
6595 | RStructList (_, typ) ->
6596 pr " struct guestfs_%s_list *r;\n" typ; "NULL"
6603 pr " size_t size;\n";
6607 pr " caml_enter_blocking_section ();\n";
6608 pr " r = guestfs_%s " name;
6609 generate_c_call_args ~handle:"g" style;
6611 pr " caml_leave_blocking_section ();\n";
6616 pr " ocaml_guestfs_free_strings (%s);\n" n;
6617 | Pathname _ | Device _ | String _ | OptString _ | Bool _ | Int _
6618 | FileIn _ | FileOut _ -> ()
6621 pr " if (r == %s)\n" error_code;
6622 pr " ocaml_guestfs_raise_error (g, \"%s\");\n" name;
6625 (match fst style with
6626 | RErr -> pr " rv = Val_unit;\n"
6627 | RInt _ -> pr " rv = Val_int (r);\n"
6629 pr " rv = caml_copy_int64 (r);\n"
6630 | RBool _ -> pr " rv = Val_bool (r);\n"
6632 pr " rv = caml_copy_string (r);\n"
6633 | RConstOptString _ ->
6634 pr " if (r) { /* Some string */\n";
6635 pr " v = caml_alloc (1, 0);\n";
6636 pr " v2 = caml_copy_string (r);\n";
6637 pr " Store_field (v, 0, v2);\n";
6638 pr " } else /* None */\n";
6639 pr " v = Val_int (0);\n";
6641 pr " rv = caml_copy_string (r);\n";
6644 pr " rv = caml_copy_string_array ((const char **) r);\n";
6645 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
6647 | RStruct (_, typ) ->
6648 pr " rv = copy_%s (r);\n" typ;
6649 pr " guestfs_free_%s (r);\n" typ;
6650 | RStructList (_, typ) ->
6651 pr " rv = copy_%s_list (r);\n" typ;
6652 pr " guestfs_free_%s_list (r);\n" typ;
6654 pr " rv = copy_table (r);\n";
6655 pr " for (i = 0; r[i] != NULL; ++i) free (r[i]);\n";
6658 pr " rv = caml_alloc_string (size);\n";
6659 pr " memcpy (String_val (rv), r, size);\n";
6662 pr " CAMLreturn (rv);\n";
6666 if List.length params > 5 then (
6667 pr "CAMLprim value\n";
6668 pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name;
6670 pr " return ocaml_guestfs_%s (argv[0]" name;
6671 iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params);
6678 and generate_ocaml_structure_decls () =
6681 pr "type %s = {\n" typ;
6684 | name, FString -> pr " %s : string;\n" name
6685 | name, FBuffer -> pr " %s : string;\n" name
6686 | name, FUUID -> pr " %s : string;\n" name
6687 | name, (FBytes|FInt64|FUInt64) -> pr " %s : int64;\n" name
6688 | name, (FInt32|FUInt32) -> pr " %s : int32;\n" name
6689 | name, FChar -> pr " %s : char;\n" name
6690 | name, FOptPercent -> pr " %s : float option;\n" name
6696 and generate_ocaml_prototype ?(is_external = false) name style =
6697 if is_external then pr "external " else pr "val ";
6698 pr "%s : t -> " name;
6701 | Pathname _ | Device _ | String _ | FileIn _ | FileOut _ -> pr "string -> "
6702 | OptString _ -> pr "string option -> "
6703 | StringList _ -> pr "string array -> "
6704 | Bool _ -> pr "bool -> "
6705 | Int _ -> pr "int -> "
6707 (match fst style with
6708 | RErr -> pr "unit" (* all errors are turned into exceptions *)
6709 | RInt _ -> pr "int"
6710 | RInt64 _ -> pr "int64"
6711 | RBool _ -> pr "bool"
6712 | RConstString _ -> pr "string"
6713 | RConstOptString _ -> pr "string option"
6714 | RString _ | RBufferOut _ -> pr "string"
6715 | RStringList _ -> pr "string array"
6716 | RStruct (_, typ) -> pr "%s" typ
6717 | RStructList (_, typ) -> pr "%s array" typ
6718 | RHashtable _ -> pr "(string * string) list"
6720 if is_external then (
6722 if List.length (snd style) + 1 > 5 then
6723 pr "\"ocaml_guestfs_%s_byte\" " name;
6724 pr "\"ocaml_guestfs_%s\"" name
6728 (* Generate Perl xs code, a sort of crazy variation of C with macros. *)
6729 and generate_perl_xs () =
6730 generate_header CStyle LGPLv2;
6733 #include \"EXTERN.h\"
6737 #include <guestfs.h>
6740 #define PRId64 \"lld\"
6744 my_newSVll(long long val) {
6745 #ifdef USE_64_BIT_ALL
6746 return newSViv(val);
6750 len = snprintf(buf, 100, \"%%\" PRId64, val);
6751 return newSVpv(buf, len);
6756 #define PRIu64 \"llu\"
6760 my_newSVull(unsigned long long val) {
6761 #ifdef USE_64_BIT_ALL
6762 return newSVuv(val);
6766 len = snprintf(buf, 100, \"%%\" PRIu64, val);
6767 return newSVpv(buf, len);
6771 /* http://www.perlmonks.org/?node_id=680842 */
6773 XS_unpack_charPtrPtr (SV *arg) {
6778 if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV)
6779 croak (\"array reference expected\");
6781 av = (AV *)SvRV (arg);
6782 ret = malloc ((av_len (av) + 1 + 1) * sizeof (char *));
6784 croak (\"malloc failed\");
6786 for (i = 0; i <= av_len (av); i++) {
6787 SV **elem = av_fetch (av, i, 0);
6789 if (!elem || !*elem)
6790 croak (\"missing element in list\");
6792 ret[i] = SvPV_nolen (*elem);
6800 MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
6807 RETVAL = guestfs_create ();
6809 croak (\"could not create guestfs handle\");
6810 guestfs_set_error_handler (RETVAL, NULL, NULL);
6823 fun (name, style, _, _, _, _, _) ->
6824 (match fst style with
6825 | RErr -> pr "void\n"
6826 | RInt _ -> pr "SV *\n"
6827 | RInt64 _ -> pr "SV *\n"
6828 | RBool _ -> pr "SV *\n"
6829 | RConstString _ -> pr "SV *\n"
6830 | RConstOptString _ -> pr "SV *\n"
6831 | RString _ -> pr "SV *\n"
6832 | RBufferOut _ -> pr "SV *\n"
6834 | RStruct _ | RStructList _
6836 pr "void\n" (* all lists returned implictly on the stack *)
6838 (* Call and arguments. *)
6840 generate_c_call_args ~handle:"g" ~decl:true style;
6842 pr " guestfs_h *g;\n";
6847 | Pathname n | Device n | String n | FileIn n | FileOut n ->
6850 (* http://www.perlmonks.org/?node_id=554277
6851 * Note that the implicit handle argument means we have
6852 * to add 1 to the ST(x) operator.
6854 pr " char *%s = SvOK(ST(%d)) ? SvPV_nolen(ST(%d)) : NULL;\n" n (i+1) (i+1)
6855 | StringList n -> pr " char **%s;\n" n
6856 | Bool n -> pr " int %s;\n" n
6857 | Int n -> pr " int %s;\n" n
6860 let do_cleanups () =
6863 | Pathname _ | Device _ | String _ | OptString _ | Bool _ | Int _
6864 | FileIn _ | FileOut _ -> ()
6865 | StringList n -> pr " free (%s);\n" n
6870 (match fst style with
6875 pr " r = guestfs_%s " name;
6876 generate_c_call_args ~handle:"g" style;
6879 pr " if (r == -1)\n";
6880 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6886 pr " %s = guestfs_%s " n name;
6887 generate_c_call_args ~handle:"g" style;
6890 pr " if (%s == -1)\n" n;
6891 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6892 pr " RETVAL = newSViv (%s);\n" n;
6897 pr " int64_t %s;\n" n;
6899 pr " %s = guestfs_%s " n name;
6900 generate_c_call_args ~handle:"g" style;
6903 pr " if (%s == -1)\n" n;
6904 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6905 pr " RETVAL = my_newSVll (%s);\n" n;
6910 pr " const char *%s;\n" n;
6912 pr " %s = guestfs_%s " n name;
6913 generate_c_call_args ~handle:"g" style;
6916 pr " if (%s == NULL)\n" n;
6917 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6918 pr " RETVAL = newSVpv (%s, 0);\n" n;
6921 | RConstOptString n ->
6923 pr " const char *%s;\n" n;
6925 pr " %s = guestfs_%s " n name;
6926 generate_c_call_args ~handle:"g" style;
6929 pr " if (%s == NULL)\n" n;
6930 pr " RETVAL = &PL_sv_undef;\n";
6932 pr " RETVAL = newSVpv (%s, 0);\n" n;
6937 pr " char *%s;\n" n;
6939 pr " %s = guestfs_%s " n name;
6940 generate_c_call_args ~handle:"g" style;
6943 pr " if (%s == NULL)\n" n;
6944 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6945 pr " RETVAL = newSVpv (%s, 0);\n" n;
6946 pr " free (%s);\n" n;
6949 | RStringList n | RHashtable n ->
6951 pr " char **%s;\n" n;
6954 pr " %s = guestfs_%s " n name;
6955 generate_c_call_args ~handle:"g" style;
6958 pr " if (%s == NULL)\n" n;
6959 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6960 pr " for (n = 0; %s[n] != NULL; ++n) /**/;\n" n;
6961 pr " EXTEND (SP, n);\n";
6962 pr " for (i = 0; i < n; ++i) {\n";
6963 pr " PUSHs (sv_2mortal (newSVpv (%s[i], 0)));\n" n;
6964 pr " free (%s[i]);\n" n;
6966 pr " free (%s);\n" n;
6967 | RStruct (n, typ) ->
6968 let cols = cols_of_struct typ in
6969 generate_perl_struct_code typ cols name style n do_cleanups
6970 | RStructList (n, typ) ->
6971 let cols = cols_of_struct typ in
6972 generate_perl_struct_list_code typ cols name style n do_cleanups
6975 pr " char *%s;\n" n;
6976 pr " size_t size;\n";
6978 pr " %s = guestfs_%s " n name;
6979 generate_c_call_args ~handle:"g" style;
6982 pr " if (%s == NULL)\n" n;
6983 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
6984 pr " RETVAL = newSVpv (%s, size);\n" n;
6985 pr " free (%s);\n" n;
6993 and generate_perl_struct_list_code typ cols name style n do_cleanups =
6995 pr " struct guestfs_%s_list *%s;\n" typ n;
6999 pr " %s = guestfs_%s " n name;
7000 generate_c_call_args ~handle:"g" style;
7003 pr " if (%s == NULL)\n" n;
7004 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
7005 pr " EXTEND (SP, %s->len);\n" n;
7006 pr " for (i = 0; i < %s->len; ++i) {\n" n;
7007 pr " hv = newHV ();\n";
7011 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 0), 0);\n"
7012 name (String.length name) n name
7014 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, 32), 0);\n"
7015 name (String.length name) n name
7017 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (%s->val[i].%s, %s->val[i].%s_len), 0);\n"
7018 name (String.length name) n name n name
7019 | name, (FBytes|FUInt64) ->
7020 pr " (void) hv_store (hv, \"%s\", %d, my_newSVull (%s->val[i].%s), 0);\n"
7021 name (String.length name) n name
7023 pr " (void) hv_store (hv, \"%s\", %d, my_newSVll (%s->val[i].%s), 0);\n"
7024 name (String.length name) n name
7025 | name, (FInt32|FUInt32) ->
7026 pr " (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
7027 name (String.length name) n name
7029 pr " (void) hv_store (hv, \"%s\", %d, newSVpv (&%s->val[i].%s, 1), 0);\n"
7030 name (String.length name) n name
7031 | name, FOptPercent ->
7032 pr " (void) hv_store (hv, \"%s\", %d, newSVnv (%s->val[i].%s), 0);\n"
7033 name (String.length name) n name
7035 pr " PUSHs (sv_2mortal (newRV ((SV *) hv)));\n";
7037 pr " guestfs_free_%s_list (%s);\n" typ n
7039 and generate_perl_struct_code typ cols name style n do_cleanups =
7041 pr " struct guestfs_%s *%s;\n" typ n;
7043 pr " %s = guestfs_%s " n name;
7044 generate_c_call_args ~handle:"g" style;
7047 pr " if (%s == NULL)\n" n;
7048 pr " croak (\"%s: %%s\", guestfs_last_error (g));\n" name;
7049 pr " EXTEND (SP, 2 * %d);\n" (List.length cols);
7051 fun ((name, _) as col) ->
7052 pr " PUSHs (sv_2mortal (newSVpv (\"%s\", 0)));\n" name;
7056 pr " PUSHs (sv_2mortal (newSVpv (%s->%s, 0)));\n"
7059 pr " PUSHs (sv_2mortal (newSVpv (%s->%s, %s->%s_len)));\n"
7062 pr " PUSHs (sv_2mortal (newSVpv (%s->%s, 32)));\n"
7064 | name, (FBytes|FUInt64) ->
7065 pr " PUSHs (sv_2mortal (my_newSVull (%s->%s)));\n"
7068 pr " PUSHs (sv_2mortal (my_newSVll (%s->%s)));\n"
7070 | name, (FInt32|FUInt32) ->
7071 pr " PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
7074 pr " PUSHs (sv_2mortal (newSVpv (&%s->%s, 1)));\n"
7076 | name, FOptPercent ->
7077 pr " PUSHs (sv_2mortal (newSVnv (%s->%s)));\n"
7080 pr " free (%s);\n" n
7082 (* Generate Sys/Guestfs.pm. *)
7083 and generate_perl_pm () =
7084 generate_header HashStyle LGPLv2;
7091 Sys::Guestfs - Perl bindings for libguestfs
7097 my $h = Sys::Guestfs->new ();
7098 $h->add_drive ('guest.img');
7101 $h->mount ('/dev/sda1', '/');
7102 $h->touch ('/hello');
7107 The C<Sys::Guestfs> module provides a Perl XS binding to the
7108 libguestfs API for examining and modifying virtual machine
7111 Amongst the things this is good for: making batch configuration
7112 changes to guests, getting disk used/free statistics (see also:
7113 virt-df), migrating between virtualization systems (see also:
7114 virt-p2v), performing partial backups, performing partial guest
7115 clones, cloning guests and changing registry/UUID/hostname info, and
7118 Libguestfs uses Linux kernel and qemu code, and can access any type of
7119 guest filesystem that Linux and qemu can, including but not limited
7120 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
7121 schemes, qcow, qcow2, vmdk.
7123 Libguestfs provides ways to enumerate guest storage (eg. partitions,
7124 LVs, what filesystem is in each LV, etc.). It can also run commands
7125 in the context of the guest. Also you can access filesystems over FTP.
7127 See also L<Sys::Guestfs::Lib(3)> for a set of useful library
7128 functions for using libguestfs from Perl, including integration
7133 All errors turn into calls to C<croak> (see L<Carp(3)>).
7141 package Sys::Guestfs;
7147 XSLoader::load ('Sys::Guestfs');
7149 =item $h = Sys::Guestfs->new ();
7151 Create a new guestfs handle.
7157 my $class = ref ($proto) || $proto;
7159 my $self = Sys::Guestfs::_create ();
7160 bless $self, $class;
7166 (* Actions. We only need to print documentation for these as
7167 * they are pulled in from the XS code automatically.
7170 fun (name, style, _, flags, _, _, longdesc) ->
7171 if not (List.mem NotInDocs flags) then (
7172 let longdesc = replace_str longdesc "C<guestfs_" "C<$h-E<gt>" in
7174 generate_perl_prototype name style;
7176 pr "%s\n\n" longdesc;
7177 if List.mem ProtocolLimitWarning flags then
7178 pr "%s\n\n" protocol_limit_warning;
7179 if List.mem DangerWillRobinson flags then
7180 pr "%s\n\n" danger_will_robinson;
7181 match deprecation_notice flags with
7183 | Some txt -> pr "%s\n\n" txt
7185 ) all_functions_sorted;
7197 Copyright (C) 2009 Red Hat Inc.
7201 Please see the file COPYING.LIB for the full license.
7207 L<http://libguestfs.org>,
7208 L<Sys::Guestfs::Lib(3)>.
7213 and generate_perl_prototype name style =
7214 (match fst style with
7222 | RBufferOut n -> pr "$%s = " n
7224 | RHashtable n -> pr "%%%s = " n
7226 | RStructList (n,_) -> pr "@%s = " n
7229 let comma = ref false in
7232 if !comma then pr ", ";
7235 | Pathname n | Device n | String n
7236 | OptString n | Bool n | Int n | FileIn n | FileOut n ->
7243 (* Generate Python C module. *)
7244 and generate_python_c () =
7245 generate_header CStyle LGPLv2;
7254 #include \"guestfs.h\"
7262 get_handle (PyObject *obj)
7265 assert (obj != Py_None);
7266 return ((Pyguestfs_Object *) obj)->g;
7270 put_handle (guestfs_h *g)
7274 PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
7277 /* This list should be freed (but not the strings) after use. */
7278 static const char **
7279 get_string_list (PyObject *obj)
7286 if (!PyList_Check (obj)) {
7287 PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
7291 len = PyList_Size (obj);
7292 r = malloc (sizeof (char *) * (len+1));
7294 PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
7298 for (i = 0; i < len; ++i)
7299 r[i] = PyString_AsString (PyList_GetItem (obj, i));
7306 put_string_list (char * const * const argv)
7311 for (argc = 0; argv[argc] != NULL; ++argc)
7314 list = PyList_New (argc);
7315 for (i = 0; i < argc; ++i)
7316 PyList_SetItem (list, i, PyString_FromString (argv[i]));
7322 put_table (char * const * const argv)
7324 PyObject *list, *item;
7327 for (argc = 0; argv[argc] != NULL; ++argc)
7330 list = PyList_New (argc >> 1);
7331 for (i = 0; i < argc; i += 2) {
7332 item = PyTuple_New (2);
7333 PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
7334 PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
7335 PyList_SetItem (list, i >> 1, item);
7342 free_strings (char **argv)
7346 for (argc = 0; argv[argc] != NULL; ++argc)
7352 py_guestfs_create (PyObject *self, PyObject *args)
7356 g = guestfs_create ();
7358 PyErr_SetString (PyExc_RuntimeError,
7359 \"guestfs.create: failed to allocate handle\");
7362 guestfs_set_error_handler (g, NULL, NULL);
7363 return put_handle (g);
7367 py_guestfs_close (PyObject *self, PyObject *args)
7372 if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
7374 g = get_handle (py_g);
7378 Py_INCREF (Py_None);
7384 (* Structures, turned into Python dictionaries. *)
7387 pr "static PyObject *\n";
7388 pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
7390 pr " PyObject *dict;\n";
7392 pr " dict = PyDict_New ();\n";
7396 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
7397 pr " PyString_FromString (%s->%s));\n"
7400 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
7401 pr " PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
7404 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
7405 pr " PyString_FromStringAndSize (%s->%s, 32));\n"
7407 | name, (FBytes|FUInt64) ->
7408 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
7409 pr " PyLong_FromUnsignedLongLong (%s->%s));\n"
7412 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
7413 pr " PyLong_FromLongLong (%s->%s));\n"
7416 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
7417 pr " PyLong_FromUnsignedLong (%s->%s));\n"
7420 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
7421 pr " PyLong_FromLong (%s->%s));\n"
7423 | name, FOptPercent ->
7424 pr " if (%s->%s >= 0)\n" typ name;
7425 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
7426 pr " PyFloat_FromDouble ((double) %s->%s));\n"
7429 pr " Py_INCREF (Py_None);\n";
7430 pr " PyDict_SetItemString (dict, \"%s\", Py_None);" name;
7433 pr " PyDict_SetItemString (dict, \"%s\",\n" name;
7434 pr " PyString_FromStringAndSize (&dirent->%s, 1));\n" name
7436 pr " return dict;\n";
7440 pr "static PyObject *\n";
7441 pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
7443 pr " PyObject *list;\n";
7446 pr " list = PyList_New (%ss->len);\n" typ;
7447 pr " for (i = 0; i < %ss->len; ++i)\n" typ;
7448 pr " PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
7449 pr " return list;\n";
7454 (* Python wrapper functions. *)
7456 fun (name, style, _, _, _, _, _) ->
7457 pr "static PyObject *\n";
7458 pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
7461 pr " PyObject *py_g;\n";
7462 pr " guestfs_h *g;\n";
7463 pr " PyObject *py_r;\n";
7466 match fst style with
7467 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
7468 | RInt64 _ -> pr " int64_t r;\n"; "-1"
7469 | RConstString _ | RConstOptString _ ->
7470 pr " const char *r;\n"; "NULL"
7471 | RString _ -> pr " char *r;\n"; "NULL"
7472 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
7473 | RStruct (_, typ) -> pr " struct guestfs_%s *r;\n" typ; "NULL"
7474 | RStructList (_, typ) ->
7475 pr " struct guestfs_%s_list *r;\n" typ; "NULL"
7478 pr " size_t size;\n";
7483 | Pathname n | Device n | String n | FileIn n | FileOut n ->
7484 pr " const char *%s;\n" n
7485 | OptString n -> pr " const char *%s;\n" n
7487 pr " PyObject *py_%s;\n" n;
7488 pr " const char **%s;\n" n
7489 | Bool n -> pr " int %s;\n" n
7490 | Int n -> pr " int %s;\n" n
7495 (* Convert the parameters. *)
7496 pr " if (!PyArg_ParseTuple (args, (char *) \"O";
7499 | Pathname _ | Device _ | String _ | FileIn _ | FileOut _ -> pr "s"
7500 | OptString _ -> pr "z"
7501 | StringList _ -> pr "O"
7502 | Bool _ -> pr "i" (* XXX Python has booleans? *)
7505 pr ":guestfs_%s\",\n" name;
7509 | Pathname n | Device n | String n | FileIn n | FileOut n -> pr ", &%s" n
7510 | OptString n -> pr ", &%s" n
7511 | StringList n -> pr ", &py_%s" n
7512 | Bool n -> pr ", &%s" n
7513 | Int n -> pr ", &%s" n
7517 pr " return NULL;\n";
7519 pr " g = get_handle (py_g);\n";
7522 | Pathname _ | Device _ | String _
7523 | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
7525 pr " %s = get_string_list (py_%s);\n" n n;
7526 pr " if (!%s) return NULL;\n" n
7531 pr " r = guestfs_%s " name;
7532 generate_c_call_args ~handle:"g" style;
7537 | Pathname _ | Device _ | String _
7538 | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
7540 pr " free (%s);\n" n
7543 pr " if (r == %s) {\n" error_code;
7544 pr " PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
7545 pr " return NULL;\n";
7549 (match fst style with
7551 pr " Py_INCREF (Py_None);\n";
7552 pr " py_r = Py_None;\n"
7554 | RBool _ -> pr " py_r = PyInt_FromLong ((long) r);\n"
7555 | RInt64 _ -> pr " py_r = PyLong_FromLongLong (r);\n"
7556 | RConstString _ -> pr " py_r = PyString_FromString (r);\n"
7557 | RConstOptString _ ->
7559 pr " py_r = PyString_FromString (r);\n";
7561 pr " Py_INCREF (Py_None);\n";
7562 pr " py_r = Py_None;\n";
7565 pr " py_r = PyString_FromString (r);\n";
7568 pr " py_r = put_string_list (r);\n";
7569 pr " free_strings (r);\n"
7570 | RStruct (_, typ) ->
7571 pr " py_r = put_%s (r);\n" typ;
7572 pr " guestfs_free_%s (r);\n" typ
7573 | RStructList (_, typ) ->
7574 pr " py_r = put_%s_list (r);\n" typ;
7575 pr " guestfs_free_%s_list (r);\n" typ
7577 pr " py_r = put_table (r);\n";
7578 pr " free_strings (r);\n"
7580 pr " py_r = PyString_FromStringAndSize (r, size);\n";
7584 pr " return py_r;\n";
7589 (* Table of functions. *)
7590 pr "static PyMethodDef methods[] = {\n";
7591 pr " { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
7592 pr " { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
7594 fun (name, _, _, _, _, _, _) ->
7595 pr " { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
7598 pr " { NULL, NULL, 0, NULL }\n";
7602 (* Init function. *)
7605 initlibguestfsmod (void)
7607 static int initialized = 0;
7609 if (initialized) return;
7610 Py_InitModule ((char *) \"libguestfsmod\", methods);
7615 (* Generate Python module. *)
7616 and generate_python_py () =
7617 generate_header HashStyle LGPLv2;
7620 u\"\"\"Python bindings for libguestfs
7623 g = guestfs.GuestFS ()
7624 g.add_drive (\"guest.img\")
7627 parts = g.list_partitions ()
7629 The guestfs module provides a Python binding to the libguestfs API
7630 for examining and modifying virtual machine disk images.
7632 Amongst the things this is good for: making batch configuration
7633 changes to guests, getting disk used/free statistics (see also:
7634 virt-df), migrating between virtualization systems (see also:
7635 virt-p2v), performing partial backups, performing partial guest
7636 clones, cloning guests and changing registry/UUID/hostname info, and
7639 Libguestfs uses Linux kernel and qemu code, and can access any type of
7640 guest filesystem that Linux and qemu can, including but not limited
7641 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
7642 schemes, qcow, qcow2, vmdk.
7644 Libguestfs provides ways to enumerate guest storage (eg. partitions,
7645 LVs, what filesystem is in each LV, etc.). It can also run commands
7646 in the context of the guest. Also you can access filesystems over FTP.
7648 Errors which happen while using the API are turned into Python
7649 RuntimeError exceptions.
7651 To create a guestfs handle you usually have to perform the following
7654 # Create the handle, call add_drive at least once, and possibly
7655 # several times if the guest has multiple block devices:
7656 g = guestfs.GuestFS ()
7657 g.add_drive (\"guest.img\")
7659 # Launch the qemu subprocess and wait for it to become ready:
7663 # Now you can issue commands, for example:
7668 import libguestfsmod
7671 \"\"\"Instances of this class are libguestfs API handles.\"\"\"
7673 def __init__ (self):
7674 \"\"\"Create a new libguestfs handle.\"\"\"
7675 self._o = libguestfsmod.create ()
7678 libguestfsmod.close (self._o)
7683 fun (name, style, _, flags, _, _, longdesc) ->
7685 generate_py_call_args ~handle:"self" (snd style);
7688 if not (List.mem NotInDocs flags) then (
7689 let doc = replace_str longdesc "C<guestfs_" "C<g." in
7691 match fst style with
7692 | RErr | RInt _ | RInt64 _ | RBool _
7693 | RConstOptString _ | RConstString _
7694 | RString _ | RBufferOut _ -> doc
7696 doc ^ "\n\nThis function returns a list of strings."
7697 | RStruct (_, typ) ->
7698 doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
7699 | RStructList (_, typ) ->
7700 doc ^ sprintf "\n\nThis function returns a list of %ss. Each %s is represented as a dictionary." typ typ
7702 doc ^ "\n\nThis function returns a dictionary." in
7704 if List.mem ProtocolLimitWarning flags then
7705 doc ^ "\n\n" ^ protocol_limit_warning
7708 if List.mem DangerWillRobinson flags then
7709 doc ^ "\n\n" ^ danger_will_robinson
7712 match deprecation_notice flags with
7714 | Some txt -> doc ^ "\n\n" ^ txt in
7715 let doc = pod2text ~width:60 name doc in
7716 let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
7717 let doc = String.concat "\n " doc in
7718 pr " u\"\"\"%s\"\"\"\n" doc;
7720 pr " return libguestfsmod.%s " name;
7721 generate_py_call_args ~handle:"self._o" (snd style);
7726 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
7727 and generate_py_call_args ~handle args =
7729 List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
7732 (* Useful if you need the longdesc POD text as plain text. Returns a
7735 * Because this is very slow (the slowest part of autogeneration),
7736 * we memoize the results.
7738 and pod2text ~width name longdesc =
7739 let key = width, name, longdesc in
7740 try Hashtbl.find pod2text_memo key
7742 let filename, chan = Filename.open_temp_file "gen" ".tmp" in
7743 fprintf chan "=head1 %s\n\n%s\n" name longdesc;
7745 let cmd = sprintf "pod2text -w %d %s" width (Filename.quote filename) in
7746 let chan = Unix.open_process_in cmd in
7747 let lines = ref [] in
7749 let line = input_line chan in
7750 if i = 1 then (* discard the first line of output *)
7753 let line = triml line in
7754 lines := line :: !lines;
7757 let lines = try loop 1 with End_of_file -> List.rev !lines in
7758 Unix.unlink filename;
7759 (match Unix.close_process_in chan with
7760 | Unix.WEXITED 0 -> ()
7762 failwithf "pod2text: process exited with non-zero status (%d)" i
7763 | Unix.WSIGNALED i | Unix.WSTOPPED i ->
7764 failwithf "pod2text: process signalled or stopped by signal %d" i
7766 Hashtbl.add pod2text_memo key lines;
7767 let chan = open_out pod2text_memo_filename in
7768 output_value chan pod2text_memo;
7772 (* Generate ruby bindings. *)
7773 and generate_ruby_c () =
7774 generate_header CStyle LGPLv2;
7782 #include \"guestfs.h\"
7784 #include \"extconf.h\"
7786 /* For Ruby < 1.9 */
7788 #define RARRAY_LEN(r) (RARRAY((r))->len)
7791 static VALUE m_guestfs; /* guestfs module */
7792 static VALUE c_guestfs; /* guestfs_h handle */
7793 static VALUE e_Error; /* used for all errors */
7795 static void ruby_guestfs_free (void *p)
7798 guestfs_close ((guestfs_h *) p);
7801 static VALUE ruby_guestfs_create (VALUE m)
7805 g = guestfs_create ();
7807 rb_raise (e_Error, \"failed to create guestfs handle\");
7809 /* Don't print error messages to stderr by default. */
7810 guestfs_set_error_handler (g, NULL, NULL);
7812 /* Wrap it, and make sure the close function is called when the
7815 return Data_Wrap_Struct (c_guestfs, NULL, ruby_guestfs_free, g);
7818 static VALUE ruby_guestfs_close (VALUE gv)
7821 Data_Get_Struct (gv, guestfs_h, g);
7823 ruby_guestfs_free (g);
7824 DATA_PTR (gv) = NULL;
7832 fun (name, style, _, _, _, _, _) ->
7833 pr "static VALUE ruby_guestfs_%s (VALUE gv" name;
7834 List.iter (fun arg -> pr ", VALUE %sv" (name_of_argt arg)) (snd style);
7837 pr " guestfs_h *g;\n";
7838 pr " Data_Get_Struct (gv, guestfs_h, g);\n";
7840 pr " rb_raise (rb_eArgError, \"%%s: used handle after closing it\", \"%s\");\n"
7846 | Pathname n | Device n | String n | FileIn n | FileOut n ->
7847 pr " Check_Type (%sv, T_STRING);\n" n;
7848 pr " const char *%s = StringValueCStr (%sv);\n" n n;
7850 pr " rb_raise (rb_eTypeError, \"expected string for parameter %%s of %%s\",\n";
7851 pr " \"%s\", \"%s\");\n" n name
7853 pr " const char *%s = !NIL_P (%sv) ? StringValueCStr (%sv) : NULL;\n" n n n
7855 pr " char **%s;\n" n;
7856 pr " Check_Type (%sv, T_ARRAY);\n" n;
7858 pr " int i, len;\n";
7859 pr " len = RARRAY_LEN (%sv);\n" n;
7860 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (len+1));\n"
7862 pr " for (i = 0; i < len; ++i) {\n";
7863 pr " VALUE v = rb_ary_entry (%sv, i);\n" n;
7864 pr " %s[i] = StringValueCStr (v);\n" n;
7866 pr " %s[len] = NULL;\n" n;
7869 pr " int %s = RTEST (%sv);\n" n n
7871 pr " int %s = NUM2INT (%sv);\n" n n
7876 match fst style with
7877 | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1"
7878 | RInt64 _ -> pr " int64_t r;\n"; "-1"
7879 | RConstString _ | RConstOptString _ ->
7880 pr " const char *r;\n"; "NULL"
7881 | RString _ -> pr " char *r;\n"; "NULL"
7882 | RStringList _ | RHashtable _ -> pr " char **r;\n"; "NULL"
7883 | RStruct (_, typ) -> pr " struct guestfs_%s *r;\n" typ; "NULL"
7884 | RStructList (_, typ) ->
7885 pr " struct guestfs_%s_list *r;\n" typ; "NULL"
7888 pr " size_t size;\n";
7892 pr " r = guestfs_%s " name;
7893 generate_c_call_args ~handle:"g" style;
7898 | Pathname _ | Device _ | String _
7899 | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ -> ()
7901 pr " free (%s);\n" n
7904 pr " if (r == %s)\n" error_code;
7905 pr " rb_raise (e_Error, \"%%s\", guestfs_last_error (g));\n";
7908 (match fst style with
7910 pr " return Qnil;\n"
7911 | RInt _ | RBool _ ->
7912 pr " return INT2NUM (r);\n"
7914 pr " return ULL2NUM (r);\n"
7916 pr " return rb_str_new2 (r);\n";
7917 | RConstOptString _ ->
7919 pr " return rb_str_new2 (r);\n";
7921 pr " return Qnil;\n";
7923 pr " VALUE rv = rb_str_new2 (r);\n";
7927 pr " int i, len = 0;\n";
7928 pr " for (i = 0; r[i] != NULL; ++i) len++;\n";
7929 pr " VALUE rv = rb_ary_new2 (len);\n";
7930 pr " for (i = 0; r[i] != NULL; ++i) {\n";
7931 pr " rb_ary_push (rv, rb_str_new2 (r[i]));\n";
7932 pr " free (r[i]);\n";
7936 | RStruct (_, typ) ->
7937 let cols = cols_of_struct typ in
7938 generate_ruby_struct_code typ cols
7939 | RStructList (_, typ) ->
7940 let cols = cols_of_struct typ in
7941 generate_ruby_struct_list_code typ cols
7943 pr " VALUE rv = rb_hash_new ();\n";
7945 pr " for (i = 0; r[i] != NULL; i+=2) {\n";
7946 pr " rb_hash_aset (rv, rb_str_new2 (r[i]), rb_str_new2 (r[i+1]));\n";
7947 pr " free (r[i]);\n";
7948 pr " free (r[i+1]);\n";
7953 pr " VALUE rv = rb_str_new (r, size);\n";
7963 /* Initialize the module. */
7964 void Init__guestfs ()
7966 m_guestfs = rb_define_module (\"Guestfs\");
7967 c_guestfs = rb_define_class_under (m_guestfs, \"Guestfs\", rb_cObject);
7968 e_Error = rb_define_class_under (m_guestfs, \"Error\", rb_eStandardError);
7970 rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
7971 rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
7974 (* Define the rest of the methods. *)
7976 fun (name, style, _, _, _, _, _) ->
7977 pr " rb_define_method (c_guestfs, \"%s\",\n" name;
7978 pr " ruby_guestfs_%s, %d);\n" name (List.length (snd style))
7983 (* Ruby code to return a struct. *)
7984 and generate_ruby_struct_code typ cols =
7985 pr " VALUE rv = rb_hash_new ();\n";
7989 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new2 (r->%s));\n" name name
7991 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, r->%s_len));\n" name name name
7993 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_str_new (r->%s, 32));\n" name name
7994 | name, (FBytes|FUInt64) ->
7995 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
7997 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), LL2NUM (r->%s));\n" name name
7999 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), UINT2NUM (r->%s));\n" name name
8001 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), INT2NUM (r->%s));\n" name name
8002 | name, FOptPercent ->
8003 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), rb_dbl2big (r->%s));\n" name name
8004 | name, FChar -> (* XXX wrong? *)
8005 pr " rb_hash_aset (rv, rb_str_new2 (\"%s\"), ULL2NUM (r->%s));\n" name name
8007 pr " guestfs_free_%s (r);\n" typ;
8010 (* Ruby code to return a struct list. *)
8011 and generate_ruby_struct_list_code typ cols =
8012 pr " VALUE rv = rb_ary_new2 (r->len);\n";
8014 pr " for (i = 0; i < r->len; ++i) {\n";
8015 pr " VALUE hv = rb_hash_new ();\n";
8019 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new2 (r->val[i].%s));\n" name name
8021 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
8023 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_str_new (r->val[i].%s, 32));\n" name name
8024 | name, (FBytes|FUInt64) ->
8025 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
8027 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), LL2NUM (r->val[i].%s));\n" name name
8029 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), UINT2NUM (r->val[i].%s));\n" name name
8031 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), INT2NUM (r->val[i].%s));\n" name name
8032 | name, FOptPercent ->
8033 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), rb_dbl2big (r->val[i].%s));\n" name name
8034 | name, FChar -> (* XXX wrong? *)
8035 pr " rb_hash_aset (hv, rb_str_new2 (\"%s\"), ULL2NUM (r->val[i].%s));\n" name name
8037 pr " rb_ary_push (rv, hv);\n";
8039 pr " guestfs_free_%s_list (r);\n" typ;
8042 (* Generate Java bindings GuestFS.java file. *)
8043 and generate_java_java () =
8044 generate_header CStyle LGPLv2;
8047 package com.redhat.et.libguestfs;
8049 import java.util.HashMap;
8050 import com.redhat.et.libguestfs.LibGuestFSException;
8051 import com.redhat.et.libguestfs.PV;
8052 import com.redhat.et.libguestfs.VG;
8053 import com.redhat.et.libguestfs.LV;
8054 import com.redhat.et.libguestfs.Stat;
8055 import com.redhat.et.libguestfs.StatVFS;
8056 import com.redhat.et.libguestfs.IntBool;
8057 import com.redhat.et.libguestfs.Dirent;
8060 * The GuestFS object is a libguestfs handle.
8064 public class GuestFS {
8065 // Load the native code.
8067 System.loadLibrary (\"guestfs_jni\");
8071 * The native guestfs_h pointer.
8076 * Create a libguestfs handle.
8078 * @throws LibGuestFSException
8080 public GuestFS () throws LibGuestFSException
8084 private native long _create () throws LibGuestFSException;
8087 * Close a libguestfs handle.
8089 * You can also leave handles to be collected by the garbage
8090 * collector, but this method ensures that the resources used
8091 * by the handle are freed up immediately. If you call any
8092 * other methods after closing the handle, you will get an
8095 * @throws LibGuestFSException
8097 public void close () throws LibGuestFSException
8103 private native void _close (long g) throws LibGuestFSException;
8105 public void finalize () throws LibGuestFSException
8113 fun (name, style, _, flags, _, shortdesc, longdesc) ->
8114 if not (List.mem NotInDocs flags); then (
8115 let doc = replace_str longdesc "C<guestfs_" "C<g." in
8117 if List.mem ProtocolLimitWarning flags then
8118 doc ^ "\n\n" ^ protocol_limit_warning
8121 if List.mem DangerWillRobinson flags then
8122 doc ^ "\n\n" ^ danger_will_robinson
8125 match deprecation_notice flags with
8127 | Some txt -> doc ^ "\n\n" ^ txt in
8128 let doc = pod2text ~width:60 name doc in
8129 let doc = List.map ( (* RHBZ#501883 *)
8132 | nonempty -> nonempty
8134 let doc = String.concat "\n * " doc in
8137 pr " * %s\n" shortdesc;
8140 pr " * @throws LibGuestFSException\n";
8144 generate_java_prototype ~public:true ~semicolon:false name style;
8147 pr " if (g == 0)\n";
8148 pr " throw new LibGuestFSException (\"%s: handle is closed\");\n"
8151 if fst style <> RErr then pr "return ";
8153 generate_java_call_args ~handle:"g" (snd style);
8157 generate_java_prototype ~privat:true ~native:true name style;
8164 (* Generate Java call arguments, eg "(handle, foo, bar)" *)
8165 and generate_java_call_args ~handle args =
8167 List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
8170 and generate_java_prototype ?(public=false) ?(privat=false) ?(native=false)
8171 ?(semicolon=true) name style =
8172 if privat then pr "private ";
8173 if public then pr "public ";
8174 if native then pr "native ";
8177 (match fst style with
8178 | RErr -> pr "void ";
8179 | RInt _ -> pr "int ";
8180 | RInt64 _ -> pr "long ";
8181 | RBool _ -> pr "boolean ";
8182 | RConstString _ | RConstOptString _ | RString _
8183 | RBufferOut _ -> pr "String ";
8184 | RStringList _ -> pr "String[] ";
8185 | RStruct (_, typ) ->
8186 let name = java_name_of_struct typ in
8188 | RStructList (_, typ) ->
8189 let name = java_name_of_struct typ in
8191 | RHashtable _ -> pr "HashMap<String,String> ";
8194 if native then pr "_%s " name else pr "%s " name;
8196 let needs_comma = ref false in
8205 if !needs_comma then pr ", ";
8206 needs_comma := true;
8225 pr " throws LibGuestFSException";
8226 if semicolon then pr ";"
8228 and generate_java_struct jtyp cols =
8229 generate_header CStyle LGPLv2;
8232 package com.redhat.et.libguestfs;
8235 * Libguestfs %s structure.
8247 | name, FBuffer -> pr " public String %s;\n" name
8248 | name, (FBytes|FUInt64|FInt64) -> pr " public long %s;\n" name
8249 | name, (FUInt32|FInt32) -> pr " public int %s;\n" name
8250 | name, FChar -> pr " public char %s;\n" name
8251 | name, FOptPercent ->
8252 pr " /* The next field is [0..100] or -1 meaning 'not present': */\n";
8253 pr " public float %s;\n" name
8258 and generate_java_c () =
8259 generate_header CStyle LGPLv2;
8266 #include \"com_redhat_et_libguestfs_GuestFS.h\"
8267 #include \"guestfs.h\"
8269 /* Note that this function returns. The exception is not thrown
8270 * until after the wrapper function returns.
8273 throw_exception (JNIEnv *env, const char *msg)
8276 cl = (*env)->FindClass (env,
8277 \"com/redhat/et/libguestfs/LibGuestFSException\");
8278 (*env)->ThrowNew (env, cl, msg);
8281 JNIEXPORT jlong JNICALL
8282 Java_com_redhat_et_libguestfs_GuestFS__1create
8283 (JNIEnv *env, jobject obj)
8287 g = guestfs_create ();
8289 throw_exception (env, \"GuestFS.create: failed to allocate handle\");
8292 guestfs_set_error_handler (g, NULL, NULL);
8293 return (jlong) (long) g;
8296 JNIEXPORT void JNICALL
8297 Java_com_redhat_et_libguestfs_GuestFS__1close
8298 (JNIEnv *env, jobject obj, jlong jg)
8300 guestfs_h *g = (guestfs_h *) (long) jg;
8307 fun (name, style, _, _, _, _, _) ->
8309 (match fst style with
8310 | RErr -> pr "void ";
8311 | RInt _ -> pr "jint ";
8312 | RInt64 _ -> pr "jlong ";
8313 | RBool _ -> pr "jboolean ";
8314 | RConstString _ | RConstOptString _ | RString _
8315 | RBufferOut _ -> pr "jstring ";
8316 | RStruct _ | RHashtable _ ->
8318 | RStringList _ | RStructList _ ->
8322 pr "Java_com_redhat_et_libguestfs_GuestFS_";
8323 pr "%s" (replace_str ("_" ^ name) "_" "_1");
8325 pr " (JNIEnv *env, jobject obj, jlong jg";
8334 pr ", jstring j%s" n
8336 pr ", jobjectArray j%s" n
8338 pr ", jboolean j%s" n
8344 pr " guestfs_h *g = (guestfs_h *) (long) jg;\n";
8345 let error_code, no_ret =
8346 match fst style with
8347 | RErr -> pr " int r;\n"; "-1", ""
8349 | RInt _ -> pr " int r;\n"; "-1", "0"
8350 | RInt64 _ -> pr " int64_t r;\n"; "-1", "0"
8351 | RConstString _ -> pr " const char *r;\n"; "NULL", "NULL"
8352 | RConstOptString _ -> pr " const char *r;\n"; "NULL", "NULL"
8354 pr " jstring jr;\n";
8355 pr " char *r;\n"; "NULL", "NULL"
8357 pr " jobjectArray jr;\n";
8360 pr " jstring jstr;\n";
8361 pr " char **r;\n"; "NULL", "NULL"
8362 | RStruct (_, typ) ->
8363 pr " jobject jr;\n";
8365 pr " jfieldID fl;\n";
8366 pr " struct guestfs_%s *r;\n" typ; "NULL", "NULL"
8367 | RStructList (_, typ) ->
8368 pr " jobjectArray jr;\n";
8370 pr " jfieldID fl;\n";
8371 pr " jobject jfl;\n";
8372 pr " struct guestfs_%s_list *r;\n" typ; "NULL", "NULL"
8373 | RHashtable _ -> pr " char **r;\n"; "NULL", "NULL"
8375 pr " jstring jr;\n";
8377 pr " size_t size;\n";
8387 pr " const char *%s;\n" n
8389 pr " int %s_len;\n" n;
8390 pr " const char **%s;\n" n
8397 (match fst style with
8398 | RStringList _ | RStructList _ -> true
8399 | RErr | RBool _ | RInt _ | RInt64 _ | RConstString _
8401 | RString _ | RBufferOut _ | RStruct _ | RHashtable _ -> false) ||
8402 List.exists (function StringList _ -> true | _ -> false) (snd style) in
8408 (* Get the parameters. *)
8416 pr " %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
8418 (* This is completely undocumented, but Java null becomes
8421 pr " %s = j%s ? (*env)->GetStringUTFChars (env, j%s, NULL) : NULL;\n" n n n
8423 pr " %s_len = (*env)->GetArrayLength (env, j%s);\n" n n;
8424 pr " %s = guestfs_safe_malloc (g, sizeof (char *) * (%s_len+1));\n" n n;
8425 pr " for (i = 0; i < %s_len; ++i) {\n" n;
8426 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
8428 pr " %s[i] = (*env)->GetStringUTFChars (env, o, NULL);\n" n;
8430 pr " %s[%s_len] = NULL;\n" n n;
8433 pr " %s = j%s;\n" n n
8436 (* Make the call. *)
8437 pr " r = guestfs_%s " name;
8438 generate_c_call_args ~handle:"g" style;
8441 (* Release the parameters. *)
8449 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
8452 pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
8454 pr " for (i = 0; i < %s_len; ++i) {\n" n;
8455 pr " jobject o = (*env)->GetObjectArrayElement (env, j%s, i);\n"
8457 pr " (*env)->ReleaseStringUTFChars (env, o, %s[i]);\n" n;
8459 pr " free (%s);\n" n
8464 (* Check for errors. *)
8465 pr " if (r == %s) {\n" error_code;
8466 pr " throw_exception (env, guestfs_last_error (g));\n";
8467 pr " return %s;\n" no_ret;
8471 (match fst style with
8473 | RInt _ -> pr " return (jint) r;\n"
8474 | RBool _ -> pr " return (jboolean) r;\n"
8475 | RInt64 _ -> pr " return (jlong) r;\n"
8476 | RConstString _ -> pr " return (*env)->NewStringUTF (env, r);\n"
8477 | RConstOptString _ ->
8478 pr " return (*env)->NewStringUTF (env, r); /* XXX r NULL? */\n"
8480 pr " jr = (*env)->NewStringUTF (env, r);\n";
8484 pr " for (r_len = 0; r[r_len] != NULL; ++r_len) ;\n";
8485 pr " cl = (*env)->FindClass (env, \"java/lang/String\");\n";
8486 pr " jstr = (*env)->NewStringUTF (env, \"\");\n";
8487 pr " jr = (*env)->NewObjectArray (env, r_len, cl, jstr);\n";
8488 pr " for (i = 0; i < r_len; ++i) {\n";
8489 pr " jstr = (*env)->NewStringUTF (env, r[i]);\n";
8490 pr " (*env)->SetObjectArrayElement (env, jr, i, jstr);\n";
8491 pr " free (r[i]);\n";
8495 | RStruct (_, typ) ->
8496 let jtyp = java_name_of_struct typ in
8497 let cols = cols_of_struct typ in
8498 generate_java_struct_return typ jtyp cols
8499 | RStructList (_, typ) ->
8500 let jtyp = java_name_of_struct typ in
8501 let cols = cols_of_struct typ in
8502 generate_java_struct_list_return typ jtyp cols
8505 pr " throw_exception (env, \"%s: internal error: please let us know how to make a Java HashMap from JNI bindings!\");\n" name;
8506 pr " return NULL;\n"
8508 pr " jr = (*env)->NewStringUTF (env, r); /* XXX size */\n";
8517 and generate_java_struct_return typ jtyp cols =
8518 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
8519 pr " jr = (*env)->AllocObject (env, cl);\n";
8523 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8524 pr " (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, r->%s));\n" name;
8527 pr " char s[33];\n";
8528 pr " memcpy (s, r->%s, 32);\n" name;
8530 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8531 pr " (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
8535 pr " int len = r->%s_len;\n" name;
8536 pr " char s[len+1];\n";
8537 pr " memcpy (s, r->%s, len);\n" name;
8538 pr " s[len] = 0;\n";
8539 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8540 pr " (*env)->SetObjectField (env, jr, fl, (*env)->NewStringUTF (env, s));\n";
8542 | name, (FBytes|FUInt64|FInt64) ->
8543 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
8544 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
8545 | name, (FUInt32|FInt32) ->
8546 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
8547 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
8548 | name, FOptPercent ->
8549 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
8550 pr " (*env)->SetFloatField (env, jr, fl, r->%s);\n" name;
8552 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
8553 pr " (*env)->SetLongField (env, jr, fl, r->%s);\n" name;
8558 and generate_java_struct_list_return typ jtyp cols =
8559 pr " cl = (*env)->FindClass (env, \"com/redhat/et/libguestfs/%s\");\n" jtyp;
8560 pr " jr = (*env)->NewObjectArray (env, r->len, cl, NULL);\n";
8561 pr " for (i = 0; i < r->len; ++i) {\n";
8562 pr " jfl = (*env)->AllocObject (env, cl);\n";
8566 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8567 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, r->val[i].%s));\n" name;
8570 pr " char s[33];\n";
8571 pr " memcpy (s, r->val[i].%s, 32);\n" name;
8573 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8574 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
8578 pr " int len = r->val[i].%s_len;\n" name;
8579 pr " char s[len+1];\n";
8580 pr " memcpy (s, r->val[i].%s, len);\n" name;
8581 pr " s[len] = 0;\n";
8582 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"Ljava/lang/String;\");\n" name;
8583 pr " (*env)->SetObjectField (env, jfl, fl, (*env)->NewStringUTF (env, s));\n";
8585 | name, (FBytes|FUInt64|FInt64) ->
8586 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"J\");\n" name;
8587 pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
8588 | name, (FUInt32|FInt32) ->
8589 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"I\");\n" name;
8590 pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
8591 | name, FOptPercent ->
8592 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"F\");\n" name;
8593 pr " (*env)->SetFloatField (env, jfl, fl, r->val[i].%s);\n" name;
8595 pr " fl = (*env)->GetFieldID (env, cl, \"%s\", \"C\");\n" name;
8596 pr " (*env)->SetLongField (env, jfl, fl, r->val[i].%s);\n" name;
8598 pr " (*env)->SetObjectArrayElement (env, jfl, i, jfl);\n";
8600 pr " guestfs_free_%s_list (r);\n" typ;
8603 and generate_java_makefile_inc () =
8604 generate_header HashStyle GPLv2;
8606 pr "java_built_sources = \\\n";
8609 pr "\tcom/redhat/et/libguestfs/%s.java \\\n" jtyp;
8611 pr "\tcom/redhat/et/libguestfs/GuestFS.java\n"
8613 and generate_haskell_hs () =
8614 generate_header HaskellStyle LGPLv2;
8616 (* XXX We only know how to generate partial FFI for Haskell
8617 * at the moment. Please help out!
8619 let can_generate style =
8623 | RInt64 _, _ -> true
8626 | RConstOptString _, _
8632 | RBufferOut _, _ -> false in
8635 {-# INCLUDE <guestfs.h> #-}
8636 {-# LANGUAGE ForeignFunctionInterface #-}
8641 (* List out the names of the actions we want to export. *)
8643 fun (name, style, _, _, _, _, _) ->
8644 if can_generate style then pr ",\n %s" name
8651 import Foreign.C.Types
8653 import Control.Exception
8654 import Data.Typeable
8656 data GuestfsS = GuestfsS -- represents the opaque C struct
8657 type GuestfsP = Ptr GuestfsS -- guestfs_h *
8658 type GuestfsH = ForeignPtr GuestfsS -- guestfs_h * with attached finalizer
8660 -- XXX define properly later XXX
8664 data IntBool = IntBool
8666 data StatVFS = StatVFS
8667 data Hashtable = Hashtable
8669 foreign import ccall unsafe \"guestfs_create\" c_create
8671 foreign import ccall unsafe \"&guestfs_close\" c_close
8672 :: FunPtr (GuestfsP -> IO ())
8673 foreign import ccall unsafe \"guestfs_set_error_handler\" c_set_error_handler
8674 :: GuestfsP -> Ptr CInt -> Ptr CInt -> IO ()
8676 create :: IO GuestfsH
8679 c_set_error_handler p nullPtr nullPtr
8680 h <- newForeignPtr c_close p
8683 foreign import ccall unsafe \"guestfs_last_error\" c_last_error
8684 :: GuestfsP -> IO CString
8686 -- last_error :: GuestfsH -> IO (Maybe String)
8687 -- last_error h = do
8688 -- str <- withForeignPtr h (\\p -> c_last_error p)
8689 -- maybePeek peekCString str
8691 last_error :: GuestfsH -> IO (String)
8693 str <- withForeignPtr h (\\p -> c_last_error p)
8695 then return \"no error\"
8696 else peekCString str
8700 (* Generate wrappers for each foreign function. *)
8702 fun (name, style, _, _, _, _, _) ->
8703 if can_generate style then (
8704 pr "foreign import ccall unsafe \"guestfs_%s\" c_%s\n" name name;
8706 generate_haskell_prototype ~handle:"GuestfsP" style;
8710 generate_haskell_prototype ~handle:"GuestfsH" ~hs:true style;
8712 pr "%s %s = do\n" name
8713 (String.concat " " ("h" :: List.map name_of_argt (snd style)));
8715 (* Convert pointer arguments using with* functions. *)
8720 | Pathname n | Device n | String n -> pr "withCString %s $ \\%s -> " n n
8721 | OptString n -> pr "maybeWith withCString %s $ \\%s -> " n n
8722 | StringList n -> pr "withMany withCString %s $ \\%s -> withArray0 nullPtr %s $ \\%s -> " n n n n
8723 | Bool _ | Int _ -> ()
8725 (* Convert integer arguments. *)
8729 | Bool n -> sprintf "(fromBool %s)" n
8730 | Int n -> sprintf "(fromIntegral %s)" n
8731 | FileIn n | FileOut n
8732 | Pathname n | Device n | String n | OptString n | StringList n -> n
8734 pr "withForeignPtr h (\\p -> c_%s %s)\n" name
8735 (String.concat " " ("p" :: args));
8736 (match fst style with
8737 | RErr | RInt _ | RInt64 _ | RBool _ ->
8738 pr " if (r == -1)\n";
8740 pr " err <- last_error h\n";
8742 | RConstString _ | RConstOptString _ | RString _
8743 | RStringList _ | RStruct _
8744 | RStructList _ | RHashtable _ | RBufferOut _ ->
8745 pr " if (r == nullPtr)\n";
8747 pr " err <- last_error h\n";
8750 (match fst style with
8752 pr " else return ()\n"
8754 pr " else return (fromIntegral r)\n"
8756 pr " else return (fromIntegral r)\n"
8758 pr " else return (toBool r)\n"
8767 pr " else return ()\n" (* XXXXXXXXXXXXXXXXXXXX *)
8773 and generate_haskell_prototype ~handle ?(hs = false) style =
8775 let string = if hs then "String" else "CString" in
8776 let int = if hs then "Int" else "CInt" in
8777 let bool = if hs then "Bool" else "CInt" in
8778 let int64 = if hs then "Integer" else "Int64" in
8782 | Pathname _ | Device _ | String _ -> pr "%s" string
8783 | OptString _ -> if hs then pr "Maybe String" else pr "CString"
8784 | StringList _ -> if hs then pr "[String]" else pr "Ptr CString"
8785 | Bool _ -> pr "%s" bool
8786 | Int _ -> pr "%s" int
8787 | FileIn _ -> pr "%s" string
8788 | FileOut _ -> pr "%s" string
8793 (match fst style with
8794 | RErr -> if not hs then pr "CInt"
8795 | RInt _ -> pr "%s" int
8796 | RInt64 _ -> pr "%s" int64
8797 | RBool _ -> pr "%s" bool
8798 | RConstString _ -> pr "%s" string
8799 | RConstOptString _ -> pr "Maybe %s" string
8800 | RString _ -> pr "%s" string
8801 | RStringList _ -> pr "[%s]" string
8802 | RStruct (_, typ) ->
8803 let name = java_name_of_struct typ in
8805 | RStructList (_, typ) ->
8806 let name = java_name_of_struct typ in
8808 | RHashtable _ -> pr "Hashtable"
8809 | RBufferOut _ -> pr "%s" string
8813 and generate_bindtests () =
8814 generate_header CStyle LGPLv2;
8819 #include <inttypes.h>
8822 #include \"guestfs.h\"
8823 #include \"guestfs_protocol.h\"
8825 #define error guestfs_error
8826 #define safe_calloc guestfs_safe_calloc
8827 #define safe_malloc guestfs_safe_malloc
8830 print_strings (char * const* const argv)
8835 for (argc = 0; argv[argc] != NULL; ++argc) {
8836 if (argc > 0) printf (\", \");
8837 printf (\"\\\"%%s\\\"\", argv[argc]);
8842 /* The test0 function prints its parameters to stdout. */
8846 match test_functions with
8847 | [] -> assert false
8848 | test0 :: tests -> test0, tests in
8851 let (name, style, _, _, _, _, _) = test0 in
8852 generate_prototype ~extern:false ~semicolon:false ~newline:true
8853 ~handle:"g" ~prefix:"guestfs_" name style;
8861 | FileOut n -> pr " printf (\"%%s\\n\", %s);\n" n
8862 | OptString n -> pr " printf (\"%%s\\n\", %s ? %s : \"null\");\n" n n
8863 | StringList n -> pr " print_strings (%s);\n" n
8864 | Bool n -> pr " printf (\"%%s\\n\", %s ? \"true\" : \"false\");\n" n
8865 | Int n -> pr " printf (\"%%d\\n\", %s);\n" n
8867 pr " /* Java changes stdout line buffering so we need this: */\n";
8868 pr " fflush (stdout);\n";
8874 fun (name, style, _, _, _, _, _) ->
8875 if String.sub name (String.length name - 3) 3 <> "err" then (
8876 pr "/* Test normal return. */\n";
8877 generate_prototype ~extern:false ~semicolon:false ~newline:true
8878 ~handle:"g" ~prefix:"guestfs_" name style;
8880 (match fst style with
8885 pr " sscanf (val, \"%%d\", &r);\n";
8889 pr " sscanf (val, \"%%\" SCNi64, &r);\n";
8892 pr " return strcmp (val, \"true\") == 0;\n"
8894 | RConstOptString _ ->
8895 (* Can't return the input string here. Return a static
8896 * string so we ensure we get a segfault if the caller
8899 pr " return \"static string\";\n"
8901 pr " return strdup (val);\n"
8903 pr " char **strs;\n";
8905 pr " sscanf (val, \"%%d\", &n);\n";
8906 pr " strs = safe_malloc (g, (n+1) * sizeof (char *));\n";
8907 pr " for (i = 0; i < n; ++i) {\n";
8908 pr " strs[i] = safe_malloc (g, 16);\n";
8909 pr " snprintf (strs[i], 16, \"%%d\", i);\n";
8911 pr " strs[n] = NULL;\n";
8912 pr " return strs;\n"
8913 | RStruct (_, typ) ->
8914 pr " struct guestfs_%s *r;\n" typ;
8915 pr " r = safe_calloc (g, sizeof *r, 1);\n";
8917 | RStructList (_, typ) ->
8918 pr " struct guestfs_%s_list *r;\n" typ;
8919 pr " r = safe_calloc (g, sizeof *r, 1);\n";
8920 pr " sscanf (val, \"%%d\", &r->len);\n";
8921 pr " r->val = safe_calloc (g, r->len, sizeof *r->val);\n";
8924 pr " char **strs;\n";
8926 pr " sscanf (val, \"%%d\", &n);\n";
8927 pr " strs = safe_malloc (g, (n*2+1) * sizeof (*strs));\n";
8928 pr " for (i = 0; i < n; ++i) {\n";
8929 pr " strs[i*2] = safe_malloc (g, 16);\n";
8930 pr " strs[i*2+1] = safe_malloc (g, 16);\n";
8931 pr " snprintf (strs[i*2], 16, \"%%d\", i);\n";
8932 pr " snprintf (strs[i*2+1], 16, \"%%d\", i);\n";
8934 pr " strs[n*2] = NULL;\n";
8935 pr " return strs;\n"
8937 pr " return strdup (val);\n"
8942 pr "/* Test error return. */\n";
8943 generate_prototype ~extern:false ~semicolon:false ~newline:true
8944 ~handle:"g" ~prefix:"guestfs_" name style;
8946 pr " error (g, \"error\");\n";
8947 (match fst style with
8948 | RErr | RInt _ | RInt64 _ | RBool _ ->
8950 | RConstString _ | RConstOptString _
8951 | RString _ | RStringList _ | RStruct _
8955 pr " return NULL;\n"
8962 and generate_ocaml_bindtests () =
8963 generate_header OCamlStyle GPLv2;
8967 let g = Guestfs.create () in
8974 | CallString s -> "\"" ^ s ^ "\""
8975 | CallOptString None -> "None"
8976 | CallOptString (Some s) -> sprintf "(Some \"%s\")" s
8977 | CallStringList xs ->
8978 "[|" ^ String.concat ";" (List.map (sprintf "\"%s\"") xs) ^ "|]"
8979 | CallInt i when i >= 0 -> string_of_int i
8980 | CallInt i (* when i < 0 *) -> "(" ^ string_of_int i ^ ")"
8981 | CallBool b -> string_of_bool b
8986 generate_lang_bindtests (
8987 fun f args -> pr " Guestfs.%s g %s;\n" f (mkargs args)
8990 pr "print_endline \"EOF\"\n"
8992 and generate_perl_bindtests () =
8993 pr "#!/usr/bin/perl -w\n";
8994 generate_header HashStyle GPLv2;
9001 my $g = Sys::Guestfs->new ();
9005 String.concat ", " (
9008 | CallString s -> "\"" ^ s ^ "\""
9009 | CallOptString None -> "undef"
9010 | CallOptString (Some s) -> sprintf "\"%s\"" s
9011 | CallStringList xs ->
9012 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
9013 | CallInt i -> string_of_int i
9014 | CallBool b -> if b then "1" else "0"
9019 generate_lang_bindtests (
9020 fun f args -> pr "$g->%s (%s);\n" f (mkargs args)
9023 pr "print \"EOF\\n\"\n"
9025 and generate_python_bindtests () =
9026 generate_header HashStyle GPLv2;
9031 g = guestfs.GuestFS ()
9035 String.concat ", " (
9038 | CallString s -> "\"" ^ s ^ "\""
9039 | CallOptString None -> "None"
9040 | CallOptString (Some s) -> sprintf "\"%s\"" s
9041 | CallStringList xs ->
9042 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
9043 | CallInt i -> string_of_int i
9044 | CallBool b -> if b then "1" else "0"
9049 generate_lang_bindtests (
9050 fun f args -> pr "g.%s (%s)\n" f (mkargs args)
9053 pr "print \"EOF\"\n"
9055 and generate_ruby_bindtests () =
9056 generate_header HashStyle GPLv2;
9061 g = Guestfs::create()
9065 String.concat ", " (
9068 | CallString s -> "\"" ^ s ^ "\""
9069 | CallOptString None -> "nil"
9070 | CallOptString (Some s) -> sprintf "\"%s\"" s
9071 | CallStringList xs ->
9072 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
9073 | CallInt i -> string_of_int i
9074 | CallBool b -> string_of_bool b
9079 generate_lang_bindtests (
9080 fun f args -> pr "g.%s(%s)\n" f (mkargs args)
9083 pr "print \"EOF\\n\"\n"
9085 and generate_java_bindtests () =
9086 generate_header CStyle GPLv2;
9089 import com.redhat.et.libguestfs.*;
9091 public class Bindtests {
9092 public static void main (String[] argv)
9095 GuestFS g = new GuestFS ();
9099 String.concat ", " (
9102 | CallString s -> "\"" ^ s ^ "\""
9103 | CallOptString None -> "null"
9104 | CallOptString (Some s) -> sprintf "\"%s\"" s
9105 | CallStringList xs ->
9107 String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "}"
9108 | CallInt i -> string_of_int i
9109 | CallBool b -> string_of_bool b
9114 generate_lang_bindtests (
9115 fun f args -> pr " g.%s (%s);\n" f (mkargs args)
9119 System.out.println (\"EOF\");
9121 catch (Exception exn) {
9122 System.err.println (exn);
9129 and generate_haskell_bindtests () =
9130 generate_header HaskellStyle GPLv2;
9133 module Bindtests where
9134 import qualified Guestfs
9144 | CallString s -> "\"" ^ s ^ "\""
9145 | CallOptString None -> "Nothing"
9146 | CallOptString (Some s) -> sprintf "(Just \"%s\")" s
9147 | CallStringList xs ->
9148 "[" ^ String.concat "," (List.map (sprintf "\"%s\"") xs) ^ "]"
9149 | CallInt i when i < 0 -> "(" ^ string_of_int i ^ ")"
9150 | CallInt i -> string_of_int i
9151 | CallBool true -> "True"
9152 | CallBool false -> "False"
9157 generate_lang_bindtests (
9158 fun f args -> pr " Guestfs.%s g %s\n" f (mkargs args)
9161 pr " putStrLn \"EOF\"\n"
9163 (* Language-independent bindings tests - we do it this way to
9164 * ensure there is parity in testing bindings across all languages.
9166 and generate_lang_bindtests call =
9167 call "test0" [CallString "abc"; CallOptString (Some "def");
9168 CallStringList []; CallBool false;
9169 CallInt 0; CallString "123"; CallString "456"];
9170 call "test0" [CallString "abc"; CallOptString None;
9171 CallStringList []; CallBool false;
9172 CallInt 0; CallString "123"; CallString "456"];
9173 call "test0" [CallString ""; CallOptString (Some "def");
9174 CallStringList []; CallBool false;
9175 CallInt 0; CallString "123"; CallString "456"];
9176 call "test0" [CallString ""; CallOptString (Some "");
9177 CallStringList []; CallBool false;
9178 CallInt 0; CallString "123"; CallString "456"];
9179 call "test0" [CallString "abc"; CallOptString (Some "def");
9180 CallStringList ["1"]; CallBool false;
9181 CallInt 0; CallString "123"; CallString "456"];
9182 call "test0" [CallString "abc"; CallOptString (Some "def");
9183 CallStringList ["1"; "2"]; CallBool false;
9184 CallInt 0; CallString "123"; CallString "456"];
9185 call "test0" [CallString "abc"; CallOptString (Some "def");
9186 CallStringList ["1"]; CallBool true;
9187 CallInt 0; CallString "123"; CallString "456"];
9188 call "test0" [CallString "abc"; CallOptString (Some "def");
9189 CallStringList ["1"]; CallBool false;
9190 CallInt (-1); CallString "123"; CallString "456"];
9191 call "test0" [CallString "abc"; CallOptString (Some "def");
9192 CallStringList ["1"]; CallBool false;
9193 CallInt (-2); CallString "123"; CallString "456"];
9194 call "test0" [CallString "abc"; CallOptString (Some "def");
9195 CallStringList ["1"]; CallBool false;
9196 CallInt 1; CallString "123"; CallString "456"];
9197 call "test0" [CallString "abc"; CallOptString (Some "def");
9198 CallStringList ["1"]; CallBool false;
9199 CallInt 2; CallString "123"; CallString "456"];
9200 call "test0" [CallString "abc"; CallOptString (Some "def");
9201 CallStringList ["1"]; CallBool false;
9202 CallInt 4095; CallString "123"; CallString "456"];
9203 call "test0" [CallString "abc"; CallOptString (Some "def");
9204 CallStringList ["1"]; CallBool false;
9205 CallInt 0; CallString ""; CallString ""]
9207 (* XXX Add here tests of the return and error functions. *)
9209 (* This is used to generate the src/MAX_PROC_NR file which
9210 * contains the maximum procedure number, a surrogate for the
9211 * ABI version number. See src/Makefile.am for the details.
9213 and generate_max_proc_nr () =
9214 let proc_nrs = List.map (
9215 fun (_, _, proc_nr, _, _, _, _) -> proc_nr
9216 ) daemon_functions in
9218 let max_proc_nr = List.fold_left max 0 proc_nrs in
9220 pr "%d\n" max_proc_nr
9222 let output_to filename =
9223 let filename_new = filename ^ ".new" in
9224 chan := open_out filename_new;
9229 (* Is the new file different from the current file? *)
9230 if Sys.file_exists filename && files_equal filename filename_new then
9231 Unix.unlink filename_new (* same, so skip it *)
9233 (* different, overwrite old one *)
9234 (try Unix.chmod filename 0o644 with Unix.Unix_error _ -> ());
9235 Unix.rename filename_new filename;
9236 Unix.chmod filename 0o444;
9237 printf "written %s\n%!" filename;
9246 if not (Sys.file_exists "HACKING") then (
9248 You are probably running this from the wrong directory.
9249 Run it from the top source directory using the command
9255 let close = output_to "src/guestfs_protocol.x" in
9259 let close = output_to "src/guestfs-structs.h" in
9260 generate_structs_h ();
9263 let close = output_to "src/guestfs-actions.h" in
9264 generate_actions_h ();
9267 let close = output_to "src/guestfs-actions.c" in
9268 generate_client_actions ();
9271 let close = output_to "daemon/actions.h" in
9272 generate_daemon_actions_h ();
9275 let close = output_to "daemon/stubs.c" in
9276 generate_daemon_actions ();
9279 let close = output_to "daemon/names.c" in
9280 generate_daemon_names ();
9283 let close = output_to "capitests/tests.c" in
9287 let close = output_to "src/guestfs-bindtests.c" in
9288 generate_bindtests ();
9291 let close = output_to "fish/cmds.c" in
9292 generate_fish_cmds ();
9295 let close = output_to "fish/completion.c" in
9296 generate_fish_completion ();
9299 let close = output_to "guestfs-structs.pod" in
9300 generate_structs_pod ();
9303 let close = output_to "guestfs-actions.pod" in
9304 generate_actions_pod ();
9307 let close = output_to "guestfish-actions.pod" in
9308 generate_fish_actions_pod ();
9311 let close = output_to "ocaml/guestfs.mli" in
9312 generate_ocaml_mli ();
9315 let close = output_to "ocaml/guestfs.ml" in
9316 generate_ocaml_ml ();
9319 let close = output_to "ocaml/guestfs_c_actions.c" in
9320 generate_ocaml_c ();
9323 let close = output_to "ocaml/bindtests.ml" in
9324 generate_ocaml_bindtests ();
9327 let close = output_to "perl/Guestfs.xs" in
9328 generate_perl_xs ();
9331 let close = output_to "perl/lib/Sys/Guestfs.pm" in
9332 generate_perl_pm ();
9335 let close = output_to "perl/bindtests.pl" in
9336 generate_perl_bindtests ();
9339 let close = output_to "python/guestfs-py.c" in
9340 generate_python_c ();
9343 let close = output_to "python/guestfs.py" in
9344 generate_python_py ();
9347 let close = output_to "python/bindtests.py" in
9348 generate_python_bindtests ();
9351 let close = output_to "ruby/ext/guestfs/_guestfs.c" in
9355 let close = output_to "ruby/bindtests.rb" in
9356 generate_ruby_bindtests ();
9359 let close = output_to "java/com/redhat/et/libguestfs/GuestFS.java" in
9360 generate_java_java ();
9365 let cols = cols_of_struct typ in
9366 let filename = sprintf "java/com/redhat/et/libguestfs/%s.java" jtyp in
9367 let close = output_to filename in
9368 generate_java_struct jtyp cols;
9372 let close = output_to "java/Makefile.inc" in
9373 generate_java_makefile_inc ();
9376 let close = output_to "java/com_redhat_et_libguestfs_GuestFS.c" in
9380 let close = output_to "java/Bindtests.java" in
9381 generate_java_bindtests ();
9384 let close = output_to "haskell/Guestfs.hs" in
9385 generate_haskell_hs ();
9388 let close = output_to "haskell/Bindtests.hs" in
9389 generate_haskell_bindtests ();
9392 let close = output_to "src/MAX_PROC_NR" in
9393 generate_max_proc_nr ();
9396 (* Always generate this file last, and unconditionally. It's used
9397 * by the Makefile to know when we must re-run the generator.
9399 let chan = open_out "src/stamp-generator" in