X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=src%2Fgenerator.ml;h=b274411bd753373e0f9bfaac045dbfc4bc1be792;hp=2b833c11fe72267b3e601287e9e367468703c35a;hb=c3a68961859a617f7c574c528d0f8ac1fdbb53e1;hpb=30752ac7ca042f533b8d0c4c6144400a8532b154 diff --git a/src/generator.ml b/src/generator.ml index 2b833c1..b274411 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -182,11 +182,16 @@ type flags = | DangerWillRobinson (* flags particularly dangerous commands *) | FishAlias of string (* provide an alias for this cmd in guestfish *) | FishAction of string (* call this function in guestfish *) + | FishOutput of fish_output_t (* how to display output in guestfish *) | NotInFish (* do not export via guestfish *) | NotInDocs (* do not add this function to documentation *) | DeprecatedBy of string (* function is deprecated, use .. instead *) | Optional of string (* function is part of an optional group *) +and fish_output_t = + | FishOutputOctal (* for int return, print in octal *) + | FishOutputHexadecimal (* for int return, print in hex *) + (* 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, @@ -1238,7 +1243,12 @@ matches exactly one node, the C is returned."); [], (* XXX Augeas code needs tests. *) "set Augeas path to value", "\ -Set the value associated with C to C."); +Set the value associated with C to C. + +In the Augeas API, it is possible to clear a node by setting +the value to NULL. Due to an oversight in the libguestfs API +you cannot do that with this call. Instead you must use the +C call."); ("aug_insert", (RErr, [String "augpath"; String "label"; Bool "before"]), 21, [Optional "augeas"], [], (* XXX Augeas code needs tests. *) @@ -1380,7 +1390,9 @@ numeric modes are supported. I: When using this command from guestfish, C by default would be decimal, unless you prefix it with -C<0> to get octal, ie. use C<0700> not C<700>."); +C<0> to get octal, ie. use C<0700> not C<700>. + +The mode actually set is affected by the umask."); ("chown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 35, [], [], (* XXX Need stat command to test *) @@ -1473,9 +1485,9 @@ from the non-empty list of physical volumes C."); ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])], - "create an LVM volume group", + "create an LVM logical volume", "\ -This creates an LVM volume group called C +This creates an LVM logical volume called C on the volume group C, with C megabytes."); ("mkfs", (RErr, [String "fstype"; Device "device"]), 42, [], @@ -2016,7 +2028,7 @@ Compute the SHA512 hash (using the C program). The checksum is returned as a printable string."); - ("tar_in", (RErr, [FileIn "tarfile"; String "directory"]), 69, [], + ("tar_in", (RErr, [FileIn "tarfile"; Pathname "directory"]), 69, [], [InitBasicFS, Always, TestOutput ( [["tar_in"; "../images/helloworld.tar"; "/"]; ["cat"; "/hello"]], "hello\n")], @@ -2038,7 +2050,7 @@ it to local file C. To download a compressed tarball, use C or C."); - ("tgz_in", (RErr, [FileIn "tarball"; String "directory"]), 71, [], + ("tgz_in", (RErr, [FileIn "tarball"; Pathname "directory"]), 71, [], [InitBasicFS, Always, TestOutput ( [["tgz_in"; "../images/helloworld.tar.gz"; "/"]; ["cat"; "/hello"]], "hello\n")], @@ -2245,7 +2257,7 @@ to return the existing UUID of a filesystem."); This returns the ext2/3/4 filesystem UUID of the filesystem on C."); - ("fsck", (RInt "status", [String "fstype"; Device "device"]), 84, [], + ("fsck", (RInt "status", [String "fstype"; Device "device"]), 84, [FishOutput FishOutputHexadecimal], [InitBasicFS, Always, TestOutputInt ( [["umount"; "/dev/sda1"]; ["fsck"; "ext2"; "/dev/sda1"]], 0); @@ -2975,7 +2987,9 @@ named pipes (FIFOs). The C parameter should be the mode, using the standard constants. C and C are the device major and minor numbers, only used when creating block -and character special devices."); +and character special devices. + +The mode actually set is affected by the umask."); ("mkfifo", (RErr, [Int "mode"; Pathname "path"]), 134, [Optional "mknod"], [InitBasicFS, Always, TestOutputStruct ( @@ -2985,7 +2999,9 @@ and character special devices."); "\ This call creates a FIFO (named pipe) called C with mode C. It is just a convenient wrapper around -C."); +C. + +The mode actually set is affected by the umask."); ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 135, [Optional "mknod"], [InitBasicFS, Always, TestOutputStruct ( @@ -2995,7 +3011,9 @@ C."); "\ This call creates a block device node called C with mode C and device major/minor C and C. -It is just a convenient wrapper around C."); +It is just a convenient wrapper around C. + +The mode actually set is affected by the umask."); ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 136, [Optional "mknod"], [InitBasicFS, Always, TestOutputStruct ( @@ -3005,12 +3023,13 @@ It is just a convenient wrapper around C."); "\ This call creates a char device node called C with mode C and device major/minor C and C. -It is just a convenient wrapper around C."); +It is just a convenient wrapper around C. - ("umask", (RInt "oldmask", [Int "mask"]), 137, [], - [], (* XXX umask is one of those stateful things that we should - * reset between each test. - *) +The mode actually set is affected by the umask."); + + ("umask", (RInt "oldmask", [Int "mask"]), 137, [FishOutput FishOutputOctal], + [InitEmpty, Always, TestOutputInt ( + [["umask"; "0o22"]], 0o22)], "set file mode creation mask (umask)", "\ This function sets the mask used for creating new files and @@ -3025,7 +3044,8 @@ The default umask is C<022>. This is important because it means that directories and device nodes will be created with C<0644> or C<0755> mode even if you specify C<0777>. -See also L, C, C. +See also C, +L, C, C. This call returns the previous umask."); @@ -3869,7 +3889,13 @@ C<*secs> field is ignored in this case)."); "create a directory with a particular mode", "\ This command creates a directory, setting the initial permissions -of the directory to C. See also C."); +of the directory to C. + +For common Linux filesystems, the actual mode which is set will +be C. Non-native-Linux filesystems may +interpret the mode in other ways. + +See also C, C"); ("lchown", (RErr, [Int "owner"; Int "group"; Pathname "path"]), 203, [], [], (* XXX *) @@ -4356,7 +4382,7 @@ This command writes zeroes over the entire C. Compare with C which just zeroes the first few blocks of a device."); - ("txz_in", (RErr, [FileIn "tarball"; String "directory"]), 229, [], + ("txz_in", (RErr, [FileIn "tarball"; Pathname "directory"]), 229, [], [InitBasicFS, Always, TestOutput ( [["txz_in"; "../images/helloworld.tar.xz"; "/"]; ["cat"; "/hello"]], "hello\n")], @@ -4388,6 +4414,128 @@ See also L."); This rescans all block devices and rebuilds the list of LVM physical volumes, volume groups and logical volumes."); + ("part_del", (RErr, [Device "device"; Int "partnum"]), 233, [], + [InitEmpty, Always, TestRun ( + [["part_init"; "/dev/sda"; "mbr"]; + ["part_add"; "/dev/sda"; "primary"; "1"; "-1"]; + ["part_del"; "/dev/sda"; "1"]])], + "delete a partition", + "\ +This command deletes the partition numbered C on C. + +Note that in the case of MBR partitioning, deleting an +extended partition also deletes any logical partitions +it contains."); + + ("part_get_bootable", (RBool "bootable", [Device "device"; Int "partnum"]), 234, [], + [InitEmpty, Always, TestOutputTrue ( + [["part_init"; "/dev/sda"; "mbr"]; + ["part_add"; "/dev/sda"; "primary"; "1"; "-1"]; + ["part_set_bootable"; "/dev/sda"; "1"; "true"]; + ["part_get_bootable"; "/dev/sda"; "1"]])], + "return true if a partition is bootable", + "\ +This command returns true if the partition C on +C has the bootable flag set. + +See also C."); + + ("part_get_mbr_id", (RInt "idbyte", [Device "device"; Int "partnum"]), 235, [FishOutput FishOutputHexadecimal], + [InitEmpty, Always, TestOutputInt ( + [["part_init"; "/dev/sda"; "mbr"]; + ["part_add"; "/dev/sda"; "primary"; "1"; "-1"]; + ["part_set_mbr_id"; "/dev/sda"; "1"; "0x7f"]; + ["part_get_mbr_id"; "/dev/sda"; "1"]], 0x7f)], + "get the MBR type byte (ID byte) from a partition", + "\ +Returns the MBR type byte (also known as the ID byte) from +the numbered partition C. + +Note that only MBR (old DOS-style) partitions have type bytes. +You will get undefined results for other partition table +types (see C)."); + + ("part_set_mbr_id", (RErr, [Device "device"; Int "partnum"; Int "idbyte"]), 236, [], + [], (* tested by part_get_mbr_id *) + "set the MBR type byte (ID byte) of a partition", + "\ +Sets the MBR type byte (also known as the ID byte) of +the numbered partition C to C. Note +that the type bytes quoted in most documentation are +in fact hexadecimal numbers, but usually documented +without any leading \"0x\" which might be confusing. + +Note that only MBR (old DOS-style) partitions have type bytes. +You will get undefined results for other partition table +types (see C)."); + + ("checksum_device", (RString "checksum", [String "csumtype"; Device "device"]), 237, [], + [InitISOFS, Always, TestOutput ( + [["checksum_device"; "md5"; "/dev/sdd"]], + (Digest.to_hex (Digest.file "images/test.iso")))], + "compute MD5, SHAx or CRC checksum of the contents of a device", + "\ +This call computes the MD5, SHAx or CRC checksum of the +contents of the device named C. For the types of +checksums supported see the C command."); + + ("lvresize_free", (RErr, [Device "lv"; Int "percent"]), 238, [Optional "lvm2"], + [InitNone, Always, TestRun ( + [["part_disk"; "/dev/sda"; "mbr"]; + ["pvcreate"; "/dev/sda1"]; + ["vgcreate"; "VG"; "/dev/sda1"]; + ["lvcreate"; "LV"; "VG"; "10"]; + ["lvresize_free"; "/dev/VG/LV"; "100"]])], + "expand an LV to fill free space", + "\ +This expands an existing logical volume C so that it fills +C% of the remaining free space in the volume group. Commonly +you would call this with pc = 100 which expands the logical volume +as much as possible, using all remaining free space in the volume +group."); + + ("aug_clear", (RErr, [String "augpath"]), 239, [Optional "augeas"], + [], (* XXX Augeas code needs tests. *) + "clear Augeas path", + "\ +Set the value associated with C to C. This +is the same as the L C command."); + + ("get_umask", (RInt "mask", []), 240, [FishOutput FishOutputOctal], + [InitEmpty, Always, TestOutputInt ( + [["get_umask"]], 0o22)], + "get the current umask", + "\ +Return the current umask. By default the umask is C<022> +unless it has been set by calling C."); + + ("debug_upload", (RErr, [FileIn "filename"; String "tmpname"; Int "mode"]), 241, [], + [], + "upload a file to the appliance (internal use only)", + "\ +The C command uploads a file to +the libguestfs appliance. + +There is no comprehensive help for this command. You have +to look at the file C in the libguestfs source +to find out what it is for."); + + ("base64_in", (RErr, [FileIn "base64file"; Pathname "filename"]), 242, [], + [InitBasicFS, Always, TestOutput ( + [["base64_in"; "../images/hello.b64"; "/hello"]; + ["cat"; "/hello"]], "hello\n")], + "upload base64-encoded data to file", + "\ +This command uploads base64-encoded data from C +to C."); + + ("base64_out", (RErr, [Pathname "filename"; FileOut "base64file"]), 243, [], + [], + "download file and encode as base64", + "\ +This command downloads the contents of C, writing +it out to local file C encoded as base64."); + ] let all_functions = non_daemon_functions @ daemon_functions @@ -4953,7 +5101,7 @@ let check_functions () = failwithf "short description of %s should not end with . or \\n." name ) all_functions; - (* Check long dscriptions. *) + (* Check long descriptions. *) List.iter ( fun (name, _, _, _, _, _, longdesc) -> if longdesc.[String.length longdesc-1] = '\n' then @@ -5098,7 +5246,7 @@ let rec generate_actions_pod () = let name = "guestfs_" ^ shortname in pr "=head2 %s\n\n" name; pr " "; - generate_prototype ~extern:false ~handle:"handle" name style; + generate_prototype ~extern:false ~handle:"g" name style; pr "\n\n"; pr "%s\n\n" longdesc; (match fst style with @@ -5426,7 +5574,7 @@ and generate_actions_h () = List.iter ( fun (shortname, style, _, _, _, _, _) -> let name = "guestfs_" ^ shortname in - generate_prototype ~single_line:true ~newline:true ~handle:"handle" + generate_prototype ~single_line:true ~newline:true ~handle:"g" name style ) all_functions @@ -5436,7 +5584,7 @@ and generate_internal_actions_h () = List.iter ( fun (shortname, style, _, _, _, _, _) -> let name = "guestfs__" ^ shortname in - generate_prototype ~single_line:true ~newline:true ~handle:"handle" + generate_prototype ~single_line:true ~newline:true ~handle:"g" name style ) non_daemon_functions @@ -5621,7 +5769,8 @@ check_state (guestfs_h *g, const char *caller) pr " int r;\n"; pr "\n"; trace_call shortname style; - pr " if (check_state (g, \"%s\") == -1) return %s;\n" name error_code; + pr " if (check_state (g, \"%s\") == -1) return %s;\n" + shortname error_code; pr " guestfs___set_busy (g);\n"; pr "\n"; @@ -5911,14 +6060,19 @@ and generate_daemon_actions () = ); pr "\n"; + let is_filein = + List.exists (function FileIn _ -> true | _ -> false) (snd style) in + (match snd style with | [] -> () | args -> pr " memset (&args, 0, sizeof args);\n"; pr "\n"; pr " if (!xdr_guestfs_%s_args (xdr_in, &args)) {\n" name; + if is_filein then + pr " cancel_receive ();\n"; pr " reply_with_error (\"daemon failed to decode procedure arguments\");\n"; - pr " return;\n"; + pr " goto done;\n"; pr " }\n"; let pr_args n = pr " char *%s = args.%s;\n" n n @@ -5927,6 +6081,8 @@ and generate_daemon_actions () = pr " %s = realloc (args.%s.%s_val,\n" n n n; pr " sizeof (char *) * (args.%s.%s_len+1));\n" n n; pr " if (%s == NULL) {\n" n; + if is_filein then + pr " cancel_receive ();\n"; pr " reply_with_perror (\"realloc\");\n"; pr " goto done;\n"; pr " }\n"; @@ -5937,13 +6093,16 @@ and generate_daemon_actions () = function | Pathname n -> pr_args n; - pr " ABS_PATH (%s, goto done);\n" n; + pr " ABS_PATH (%s, %s, goto done);\n" + n (if is_filein then "cancel_receive ()" else ""); | Device n -> pr_args n; - pr " RESOLVE_DEVICE (%s, goto done);\n" n; + pr " RESOLVE_DEVICE (%s, %s, goto done);\n" + n (if is_filein then "cancel_receive ()" else ""); | Dev_or_Path n -> pr_args n; - pr " REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, goto done);\n" n; + pr " REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, %s, goto done);\n" + n (if is_filein then "cancel_receive ()" else ""); | String n -> pr_args n | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n | StringList n -> @@ -5953,7 +6112,8 @@ and generate_daemon_actions () = pr " /* Ensure that each is a device,\n"; pr " * and perform device name translation. */\n"; pr " { int pvi; for (pvi = 0; physvols[pvi] != NULL; ++pvi)\n"; - pr " RESOLVE_DEVICE (physvols[pvi], goto done);\n"; + pr " RESOLVE_DEVICE (physvols[pvi], %s, goto done);\n" + (if is_filein then "cancel_receive ()" else ""); pr " }\n"; | Bool n -> pr " %s = args.%s;\n" n n | Int n -> pr " %s = args.%s;\n" n n @@ -5968,7 +6128,8 @@ and generate_daemon_actions () = if List.exists (function Pathname _ -> true | _ -> false) (snd style) then ( (* Emit NEED_ROOT just once, even when there are two or more Pathname args *) - pr " NEED_ROOT (goto done);\n"; + pr " NEED_ROOT (%s, goto done);\n" + (if is_filein then "cancel_receive ()" else ""); ); (* Don't want to call the impl with any FileIn or FileOut @@ -6054,15 +6215,14 @@ and generate_daemon_actions () = ); (* Free the args. *) + pr "done:\n"; (match snd style with - | [] -> - pr "done: ;\n"; + | [] -> () | _ -> - pr "done:\n"; pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n" name ); - + pr " return;\n"; pr "}\n\n"; ) daemon_functions; @@ -7252,11 +7412,11 @@ and generate_fish_cmds () = function | Device n | String n - | OptString n - | FileIn n - | FileOut n -> pr " const char *%s;\n" n + | OptString n -> pr " const char *%s;\n" n | Pathname n - | Dev_or_Path n -> pr " char *%s;\n" n + | Dev_or_Path n + | FileIn n + | FileOut n -> pr " char *%s;\n" n | StringList n | DeviceList n -> pr " char **%s;\n" n | Bool n -> pr " int %s;\n" n | Int n -> pr " int %s;\n" n @@ -7313,11 +7473,11 @@ and generate_fish_cmds () = pr " %s = STRNEQ (argv[%d], \"\") ? argv[%d] : NULL;\n" name i i | FileIn name -> - pr " %s = STRNEQ (argv[%d], \"-\") ? argv[%d] : \"/dev/stdin\";\n" - name i i + pr " %s = file_in (argv[%d]);\n" name i; + pr " if (%s == NULL) return -1;\n" name | FileOut name -> - pr " %s = STRNEQ (argv[%d], \"-\") ? argv[%d] : \"/dev/stdout\";\n" - name i i + pr " %s = file_out (argv[%d]);\n" name i; + pr " if (%s == NULL) return -1;\n" name | StringList name | DeviceList name -> pr " %s = parse_string_list (argv[%d]);\n" name i; pr " if (%s == NULL) return -1;\n" name; @@ -7346,24 +7506,49 @@ and generate_fish_cmds () = List.iter ( function | Device name | String name - | OptString name | FileIn name | FileOut name | Bool name + | OptString name | Bool name | Int name | Int64 name -> () - | Pathname name | Dev_or_Path name -> + | Pathname name | Dev_or_Path name | FileOut name -> pr " free (%s);\n" name + | FileIn name -> + pr " free_file_in (%s);\n" name | StringList name | DeviceList name -> pr " free_strings (%s);\n" name ) (snd style); + (* Any output flags? *) + let fish_output = + let flags = filter_map ( + function FishOutput flag -> Some flag | _ -> None + ) flags in + match flags with + | [] -> None + | [f] -> Some f + | _ -> + failwithf "%s: more than one FishOutput flag is not allowed" name in + (* Check return value for errors and display command results. *) (match fst style with | RErr -> pr " return r;\n" | RInt _ -> pr " if (r == -1) return -1;\n"; - pr " printf (\"%%d\\n\", r);\n"; + (match fish_output with + | None -> + pr " printf (\"%%d\\n\", r);\n"; + | Some FishOutputOctal -> + pr " printf (\"%%s%%o\\n\", r != 0 ? \"0\" : \"\", r);\n"; + | Some FishOutputHexadecimal -> + pr " printf (\"%%s%%x\\n\", r != 0 ? \"0x\" : \"\", r);\n"); pr " return 0;\n" | RInt64 _ -> pr " if (r == -1) return -1;\n"; - pr " printf (\"%%\" PRIi64 \"\\n\", r);\n"; + (match fish_output with + | None -> + pr " printf (\"%%\" PRIi64 \"\\n\", r);\n"; + | Some FishOutputOctal -> + pr " printf (\"%%s%%\" PRIo64 \"\\n\", r != 0 ? \"0\" : \"\", r);\n"; + | Some FishOutputHexadecimal -> + pr " printf (\"%%s%%\" PRIx64 \"\\n\", r != 0 ? \"0x\" : \"\", r);\n"); pr " return 0;\n" | RBool _ -> pr " if (r == -1) return -1;\n";