X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=src%2Fgenerator.ml;h=398fd04b6711bbf9d0c2c021f08ae217b2c350ca;hp=652564d85bff81a29446536f2094ecfde97624d4;hb=34d2df41626f1ee4172a6d40b06d72d6ed9d6348;hpb=d901cc916102f1aaccfb73396b48aa303e5b8cd7 diff --git a/src/generator.ml b/src/generator.ml index 652564d..398fd04 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -24,8 +24,9 @@ * this one to describe the interface (see the big table below), and * daemon/.c to write the implementation. * - * After editing this file, run it (./src/generator.ml) to regenerate - * all the output files. + * After editing this file, run it (./src/generator.ml) to regenerate all the + * output files. Note that if you are using a separate build directory you + * must run generator.ml from the _source_ directory. * * IMPORTANT: This script should NOT print any warnings. If it prints * warnings, you should treat them as errors. @@ -66,15 +67,16 @@ and ret = (* "RString" and "RStringList" are caller-frees. *) | RString of string | RStringList of string - (* Some limited tuples are possible: *) - | RIntBool of string * string - (* LVM PVs, VGs and LVs. *) - | RPVList of string - | RVGList of string - | RLVList of string - (* Stat buffers. *) - | RStat of string - | RStatVFS of string + (* "RStruct" is a function which returns a single named structure + * or an error indication (in C, a struct, and in other languages + * with varying representations, but usually very efficient). See + * after the function list below for the structures. + *) + | RStruct of string * string (* name of retval, name of struct *) + (* "RStructList" is a function which returns either a list/array + * of structures (could be zero-length), or an error indication. + *) + | RStructList of string * string (* name of retval, name of struct *) (* Key-value pairs of untyped strings. Turns into a hashtable or * dictionary in languages which support it. DON'T use this as a * general "bucket" for results. Prefer a stronger typed return @@ -83,6 +85,20 @@ and ret = * inefficient. Keys should be unique. NULLs are not permitted. *) | RHashtable of string + (* "RBufferOut" is handled almost exactly like RString, but + * it allows the string to contain arbitrary 8 bit data including + * ASCII NUL. In the C API this causes an implicit extra parameter + * to be added of type . The extra parameter + * returns the actual size of the return buffer in bytes. + * + * Other programming languages support strings with arbitrary 8 bit + * data. + * + * At the RPC layer we have to use the opaque<> type instead of + * string<>. Returned data is still limited to the max message + * size (ie. ~ 2 MB). + *) + | RBufferOut of string and args = argt list (* Function parameters, guestfs handle is implicit. *) @@ -109,6 +125,18 @@ and argt = *) | FileIn of string | FileOut of string +(* Not implemented: + (* Opaque buffer which can contain arbitrary 8 bit data. + * In the C API, this is expressed as pair. + * Most other languages have a string type which can contain + * ASCII NUL. We use whatever type is appropriate for each + * language. + * Buffers are limited by the total message size. To transfer + * large blocks of data, use FileIn/FileOut parameters instead. + * To return an arbitrary buffer, use RBufferOut. + *) + | BufferIn of string +*) type flags = | ProtocolLimitWarning (* display warning about protocol size limits *) @@ -116,9 +144,10 @@ type flags = | FishAlias of string (* provide an alias for this cmd in guestfish *) | FishAction of string (* call this function in guestfish *) | NotInFish (* do not export via guestfish *) + | NotInDocs (* do not add this function to documentation *) let protocol_limit_warning = - "Because of the message protocol, there is a transfer limit + "Because of the message protocol, there is a transfer limit of somewhere between 2MB and 4MB. To transfer large files you should use FTP." @@ -129,22 +158,20 @@ can easily destroy all your data>." (* You can supply zero or as many tests as you want per API call. * * Note that the test environment has 3 block devices, of size 500MB, - * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc). - * Note for partitioning purposes, the 500MB device has 63 cylinders. + * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc), and + * a fourth squashfs block device with some known files on it (/dev/sdd). + * + * Note for partitioning purposes, the 500MB device has 1015 cylinders. + * Number of cylinders was 63 for IDE emulated disks with precisely + * the same size. How exactly this is calculated is a mystery. + * + * The squashfs block device (/dev/sdd) comes from images/test.sqsh. * * To be able to run the tests in a reasonable amount of time, * the virtual machine and block devices are reused between tests. * So don't try testing kill_subprocess :-x * - * Between each test we blockdev-setrw, umount-all, lvm-remove-all - * (except InitNone). - * - * If the appliance is running an older Linux kernel (eg. RHEL 5) then - * devices are named /dev/hda etc. To cope with this, the test suite - * adds some hairly logic to detect this case, and then automagically - * replaces all strings which match "/dev/sd.*" with "/dev/hd.*". - * When writing test cases you shouldn't have to worry about this - * difference. + * Between each test we blockdev-setrw, umount-all, lvm-remove-all. * * Don't assume anything about the previous contents of the block * devices. Use 'Init*' to create some initial scenarios. @@ -154,6 +181,11 @@ can easily destroy all your data>." * skipped. Useful if testing a command which might not work on * all variations of libguestfs builds. A test that has prerequisite * of 'Always' is run unconditionally. + * + * In addition, packagers can skip individual tests by setting the + * environment variables: eg: + * SKIP_TEST__=1 SKIP_TEST_COMMAND_3=1 (skips test #3 of command) + * SKIP_TEST_=1 SKIP_TEST_ZEROFREE=1 (skips all zerofree tests) *) type tests = (test_init * test_prereq * test) list and test = @@ -168,10 +200,20 @@ and test = *) | TestOutputList of seq * string list (* Run the command sequence and expect the output of the final + * command to be the list of block devices (could be either + * "/dev/sd.." or "/dev/hd.." form - we don't check the 5th + * character of each string). + *) + | TestOutputListOfDevices of seq * string list + (* Run the command sequence and expect the output of the final * command to be the integer. *) | TestOutputInt of seq * int (* Run the command sequence and expect the output of the final + * command to be , eg. ">=", "1". + *) + | TestOutputIntOp of seq * string * int + (* Run the command sequence and expect the output of the final * command to be a true value (!= 0 or != NULL). *) | TestOutputTrue of seq @@ -195,6 +237,7 @@ and test = and test_field_compare = | CompareWithInt of string * int + | CompareWithIntOp of string * string * int | CompareWithString of string * string | CompareFieldsIntEq of string * string | CompareFieldsStrEq of string * string @@ -241,11 +284,6 @@ and test_init = and seq = cmd list and cmd = string list -(* Canned test prerequisites. *) -let env_is_true env = - sprintf "const char *str = getenv (\"%s\"); - return str && strcmp (str, \"1\") == 0;" env - (* Note about long descriptions: When referring to another * action, use the format C (ie. the full name of * the C function). This will be replaced as appropriate in other @@ -254,7 +292,77 @@ let env_is_true env = * Apart from that, long descriptions are just perldoc paragraphs. *) -let non_daemon_functions = [ +(* These test functions are used in the language binding tests. *) + +let test_all_args = [ + String "str"; + OptString "optstr"; + StringList "strlist"; + Bool "b"; + Int "integer"; + FileIn "filein"; + FileOut "fileout"; +] + +let test_all_rets = [ + (* except for RErr, which is tested thoroughly elsewhere *) + "test0rint", RInt "valout"; + "test0rint64", RInt64 "valout"; + "test0rbool", RBool "valout"; + "test0rconststring", RConstString "valout"; + "test0rstring", RString "valout"; + "test0rstringlist", RStringList "valout"; + "test0rstruct", RStruct ("valout", "lvm_pv"); + "test0rstructlist", RStructList ("valout", "lvm_pv"); + "test0rhashtable", RHashtable "valout"; +] + +let test_functions = [ + ("test0", (RErr, test_all_args), -1, [NotInFish; NotInDocs], + [], + "internal test function - do not use", + "\ +This is an internal test function which is used to test whether +the automatically generated bindings can handle every possible +parameter type correctly. + +It echos the contents of each parameter to stdout. + +You probably don't want to call this function."); +] @ List.flatten ( + List.map ( + fun (name, ret) -> + [(name, (ret, [String "val"]), -1, [NotInFish; NotInDocs], + [], + "internal test function - do not use", + "\ +This is an internal test function which is used to test whether +the automatically generated bindings can handle every possible +return type correctly. + +It converts string C to the return type. + +You probably don't want to call this function."); + (name ^ "err", (ret, []), -1, [NotInFish; NotInDocs], + [], + "internal test function - do not use", + "\ +This is an internal test function which is used to test whether +the automatically generated bindings can handle every possible +return type correctly. + +This function always returns an error. + +You probably don't want to call this function.")] + ) test_all_rets +) + +(* non_daemon_functions are any functions which don't get processed + * in the daemon, eg. functions for setting and getting local + * configuration values. + *) + +let non_daemon_functions = test_functions @ [ ("launch", (RErr, []), -1, [FishAlias "run"; FishAction "launch"], [], "launch the qemu subprocess", @@ -296,7 +404,13 @@ for whatever operations you want to perform (ie. read access if you just want to read the image or write access if you want to modify the image). -This is equivalent to the qemu parameter C<-drive file=filename>."); +This is equivalent to the qemu parameter +C<-drive file=filename,cache=off,if=...>. + +Note that this call checks for the existence of C. This +stops you from specifying other types of drive which are supported +by qemu such as C and C URLs. To specify those, use +the general C call instead."); ("add_cdrom", (RErr, [String "filename"]), -1, [FishAlias "cdrom"], [], @@ -304,7 +418,33 @@ This is equivalent to the qemu parameter C<-drive file=filename>."); "\ This function adds a virtual CD-ROM disk image to the guest. -This is equivalent to the qemu parameter C<-cdrom filename>."); +This is equivalent to the qemu parameter C<-cdrom filename>. + +Note that this call checks for the existence of C. This +stops you from specifying other types of drive which are supported +by qemu such as C and C URLs. To specify those, use +the general C call instead."); + + ("add_drive_ro", (RErr, [String "filename"]), -1, [FishAlias "add-ro"], + [], + "add a drive in snapshot mode (read-only)", + "\ +This adds a drive in snapshot mode, making it effectively +read-only. + +Note that writes to the device are allowed, and will be seen for +the duration of the guestfs handle, but they are written +to a temporary file which is discarded as soon as the guestfs +handle is closed. We don't currently have any method to enable +changes to be committed, although qemu can support this. + +This is equivalent to the qemu parameter +C<-drive file=filename,snapshot=on,if=...>. + +Note that this call checks for the existence of C. This +stops you from specifying other types of drive which are supported +by qemu such as C and C URLs. To specify those, use +the general C call instead."); ("config", (RErr, [String "qemuparam"; OptString "qemuvalue"]), -1, [], [], @@ -334,7 +474,8 @@ environment variable. Setting C to C restores the default qemu binary."); ("get_qemu", (RConstString "qemu", []), -1, [], - [], + [InitNone, Always, TestRun ( + [["get_qemu"]])], "get the qemu binary", "\ Return the current qemu binary. @@ -354,7 +495,8 @@ C environment variable. Setting C to C restores the default path."); ("get_path", (RConstString "path", []), -1, [], - [], + [InitNone, Always, TestRun ( + [["get_path"]])], "get the search path", "\ Return the current search path. @@ -376,6 +518,10 @@ Setting C to C means I additional options are passed (libguestfs always adds a few of its own)."); ("get_append", (RConstString "append", []), -1, [], + (* This cannot be tested with the current framework. The + * function can return NULL in normal operations, which the + * test framework interprets as an error. + *) [], "get the additional kernel options", "\ @@ -384,6 +530,31 @@ guest kernel command line. If C then no options are added."); + ("set_kernel", (RErr, [String "kernel"]), -1, [FishAlias "kernel"], + [], + "override the normal appliance kernel", + "\ +This function lets you override the ordinary selection +of kernel used in the appliance. + +The default is C unless overridden by setting +C environment variable. + +Setting C to C means the ordinary appliance +kernel is selected by the usual means."); + + ("get_kernel", (RConstString "kernel", []), -1, [], + (* This cannot be tested with the current framework. The + * function can return NULL in normal operations, which the + * test framework interprets as an error. + *) + [], + "get the override appliance kernel", + "\ +Return the override appliance kernel (see C). + +If C then the ordinary appliance kernel is used."); + ("set_autosync", (RErr, [Bool "autosync"]), -1, [FishAlias "autosync"], [], "set autosync mode", @@ -397,7 +568,8 @@ This is disabled by default (except in guestfish where it is enabled by default)."); ("get_autosync", (RBool "autosync", []), -1, [], - [], + [InitNone, Always, TestRun ( + [["get_autosync"]])], "get autosync mode", "\ Get the autosync flag."); @@ -418,7 +590,8 @@ C is defined and set to C<1>."); This returns the verbose messages flag."); ("is_ready", (RBool "ready", []), -1, [], - [], + [InitNone, Always, TestOutputTrue ( + [["is_ready"]])], "is ready to accept commands", "\ This returns true iff this handle is ready to accept commands @@ -427,7 +600,8 @@ This returns true iff this handle is ready to accept commands For more information on states, see L."); ("is_config", (RBool "config", []), -1, [], - [], + [InitNone, Always, TestOutputFalse ( + [["is_config"]])], "is in configuration state", "\ This returns true iff this handle is being configured @@ -436,7 +610,8 @@ This returns true iff this handle is being configured For more information on states, see L."); ("is_launching", (RBool "launching", []), -1, [], - [], + [InitNone, Always, TestOutputFalse ( + [["is_launching"]])], "is launching subprocess", "\ This returns true iff this handle is launching the subprocess @@ -445,7 +620,8 @@ This returns true iff this handle is launching the subprocess For more information on states, see L."); ("is_busy", (RBool "busy", []), -1, [], - [], + [InitNone, Always, TestOutputFalse ( + [["is_busy"]])], "is busy processing a command", "\ This returns true iff this handle is busy processing a command @@ -490,12 +666,88 @@ actions using the low-level API. For more information on states, see L."); + ("set_memsize", (RErr, [Int "memsize"]), -1, [FishAlias "memsize"], + [InitNone, Always, TestOutputInt ( + [["set_memsize"; "500"]; + ["get_memsize"]], 500)], + "set memory allocated to the qemu subprocess", + "\ +This sets the memory size in megabytes allocated to the +qemu subprocess. This only has any effect if called before +C. + +You can also change this by setting the environment +variable C before the handle is +created. + +For more information on the architecture of libguestfs, +see L."); + + ("get_memsize", (RInt "memsize", []), -1, [], + [InitNone, Always, TestOutputIntOp ( + [["get_memsize"]], ">=", 256)], + "get memory allocated to the qemu subprocess", + "\ +This gets the memory size in megabytes allocated to the +qemu subprocess. + +If C was not called +on this handle, and if C was not set, +then this returns the compiled-in default value for memsize. + +For more information on the architecture of libguestfs, +see L."); + + ("get_pid", (RInt "pid", []), -1, [FishAlias "pid"], + [InitNone, Always, TestOutputIntOp ( + [["get_pid"]], ">=", 1)], + "get PID of qemu subprocess", + "\ +Return the process ID of the qemu subprocess. If there is no +qemu subprocess, then this will return an error. + +This is an internal call used for debugging and testing."); + + ("version", (RStruct ("version", "version"), []), -1, [], + [InitNone, Always, TestOutputStruct ( + [["version"]], [CompareWithInt ("major", 1)])], + "get the library version number", + "\ +Return the libguestfs version number that the program is linked +against. + +Note that because of dynamic linking this is not necessarily +the version of libguestfs that you compiled against. You can +compile the program, and then at runtime dynamically link +against a completely different C library. + +This call was added in version C<1.0.58>. In previous +versions of libguestfs there was no way to get the version +number. From C code you can use ELF weak linking tricks to find out if +this symbol exists (if it doesn't, then it's an earlier version). + +The call returns a structure with four elements. The first +three (C, C and C) are numbers and +correspond to the usual version triplet. The fourth element +(C) is a string and is normally empty, but may be +used for distro-specific information. + +To construct the original version string: +C<$major.$minor.$release$extra> + +I Don't use this call to test for availability +of features. Distro backports makes this unreliable."); + ] +(* daemon_functions are any functions which cause some action + * to take place in the daemon. + *) + let daemon_functions = [ ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [], [InitEmpty, Always, TestOutput ( - [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","]; + [["sfdiskM"; "/dev/sda"; ","]; ["mkfs"; "ext2"; "/dev/sda1"]; ["mount"; "/dev/sda1"; "/"]; ["write_file"; "/new"; "new file contents"; "0"]; @@ -549,8 +801,8 @@ Return the contents of the file named C. Note that this function cannot correctly handle binary files (specifically, files containing C<\\0> character which is treated -as end of string). For those you need to use the C -function which has a more complex interface."); +as end of string). For those you need to use the C +or C functions which have a more complex interface."); ("ll", (RString "listing", [String "directory"]), 5, [], [], (* XXX Tricky to test because it depends on the exact format @@ -580,8 +832,8 @@ This command is mostly useful for interactive sessions. Programs should probably use C instead."); ("list_devices", (RStringList "devices", []), 7, [], - [InitEmpty, Always, TestOutputList ( - [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"])], + [InitEmpty, Always, TestOutputListOfDevices ( + [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"; "/dev/sdd"])], "list the block devices", "\ List all the block devices. @@ -589,10 +841,10 @@ List all the block devices. The full block device names are returned, eg. C"); ("list_partitions", (RStringList "partitions", []), 8, [], - [InitBasicFS, Always, TestOutputList ( + [InitBasicFS, Always, TestOutputListOfDevices ( [["list_partitions"]], ["/dev/sda1"]); - InitEmpty, Always, TestOutputList ( - [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"]; + InitEmpty, Always, TestOutputListOfDevices ( + [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"]; ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])], "list the partitions", "\ @@ -604,10 +856,10 @@ This does not return logical volumes. For that you will need to call C."); ("pvs", (RStringList "physvols", []), 9, [], - [InitBasicFSonLVM, Always, TestOutputList ( + [InitBasicFSonLVM, Always, TestOutputListOfDevices ( [["pvs"]], ["/dev/sda1"]); - InitEmpty, Always, TestOutputList ( - [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"]; + InitEmpty, Always, TestOutputListOfDevices ( + [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"]; ["pvcreate"; "/dev/sda1"]; ["pvcreate"; "/dev/sda2"]; ["pvcreate"; "/dev/sda3"]; @@ -626,7 +878,7 @@ See also C."); [InitBasicFSonLVM, Always, TestOutputList ( [["vgs"]], ["VG"]); InitEmpty, Always, TestOutputList ( - [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"]; + [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"]; ["pvcreate"; "/dev/sda1"]; ["pvcreate"; "/dev/sda2"]; ["pvcreate"; "/dev/sda3"]; @@ -647,7 +899,7 @@ See also C."); [InitBasicFSonLVM, Always, TestOutputList ( [["lvs"]], ["/dev/VG/LV"]); InitEmpty, Always, TestOutputList ( - [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"]; + [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"]; ["pvcreate"; "/dev/sda1"]; ["pvcreate"; "/dev/sda2"]; ["pvcreate"; "/dev/sda3"]; @@ -667,21 +919,21 @@ This returns a list of the logical volume device names See also C."); - ("pvs_full", (RPVList "physvols", []), 12, [], + ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [], [], (* XXX how to test? *) "list the LVM physical volumes (PVs)", "\ List all the physical volumes detected. This is the equivalent of the L command. The \"full\" version includes all fields."); - ("vgs_full", (RVGList "volgroups", []), 13, [], + ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [], [], (* XXX how to test? *) "list the LVM volume groups (VGs)", "\ List all the volumes groups detected. This is the equivalent of the L command. The \"full\" version includes all fields."); - ("lvs_full", (RLVList "logvols", []), 14, [], + ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [], [], (* XXX how to test? *) "list the LVM logical volumes (LVs)", "\ @@ -778,7 +1030,7 @@ undefined. On success this returns the number of nodes in C, or C<0> if C evaluates to something which is not a nodeset."); - ("aug_defnode", (RIntBool ("nrnodes", "created"), [String "name"; String "expr"; String "val"]), 18, [], + ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [], [], (* XXX Augeas code needs tests. *) "define an Augeas node", "\ @@ -924,7 +1176,14 @@ Create a directory named C."); ["is_dir"; "/new/foo"]]; InitBasicFS, Always, TestOutputTrue [["mkdir_p"; "/new/foo/bar"]; - ["is_dir"; "/new"]]], + ["is_dir"; "/new"]]; + (* Regression tests for RHBZ#503133: *) + InitBasicFS, Always, TestRun + [["mkdir"; "/new"]; + ["mkdir_p"; "/new"]]; + InitBasicFS, Always, TestLastFail + [["touch"; "/new"]; + ["mkdir_p"; "/new"]]], "create a directory and parents", "\ Create a directory named C, creating any parent directories @@ -992,8 +1251,8 @@ other objects like files. See also C."); ("pvcreate", (RErr, [String "device"]), 39, [], - [InitEmpty, Always, TestOutputList ( - [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"]; + [InitEmpty, Always, TestOutputListOfDevices ( + [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"]; ["pvcreate"; "/dev/sda1"]; ["pvcreate"; "/dev/sda2"]; ["pvcreate"; "/dev/sda3"]; @@ -1006,7 +1265,7 @@ as C."); ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [], [InitEmpty, Always, TestOutputList ( - [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"]; + [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"]; ["pvcreate"; "/dev/sda1"]; ["pvcreate"; "/dev/sda2"]; ["pvcreate"; "/dev/sda3"]; @@ -1020,7 +1279,7 @@ from the non-empty list of physical volumes C."); ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [], [InitEmpty, Always, TestOutputList ( - [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"]; + [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"]; ["pvcreate"; "/dev/sda1"]; ["pvcreate"; "/dev/sda2"]; ["pvcreate"; "/dev/sda3"]; @@ -1041,7 +1300,7 @@ on the volume group C, with C megabytes."); ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [], [InitEmpty, Always, TestOutput ( - [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","]; + [["sfdiskM"; "/dev/sda"; ","]; ["mkfs"; "ext2"; "/dev/sda1"]; ["mount"; "/dev/sda1"; "/"]; ["write_file"; "/new"; "new file contents"; "0"]; @@ -1076,7 +1335,9 @@ information refer to the L manpage. To create a single partition occupying the whole disk, you would pass C as a single element list, when the single element being -the string C<,> (comma)."); +the string C<,> (comma). + +See also: C, C"); ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning], [InitBasicFS, Always, TestOutput ( @@ -1113,13 +1374,13 @@ We hope to resolve this bug in a future version. In the meantime use C."); ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"], - [InitEmpty, Always, TestOutputList ( - [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","]; + [InitEmpty, Always, TestOutputListOfDevices ( + [["sfdiskM"; "/dev/sda"; ","]; ["mkfs"; "ext2"; "/dev/sda1"]; ["mount"; "/dev/sda1"; "/"]; ["mounts"]], ["/dev/sda1"]); InitEmpty, Always, TestOutputList ( - [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","]; + [["sfdiskM"; "/dev/sda"; ","]; ["mkfs"; "ext2"; "/dev/sda1"]; ["mount"; "/dev/sda1"; "/"]; ["umount"; "/"]; @@ -1131,14 +1392,16 @@ specified either by its mountpoint (path) or the device which contains the filesystem."); ("mounts", (RStringList "devices", []), 46, [], - [InitBasicFS, Always, TestOutputList ( + [InitBasicFS, Always, TestOutputListOfDevices ( [["mounts"]], ["/dev/sda1"])], "show mounted filesystems", "\ This returns the list of currently mounted filesystems. It returns the list of devices (eg. C, C). -Some internal mounts are not shown."); +Some internal mounts are not shown. + +See also: C"); ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"], [InitBasicFS, Always, TestOutputList ( @@ -1146,7 +1409,7 @@ Some internal mounts are not shown."); ["mounts"]], []); (* check that umount_all can unmount nested mounts correctly: *) InitEmpty, Always, TestOutputList ( - [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"]; + [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"]; ["mkfs"; "ext2"; "/dev/sda1"]; ["mkfs"; "ext2"; "/dev/sda2"]; ["mkfs"; "ext2"; "/dev/sda3"]; @@ -1191,53 +1454,53 @@ particular that the filename is not prepended to the output (the C<-b> option)."); ("command", (RString "output", [StringList "arguments"]), 50, [ProtocolLimitWarning], - [InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput ( + [InitBasicFS, Always, TestOutput ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command"; "/test-command 1"]], "Result1"); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput ( + InitBasicFS, Always, TestOutput ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command"; "/test-command 2"]], "Result2\n"); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput ( + InitBasicFS, Always, TestOutput ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command"; "/test-command 3"]], "\nResult3"); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput ( + InitBasicFS, Always, TestOutput ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command"; "/test-command 4"]], "\nResult4\n"); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput ( + InitBasicFS, Always, TestOutput ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command"; "/test-command 5"]], "\nResult5\n\n"); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput ( + InitBasicFS, Always, TestOutput ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command"; "/test-command 6"]], "\n\nResult6\n\n"); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput ( + InitBasicFS, Always, TestOutput ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command"; "/test-command 7"]], ""); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput ( + InitBasicFS, Always, TestOutput ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command"; "/test-command 8"]], "\n"); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput ( + InitBasicFS, Always, TestOutput ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command"; "/test-command 9"]], "\n\n"); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput ( + InitBasicFS, Always, TestOutput ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command"; "/test-command 10"]], "Result10-1\nResult10-2\n"); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutput ( + InitBasicFS, Always, TestOutput ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command"; "/test-command 11"]], "Result11-1\nResult11-2"); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestLastFail ( + InitBasicFS, Always, TestLastFail ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command"; "/test-command"]])], "run a command from the guest filesystem", "\ @@ -1249,7 +1512,9 @@ or compatible processor architecture). The single parameter is an argv-style list of arguments. The first element is the name of the program to run. Subsequent elements are parameters. The list must be -non-empty (ie. must contain a program name). +non-empty (ie. must contain a program name). Note that +the command runs directly, and is I invoked via +the shell (see C). The return value is anything printed to I by the command. @@ -1270,56 +1535,58 @@ all filesystems that are needed are mounted at the right locations."); ("command_lines", (RStringList "lines", [StringList "arguments"]), 51, [ProtocolLimitWarning], - [InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList ( + [InitBasicFS, Always, TestOutputList ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command_lines"; "/test-command 1"]], ["Result1"]); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList ( + InitBasicFS, Always, TestOutputList ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command_lines"; "/test-command 2"]], ["Result2"]); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList ( + InitBasicFS, Always, TestOutputList ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command_lines"; "/test-command 3"]], ["";"Result3"]); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList ( + InitBasicFS, Always, TestOutputList ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command_lines"; "/test-command 4"]], ["";"Result4"]); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList ( + InitBasicFS, Always, TestOutputList ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command_lines"; "/test-command 5"]], ["";"Result5";""]); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList ( + InitBasicFS, Always, TestOutputList ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command_lines"; "/test-command 6"]], ["";"";"Result6";""]); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList ( + InitBasicFS, Always, TestOutputList ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command_lines"; "/test-command 7"]], []); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList ( + InitBasicFS, Always, TestOutputList ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command_lines"; "/test-command 8"]], [""]); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList ( + InitBasicFS, Always, TestOutputList ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command_lines"; "/test-command 9"]], ["";""]); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList ( + InitBasicFS, Always, TestOutputList ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command_lines"; "/test-command 10"]], ["Result10-1";"Result10-2"]); - InitBasicFS, Unless (env_is_true "SKIP_TEST_COMMAND"), TestOutputList ( + InitBasicFS, Always, TestOutputList ( [["upload"; "test-command"; "/test-command"]; - ["chmod"; "493"; "/test-command"]; + ["chmod"; "0o755"; "/test-command"]; ["command_lines"; "/test-command 11"]], ["Result11-1";"Result11-2"])], "run a command, returning lines", "\ This is the same as C, but splits the -result into a list of lines."); +result into a list of lines. + +See also: C"); - ("stat", (RStat "statbuf", [String "path"]), 52, [], + ("stat", (RStruct ("statbuf", "stat"), [String "path"]), 52, [], [InitBasicFS, Always, TestOutputStruct ( [["touch"; "/new"]; ["stat"; "/new"]], [CompareWithInt ("size", 0)])], @@ -1329,7 +1596,7 @@ Returns file information for the given C. This is the same as the C system call."); - ("lstat", (RStat "statbuf", [String "path"]), 53, [], + ("lstat", (RStruct ("statbuf", "stat"), [String "path"]), 53, [], [InitBasicFS, Always, TestOutputStruct ( [["touch"; "/new"]; ["lstat"; "/new"]], [CompareWithInt ("size", 0)])], @@ -1343,10 +1610,9 @@ refers to. This is the same as the C system call."); - ("statvfs", (RStatVFS "statbuf", [String "path"]), 54, [], + ("statvfs", (RStruct ("statbuf", "statvfs"), [String "path"]), 54, [], [InitBasicFS, Always, TestOutputStruct ( - [["statvfs"; "/"]], [CompareWithInt ("bfree", 487702); - CompareWithInt ("blocks", 490020); + [["statvfs"; "/"]], [CompareWithInt ("namemax", 255); CompareWithInt ("bsize", 1024)])], "get file system statistics", "\ @@ -1482,8 +1748,8 @@ This uses the L command."); ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [], [InitBasicFS, Always, TestOutput ( (* Pick a file from cwd which isn't likely to change. *) - [["upload"; "COPYING.LIB"; "/COPYING.LIB"]; - ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")], + [["upload"; "../COPYING.LIB"; "/COPYING.LIB"]; + ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")], "upload a file from the local machine", "\ Upload local file C to C on the @@ -1496,10 +1762,10 @@ See also C."); ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [], [InitBasicFS, Always, TestOutput ( (* Pick a file from cwd which isn't likely to change. *) - [["upload"; "COPYING.LIB"; "/COPYING.LIB"]; - ["download"; "/COPYING.LIB"; "testdownload.tmp"]; - ["upload"; "testdownload.tmp"; "/upload"]; - ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")], + [["upload"; "../COPYING.LIB"; "/COPYING.LIB"]; + ["download"; "/COPYING.LIB"; "testdownload.tmp"]; + ["upload"; "testdownload.tmp"; "/upload"]; + ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")], "download a file to the local machine", "\ Download file C and save it as C @@ -1532,7 +1798,13 @@ See also C, C."); ["checksum"; "sha384"; "/new"]], "109bb6b5b6d5547c1ce03c7a8bd7d8f80c1cb0957f50c4f7fda04692079917e4f9cad52b878f3d8234e1a170b154b72d"); InitBasicFS, Always, TestOutput ( [["write_file"; "/new"; "test\n"; "0"]; - ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123")], + ["checksum"; "sha512"; "/new"]], "0e3e75234abc68f4378a86b3f4b32a198ba301845b0cd6e50106e874345700cc6663a86c1ea125dc5e92be17c98f9a0f85ca9d5f595db2012f7cc3571945c123"); + InitBasicFS, Always, TestOutput ( + (* RHEL 5 thinks this is an HFS+ filesystem unless we give + * the type explicitly. + *) + [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"]; + ["checksum"; "md5"; "/known-3"]], "46d6ca27ee07cdc6fa99c2e138cc522c")], "compute MD5, SHAx or CRC checksum of file", "\ This call computes the MD5, SHAx or CRC checksum of the @@ -1578,7 +1850,7 @@ The checksum is returned as a printable string."); ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [], [InitBasicFS, Always, TestOutput ( - [["tar_in"; "images/helloworld.tar"; "/"]; + [["tar_in"; "../images/helloworld.tar"; "/"]; ["cat"; "/hello"]], "hello\n")], "unpack tarfile to directory", "\ @@ -1598,7 +1870,7 @@ To download a compressed tarball, use C."); ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [], [InitBasicFS, Always, TestOutput ( - [["tgz_in"; "images/helloworld.tar.gz"; "/"]; + [["tgz_in"; "../images/helloworld.tar.gz"; "/"]; ["cat"; "/hello"]], "hello\n")], "unpack compressed tarball to directory", "\ @@ -1661,22 +1933,25 @@ to find out what you can do."); ("lvremove", (RErr, [String "device"]), 77, [], [InitEmpty, Always, TestOutputList ( - [["pvcreate"; "/dev/sda"]; - ["vgcreate"; "VG"; "/dev/sda"]; + [["sfdiskM"; "/dev/sda"; ","]; + ["pvcreate"; "/dev/sda1"]; + ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; ["lvcreate"; "LV2"; "VG"; "50"]; ["lvremove"; "/dev/VG/LV1"]; ["lvs"]], ["/dev/VG/LV2"]); InitEmpty, Always, TestOutputList ( - [["pvcreate"; "/dev/sda"]; - ["vgcreate"; "VG"; "/dev/sda"]; + [["sfdiskM"; "/dev/sda"; ","]; + ["pvcreate"; "/dev/sda1"]; + ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; ["lvcreate"; "LV2"; "VG"; "50"]; ["lvremove"; "/dev/VG"]; ["lvs"]], []); InitEmpty, Always, TestOutputList ( - [["pvcreate"; "/dev/sda"]; - ["vgcreate"; "VG"; "/dev/sda"]; + [["sfdiskM"; "/dev/sda"; ","]; + ["pvcreate"; "/dev/sda1"]; + ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; ["lvcreate"; "LV2"; "VG"; "50"]; ["lvremove"; "/dev/VG"]; @@ -1691,15 +1966,17 @@ the VG name, C."); ("vgremove", (RErr, [String "vgname"]), 78, [], [InitEmpty, Always, TestOutputList ( - [["pvcreate"; "/dev/sda"]; - ["vgcreate"; "VG"; "/dev/sda"]; + [["sfdiskM"; "/dev/sda"; ","]; + ["pvcreate"; "/dev/sda1"]; + ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; ["lvcreate"; "LV2"; "VG"; "50"]; ["vgremove"; "VG"]; ["lvs"]], []); InitEmpty, Always, TestOutputList ( - [["pvcreate"; "/dev/sda"]; - ["vgcreate"; "VG"; "/dev/sda"]; + [["sfdiskM"; "/dev/sda"; ","]; + ["pvcreate"; "/dev/sda1"]; + ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; ["lvcreate"; "LV2"; "VG"; "50"]; ["vgremove"; "VG"]; @@ -1712,29 +1989,32 @@ This also forcibly removes all logical volumes in the volume group (if any)."); ("pvremove", (RErr, [String "device"]), 79, [], - [InitEmpty, Always, TestOutputList ( - [["pvcreate"; "/dev/sda"]; - ["vgcreate"; "VG"; "/dev/sda"]; + [InitEmpty, Always, TestOutputListOfDevices ( + [["sfdiskM"; "/dev/sda"; ","]; + ["pvcreate"; "/dev/sda1"]; + ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; ["lvcreate"; "LV2"; "VG"; "50"]; ["vgremove"; "VG"]; - ["pvremove"; "/dev/sda"]; + ["pvremove"; "/dev/sda1"]; ["lvs"]], []); - InitEmpty, Always, TestOutputList ( - [["pvcreate"; "/dev/sda"]; - ["vgcreate"; "VG"; "/dev/sda"]; + InitEmpty, Always, TestOutputListOfDevices ( + [["sfdiskM"; "/dev/sda"; ","]; + ["pvcreate"; "/dev/sda1"]; + ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; ["lvcreate"; "LV2"; "VG"; "50"]; ["vgremove"; "VG"]; - ["pvremove"; "/dev/sda"]; + ["pvremove"; "/dev/sda1"]; ["vgs"]], []); - InitEmpty, Always, TestOutputList ( - [["pvcreate"; "/dev/sda"]; - ["vgcreate"; "VG"; "/dev/sda"]; + InitEmpty, Always, TestOutputListOfDevices ( + [["sfdiskM"; "/dev/sda"; ","]; + ["pvcreate"; "/dev/sda1"]; + ["vgcreate"; "VG"; "/dev/sda1"]; ["lvcreate"; "LV1"; "VG"; "50"]; ["lvcreate"; "LV2"; "VG"; "50"]; ["vgremove"; "VG"]; - ["pvremove"; "/dev/sda"]; + ["pvremove"; "/dev/sda1"]; ["pvs"]], [])], "remove an LVM physical volume", "\ @@ -1843,10 +2123,15 @@ This command writes zeroes over the first few blocks of C. How many blocks are zeroed isn't specified (but it's I enough to securely wipe the device). It should be sufficient to remove -any partition tables, filesystem superblocks and so on."); +any partition tables, filesystem superblocks and so on. + +See also: C."); ("grub_install", (RErr, [String "root"; String "device"]), 86, [], - [InitBasicFS, Always, TestOutputTrue ( + (* Test disabled because grub-install incompatible with virtio-blk driver. + * See also: https://bugzilla.redhat.com/show_bug.cgi?id=479760 + *) + [InitBasicFS, Disabled, TestOutputTrue ( [["grub_install"; "/"; "/dev/sda1"]; ["is_dir"; "/boot"]])], "install GRUB", @@ -1990,7 +2275,13 @@ The returned strings are transcoded to UTF-8."); ("hexdump", (RString "dump", [String "path"]), 96, [ProtocolLimitWarning], [InitBasicFS, Always, TestOutput ( [["write_file"; "/new"; "hello\nworld\n"; "12"]; - ["hexdump"; "/new"]], "00000000 68 65 6c 6c 6f 0a 77 6f 72 6c 64 0a |hello.world.|\n0000000c\n")], + ["hexdump"; "/new"]], "00000000 68 65 6c 6c 6f 0a 77 6f 72 6c 64 0a |hello.world.|\n0000000c\n"); + (* Test for RHBZ#501888c2 regression which caused large hexdump + * commands to segfault. + *) + InitBasicFS, Always, TestRun ( + [["mount_vfs"; "ro"; "squashfs"; "/dev/sdd"; "/"]; + ["hexdump"; "/100krandom"]])], "dump a file in hexadecimal", "\ This runs C on the given C. The result is @@ -1998,7 +2289,7 @@ the human-readable, canonical hex dump of the file."); ("zerofree", (RErr, [String "device"]), 97, [], [InitNone, Always, TestOutput ( - [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","]; + [["sfdiskM"; "/dev/sda"; ","]; ["mkfs"; "ext3"; "/dev/sda1"]; ["mount"; "/dev/sda1"; "/"]; ["write_file"; "/new"; "test file"; "0"]; @@ -2019,216 +2310,1054 @@ mounted. It is possible that using this program can damage the filesystem or data on the filesystem."); -] + ("pvresize", (RErr, [String "device"]), 98, [], + [], + "resize an LVM physical volume", + "\ +This resizes (expands or shrinks) an existing LVM physical +volume to match the new size of the underlying device."); -let all_functions = non_daemon_functions @ daemon_functions + ("sfdisk_N", (RErr, [String "device"; Int "partnum"; + Int "cyls"; Int "heads"; Int "sectors"; + String "line"]), 99, [DangerWillRobinson], + [], + "modify a single partition on a block device", + "\ +This runs L option to modify just the single +partition C (note: C counts from 1). -(* In some places we want the functions to be displayed sorted - * alphabetically, so this is useful: - *) -let all_functions_sorted = - List.sort (fun (n1,_,_,_,_,_,_) (n2,_,_,_,_,_,_) -> - compare n1 n2) all_functions +For other parameters, see C. You should usually +pass C<0> for the cyls/heads/sectors parameters."); -(* Column names and types from LVM PVs/VGs/LVs. *) -let pv_cols = [ - "pv_name", `String; - "pv_uuid", `UUID; - "pv_fmt", `String; - "pv_size", `Bytes; - "dev_size", `Bytes; - "pv_free", `Bytes; - "pv_used", `Bytes; - "pv_attr", `String (* XXX *); - "pv_pe_count", `Int; - "pv_pe_alloc_count", `Int; - "pv_tags", `String; - "pe_start", `Bytes; - "pv_mda_count", `Int; - "pv_mda_free", `Bytes; -(* Not in Fedora 10: - "pv_mda_size", `Bytes; -*) -] -let vg_cols = [ - "vg_name", `String; - "vg_uuid", `UUID; - "vg_fmt", `String; - "vg_attr", `String (* XXX *); - "vg_size", `Bytes; - "vg_free", `Bytes; - "vg_sysid", `String; - "vg_extent_size", `Bytes; - "vg_extent_count", `Int; - "vg_free_count", `Int; - "max_lv", `Int; - "max_pv", `Int; - "pv_count", `Int; - "lv_count", `Int; - "snap_count", `Int; - "vg_seqno", `Int; - "vg_tags", `String; - "vg_mda_count", `Int; - "vg_mda_free", `Bytes; -(* Not in Fedora 10: - "vg_mda_size", `Bytes; -*) -] -let lv_cols = [ - "lv_name", `String; - "lv_uuid", `UUID; - "lv_attr", `String (* XXX *); - "lv_major", `Int; - "lv_minor", `Int; - "lv_kernel_major", `Int; - "lv_kernel_minor", `Int; - "lv_size", `Bytes; - "seg_count", `Int; - "origin", `String; - "snap_percent", `OptPercent; - "copy_percent", `OptPercent; - "move_pv", `String; - "lv_tags", `String; - "mirror_log", `String; - "modules", `String; -] + ("sfdisk_l", (RString "partitions", [String "device"]), 100, [], + [], + "display the partition table", + "\ +This displays the partition table on C, in the +human-readable output of the L command. It is +not intended to be parsed."); -(* Column names and types from stat structures. - * NB. Can't use things like 'st_atime' because glibc header files - * define some of these as macros. Ugh. - *) -let stat_cols = [ - "dev", `Int; - "ino", `Int; - "mode", `Int; - "nlink", `Int; - "uid", `Int; - "gid", `Int; - "rdev", `Int; - "size", `Int; - "blksize", `Int; - "blocks", `Int; - "atime", `Int; - "mtime", `Int; - "ctime", `Int; -] -let statvfs_cols = [ - "bsize", `Int; - "frsize", `Int; - "blocks", `Int; - "bfree", `Int; - "bavail", `Int; - "files", `Int; - "ffree", `Int; - "favail", `Int; - "fsid", `Int; - "flag", `Int; - "namemax", `Int; -] + ("sfdisk_kernel_geometry", (RString "partitions", [String "device"]), 101, [], + [], + "display the kernel geometry", + "\ +This displays the kernel's idea of the geometry of C. -(* Useful functions. - * Note we don't want to use any external OCaml libraries which - * makes this a bit harder than it should be. - *) -let failwithf fs = ksprintf failwith fs +The result is in human-readable format, and not designed to +be parsed."); -let replace_char s c1 c2 = - let s2 = String.copy s in - let r = ref false in - for i = 0 to String.length s2 - 1 do - if String.unsafe_get s2 i = c1 then ( - String.unsafe_set s2 i c2; - r := true - ) - done; - if not !r then s else s2 + ("sfdisk_disk_geometry", (RString "partitions", [String "device"]), 102, [], + [], + "display the disk geometry from the partition table", + "\ +This displays the disk geometry of C read from the +partition table. Especially in the case where the underlying +block device has been resized, this can be different from the +kernel's idea of the geometry (see C). -let isspace c = - c = ' ' - (* || c = '\f' *) || c = '\n' || c = '\r' || c = '\t' (* || c = '\v' *) +The result is in human-readable format, and not designed to +be parsed."); -let triml ?(test = isspace) str = - let i = ref 0 in - let n = ref (String.length str) in - while !n > 0 && test str.[!i]; do - decr n; - incr i - done; - if !i = 0 then str - else String.sub str !i !n + ("vg_activate_all", (RErr, [Bool "activate"]), 103, [], + [], + "activate or deactivate all volume groups", + "\ +This command activates or (if C is false) deactivates +all logical volumes in all volume groups. +If activated, then they are made known to the +kernel, ie. they appear as C devices. If deactivated, +then those devices disappear. -let trimr ?(test = isspace) str = - let n = ref (String.length str) in - while !n > 0 && test str.[!n-1]; do - decr n - done; - if !n = String.length str then str - else String.sub str 0 !n +This command is the same as running C"); -let trim ?(test = isspace) str = - trimr ~test (triml ~test str) + ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [], + [], + "activate or deactivate some volume groups", + "\ +This command activates or (if C is false) deactivates +all logical volumes in the listed volume groups C. +If activated, then they are made known to the +kernel, ie. they appear as C devices. If deactivated, +then those devices disappear. -let rec find s sub = - let len = String.length s in - let sublen = String.length sub in - let rec loop i = - if i <= len-sublen then ( - let rec loop2 j = - if j < sublen then ( - if s.[i+j] = sub.[j] then loop2 (j+1) - else -1 - ) else - i (* found *) - in - let r = loop2 0 in - if r = -1 then loop (i+1) else r - ) else - -1 (* not found *) - in - loop 0 +This command is the same as running C -let rec replace_str s s1 s2 = - let len = String.length s in - let sublen = String.length s1 in - let i = find s s1 in - if i = -1 then s - else ( - let s' = String.sub s 0 i in - let s'' = String.sub s (i+sublen) (len-i-sublen) in - s' ^ s2 ^ replace_str s'' s1 s2 - ) +Note that if C is an empty list then B volume groups +are activated or deactivated."); -let rec string_split sep str = - let len = String.length str in - let seplen = String.length sep in - let i = find str sep in - if i = -1 then [str] - else ( - let s' = String.sub str 0 i in - let s'' = String.sub str (i+seplen) (len-i-seplen) in - s' :: string_split sep s'' - ) + ("lvresize", (RErr, [String "device"; Int "mbytes"]), 105, [], + [InitNone, Always, TestOutput ( + [["sfdiskM"; "/dev/sda"; ","]; + ["pvcreate"; "/dev/sda1"]; + ["vgcreate"; "VG"; "/dev/sda1"]; + ["lvcreate"; "LV"; "VG"; "10"]; + ["mkfs"; "ext2"; "/dev/VG/LV"]; + ["mount"; "/dev/VG/LV"; "/"]; + ["write_file"; "/new"; "test content"; "0"]; + ["umount"; "/"]; + ["lvresize"; "/dev/VG/LV"; "20"]; + ["e2fsck_f"; "/dev/VG/LV"]; + ["resize2fs"; "/dev/VG/LV"]; + ["mount"; "/dev/VG/LV"; "/"]; + ["cat"; "/new"]], "test content")], + "resize an LVM logical volume", + "\ +This resizes (expands or shrinks) an existing LVM logical +volume to C. When reducing, data in the reduced part +is lost."); -let files_equal n1 n2 = - let cmd = sprintf "cmp -s %s %s" (Filename.quote n1) (Filename.quote n2) in - match Sys.command cmd with - | 0 -> true - | 1 -> false - | i -> failwithf "%s: failed with error code %d" cmd i + ("resize2fs", (RErr, [String "device"]), 106, [], + [], (* lvresize tests this *) + "resize an ext2/ext3 filesystem", + "\ +This resizes an ext2 or ext3 filesystem to match the size of +the underlying device. -let rec find_map f = function - | [] -> raise Not_found - | x :: xs -> - match f x with - | Some y -> y - | None -> find_map f xs +I It is sometimes required that you run C +on the C before calling this command. For unknown reasons +C sometimes gives an error about this and sometimes not. +In any case, it is always safe to call C before +calling this function."); -let iteri f xs = - let rec loop i = function - | [] -> () - | x :: xs -> f i x; loop (i+1) xs - in - loop 0 xs + ("find", (RStringList "names", [String "directory"]), 107, [], + [InitBasicFS, Always, TestOutputList ( + [["find"; "/"]], ["lost+found"]); + InitBasicFS, Always, TestOutputList ( + [["touch"; "/a"]; + ["mkdir"; "/b"]; + ["touch"; "/b/c"]; + ["find"; "/"]], ["a"; "b"; "b/c"; "lost+found"]); + InitBasicFS, Always, TestOutputList ( + [["mkdir_p"; "/a/b/c"]; + ["touch"; "/a/b/c/d"]; + ["find"; "/a/b/"]], ["c"; "c/d"])], + "find all files and directories", + "\ +This command lists out all files and directories, recursively, +starting at C. It is essentially equivalent to +running the shell command C but some +post-processing happens on the output, described below. + +This returns a list of strings I. Thus +if the directory structure was: + + /tmp/a + /tmp/b + /tmp/c/d + +then the returned list from C C would be +4 elements: + + a + b + c + c/d + +If C is not a directory, then this command returns +an error. + +The returned list is sorted."); + + ("e2fsck_f", (RErr, [String "device"]), 108, [], + [], (* lvresize tests this *) + "check an ext2/ext3 filesystem", + "\ +This runs C, ie. runs the ext2/ext3 +filesystem checker on C, noninteractively (C<-p>), +even if the filesystem appears to be clean (C<-f>). + +This command is only needed because of C +(q.v.). Normally you should use C."); + + ("sleep", (RErr, [Int "secs"]), 109, [], + [InitNone, Always, TestRun ( + [["sleep"; "1"]])], + "sleep for some seconds", + "\ +Sleep for C seconds."); + + ("ntfs_3g_probe", (RInt "status", [Bool "rw"; String "device"]), 110, [], + [InitNone, Always, TestOutputInt ( + [["sfdiskM"; "/dev/sda"; ","]; + ["mkfs"; "ntfs"; "/dev/sda1"]; + ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 0); + InitNone, Always, TestOutputInt ( + [["sfdiskM"; "/dev/sda"; ","]; + ["mkfs"; "ext2"; "/dev/sda1"]; + ["ntfs_3g_probe"; "true"; "/dev/sda1"]], 12)], + "probe NTFS volume", + "\ +This command runs the L command which probes +an NTFS C for mountability. (Not all NTFS volumes can +be mounted read-write, and some cannot be mounted at all). + +C is a boolean flag. Set it to true if you want to test +if the volume can be mounted read-write. Set it to false if +you want to test if the volume can be mounted read-only. + +The return value is an integer which C<0> if the operation +would succeed, or some non-zero value documented in the +L manual page."); + + ("sh", (RString "output", [String "command"]), 111, [], + [], (* XXX needs tests *) + "run a command via the shell", + "\ +This call runs a command from the guest filesystem via the +guest's C. + +This is like C, but passes the command to: + + /bin/sh -c \"command\" + +Depending on the guest's shell, this usually results in +wildcards being expanded, shell expressions being interpolated +and so on. + +All the provisos about C apply to this call."); + + ("sh_lines", (RStringList "lines", [String "command"]), 112, [], + [], (* XXX needs tests *) + "run a command via the shell returning lines", + "\ +This is the same as C, but splits the result +into a list of lines. + +See also: C"); + + ("glob_expand", (RStringList "paths", [String "pattern"]), 113, [], + [InitBasicFS, Always, TestOutputList ( + [["mkdir_p"; "/a/b/c"]; + ["touch"; "/a/b/c/d"]; + ["touch"; "/a/b/c/e"]; + ["glob_expand"; "/a/b/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]); + InitBasicFS, Always, TestOutputList ( + [["mkdir_p"; "/a/b/c"]; + ["touch"; "/a/b/c/d"]; + ["touch"; "/a/b/c/e"]; + ["glob_expand"; "/a/*/c/*"]], ["/a/b/c/d"; "/a/b/c/e"]); + InitBasicFS, Always, TestOutputList ( + [["mkdir_p"; "/a/b/c"]; + ["touch"; "/a/b/c/d"]; + ["touch"; "/a/b/c/e"]; + ["glob_expand"; "/a/*/x/*"]], [])], + "expand a wildcard path", + "\ +This command searches for all the pathnames matching +C according to the wildcard expansion rules +used by the shell. + +If no paths match, then this returns an empty list +(note: not an error). + +It is just a wrapper around the C L function +with flags C. +See that manual page for more details."); + + ("scrub_device", (RErr, [String "device"]), 114, [DangerWillRobinson], + [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *) + [["scrub_device"; "/dev/sdc"]])], + "scrub (securely wipe) a device", + "\ +This command writes patterns over C to make data retrieval +more difficult. + +It is an interface to the L program. See that +manual page for more details."); + + ("scrub_file", (RErr, [String "file"]), 115, [], + [InitBasicFS, Always, TestRun ( + [["write_file"; "/file"; "content"; "0"]; + ["scrub_file"; "/file"]])], + "scrub (securely wipe) a file", + "\ +This command writes patterns over a file to make data retrieval +more difficult. + +The file is I after scrubbing. + +It is an interface to the L program. See that +manual page for more details."); + + ("scrub_freespace", (RErr, [String "dir"]), 116, [], + [], (* XXX needs testing *) + "scrub (securely wipe) free space", + "\ +This command creates the directory C and then fills it +with files until the filesystem is full, and scrubs the files +as for C, and deletes them. +The intention is to scrub any free space on the partition +containing C. + +It is an interface to the L program. See that +manual page for more details."); + + ("mkdtemp", (RString "dir", [String "template"]), 117, [], + [InitBasicFS, Always, TestRun ( + [["mkdir"; "/tmp"]; + ["mkdtemp"; "/tmp/tmpXXXXXX"]])], + "create a temporary directory", + "\ +This command creates a temporary directory. The +C