* To return an arbitrary buffer, use RBufferOut.
*)
| BufferIn of string
+ (* Key material / passphrase. Eventually we should treat this
+ * as sensitive and mlock it into physical RAM. However this
+ * is highly complex because of all the places that XDR-encoded
+ * strings can end up. So currently the only difference from
+ * 'String' is the way that guestfish requests these parameters
+ * from the user.
+ *)
+ | Key of string
type flags =
| ProtocolLimitWarning (* display warning about protocol size limits *)
If the filesystem does not have a UUID, this returns the empty string.");
+ ("lvm_set_filter", (RErr, [DeviceList "devices"]), 255, [Optional "lvm2"],
+ (* Can't be tested with the current framework because
+ * the VG is being used by the mounted filesystem, so
+ * the vgchange -an command we do first will fail.
+ *)
+ [],
+ "set LVM device filter",
+ "\
+This sets the LVM device filter so that LVM will only be
+able to \"see\" the block devices in the list C<devices>,
+and will ignore all other attached block devices.
+
+Where disk image(s) contain duplicate PVs or VGs, this
+command is useful to get LVM to ignore the duplicates, otherwise
+LVM can get confused. Note also there are two types
+of duplication possible: either cloned PVs/VGs which have
+identical UUIDs; or VGs that are not cloned but just happen
+to have the same name. In normal operation you cannot
+create this situation, but you can do it outside LVM, eg.
+by cloning disk images or by bit twiddling inside the LVM
+metadata.
+
+This command also clears the LVM cache and performs a volume
+group scan.
+
+You can filter whole block devices or individual partitions.
+
+You cannot use this if any VG is currently in use (eg.
+contains a mounted filesystem), even if you are not
+filtering out that VG.");
+
+ ("lvm_clear_filter", (RErr, []), 256, [],
+ [], (* see note on lvm_set_filter *)
+ "clear LVM device filter",
+ "\
+This undoes the effect of C<guestfs_lvm_set_filter>. LVM
+will be able to see every block device.
+
+This command also clears the LVM cache and performs a volume
+group scan.");
+
+ ("luks_open", (RErr, [Device "device"; Key "key"; String "mapname"]), 257, [Optional "luks"],
+ [],
+ "open a LUKS-encrypted block device",
+ "\
+This command opens a block device which has been encrypted
+according to the Linux Unified Key Setup (LUKS) standard.
+
+C<device> is the encrypted block device or partition.
+
+The caller must supply one of the keys associated with the
+LUKS block device, in the C<key> parameter.
+
+This creates a new block device called C</dev/mapper/mapname>.
+Reads and writes to this block device are decrypted from and
+encrypted to the underlying C<device> respectively.
+
+If this block device contains LVM volume groups, then
+calling C<guestfs_vgscan> followed by C<guestfs_vg_activate_all>
+will make them visible.");
+
+ ("luks_open_ro", (RErr, [Device "device"; Key "key"; String "mapname"]), 258, [Optional "luks"],
+ [],
+ "open a LUKS-encrypted block device read-only",
+ "\
+This is the same as C<guestfs_luks_open> except that a read-only
+mapping is created.");
+
+ ("luks_close", (RErr, [Device "device"]), 259, [Optional "luks"],
+ [],
+ "close a LUKS device",
+ "\
+This closes a LUKS device that was created earlier by
+C<guestfs_luks_open> or C<guestfs_luks_open_ro>. The
+C<device> parameter must be the name of the LUKS mapping
+device (ie. C</dev/mapper/mapname>) and I<not> the name
+of the underlying block device.");
+
]
let all_functions = non_daemon_functions @ daemon_functions
let name_of_argt = function
| Pathname n | Device n | Dev_or_Path n | String n | OptString n
| StringList n | DeviceList n | Bool n | Int n | Int64 n
- | FileIn n | FileOut n | BufferIn n -> n
+ | FileIn n | FileOut n | BufferIn n | Key n -> n
let java_name_of_struct typ =
try List.assoc typ java_structs
pr "%s\n\n" protocol_limit_warning;
if List.mem DangerWillRobinson flags then
pr "%s\n\n" danger_will_robinson;
+ if List.exists (function Key _ -> true | _ -> false) (snd style) then
+ pr "This function takes a key or passphrase parameter which
+could contain sensitive material. Read the section
+L</KEYS AND PASSPHRASES> for more information.\n\n";
match deprecation_notice flags with
| None -> ()
| Some txt -> pr "%s\n\n" txt
pr "struct %s_args {\n" name;
List.iter (
function
- | Pathname n | Device n | Dev_or_Path n | String n ->
+ | Pathname n | Device n | Dev_or_Path n | String n | Key n ->
pr " string %s<>;\n" n
| OptString n -> pr " str *%s;\n" n
| StringList n | DeviceList n -> pr " str %s<>;\n" n
| FileOut n
| BufferIn n
| StringList n
- | DeviceList n ->
+ | DeviceList n
+ | Key n ->
pr " if (%s == NULL) {\n" n;
pr " error (g, \"%%s: %%s: parameter cannot be NULL\",\n";
pr " \"%s\", \"%s\");\n" shortname n;
| Dev_or_Path n
| FileIn n
| FileOut n
- | BufferIn n ->
+ | BufferIn n
+ | Key n ->
(* guestfish doesn't support string escaping, so neither do we *)
pr " printf (\" \\\"%%s\\\"\", %s);\n" n
| OptString n -> (* string option *)
| args ->
List.iter (
function
- | Pathname n | Device n | Dev_or_Path n | String n ->
+ | Pathname n | Device n | Dev_or_Path n | String n | Key n ->
pr " args.%s = (char *) %s;\n" n n
| OptString n ->
pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n
function
| Device n | Dev_or_Path n
| Pathname n
- | String n -> ()
+ | String n
+ | Key n -> ()
| OptString n -> pr " char *%s;\n" n
| StringList n | DeviceList n -> pr " char **%s;\n" n
| Bool n -> pr " int %s;\n" n
pr_args n;
pr " REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, %s, goto done);\n"
n (if is_filein then "cancel_receive ()" else "0");
- | String n -> pr_args n
+ | String n | Key n -> pr_args n
| OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n
| StringList n ->
pr_list_handling_code n;
| Device n, arg
| Dev_or_Path n, arg
| String n, arg
- | OptString n, arg ->
+ | OptString n, arg
+ | Key n, arg ->
pr " const char *%s = \"%s\";\n" n (c_quote arg);
| BufferIn n, arg ->
pr " const char *%s = \"%s\";\n" n (c_quote arg);
| Pathname n, _
| Device n, _ | Dev_or_Path n, _
| String n, _
- | OptString n, _ ->
+ | OptString n, _
+ | Key n, _ ->
pr ", %s" n
| BufferIn n, _ ->
pr ", %s, %s_size" n n
match snd style with
| [] -> name2
| args ->
+ let args = List.filter (function Key _ -> false | _ -> true) args in
sprintf "%s %s"
name2 (String.concat " " (List.map name_of_argt args)) in
let warnings =
- if List.mem ProtocolLimitWarning flags then
- ("\n\n" ^ protocol_limit_warning)
+ if List.exists (function Key _ -> true | _ -> false) (snd style) then
+ "\n\nThis command has one or more key or passphrase parameters.
+Guestfish will prompt for these separately."
else "" in
+ let warnings =
+ warnings ^
+ if List.mem ProtocolLimitWarning flags then
+ ("\n\n" ^ protocol_limit_warning)
+ else "" in
+
(* For DangerWillRobinson commands, we should probably have
* guestfish prompt before allowing you to use them (especially
* in interactive mode). XXX
| Pathname n
| Dev_or_Path n
| FileIn n
- | FileOut n -> pr " char *%s;\n" n
+ | FileOut n
+ | Key n -> pr " char *%s;\n" n
| BufferIn n ->
pr " const char *%s;\n" n;
pr " size_t %s_size;\n" n
) (snd style);
(* Check and convert parameters. *)
- let argc_expected = List.length (snd style) in
+ let argc_expected =
+ let args_no_keys =
+ List.filter (function Key _ -> false | _ -> true) (snd style) in
+ List.length args_no_keys in
pr " if (argc != %d) {\n" argc_expected;
pr " fprintf (stderr, _(\"%%s should have %%d parameter(s)\\n\"), cmd, %d);\n"
argc_expected;
pr " return -1;\n";
pr " }\n";
- let parse_integer fn fntyp rtyp range name i =
+ let parse_integer fn fntyp rtyp range name =
pr " {\n";
pr " strtol_error xerr;\n";
pr " %s r;\n" fntyp;
pr "\n";
- pr " xerr = %s (argv[%d], NULL, 0, &r, xstrtol_suffixes);\n" fn i;
+ pr " xerr = %s (argv[i++], NULL, 0, &r, xstrtol_suffixes);\n" fn;
pr " if (xerr != LONGINT_OK) {\n";
pr " fprintf (stderr,\n";
pr " _(\"%%s: %%s: invalid integer parameter (%%s returned %%d)\\n\"),\n";
pr " }\n";
in
- iteri (
- fun i ->
- function
- | Device name
- | String name ->
- pr " %s = argv[%d];\n" name i
- | Pathname name
- | Dev_or_Path name ->
- pr " %s = resolve_win_path (argv[%d]);\n" name i;
- pr " if (%s == NULL) return -1;\n" name
- | OptString name ->
- pr " %s = STRNEQ (argv[%d], \"\") ? argv[%d] : NULL;\n"
- name i i
- | BufferIn name ->
- pr " %s = argv[%d];\n" name i;
- pr " %s_size = strlen (argv[%d]);\n" name i
- | FileIn name ->
- pr " %s = file_in (argv[%d]);\n" name i;
- pr " if (%s == NULL) return -1;\n" name
- | FileOut name ->
- 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;
- | Bool name ->
- pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i
- | Int name ->
- let range =
- let min = "(-(2LL<<30))"
- and max = "((2LL<<30)-1)"
- and comment =
- "The Int type in the generator is a signed 31 bit int." in
- Some (min, max, comment) in
- parse_integer "xstrtoll" "long long" "int" range name i
- | Int64 name ->
- parse_integer "xstrtoll" "long long" "int64_t" None name i
+ if snd style <> [] then
+ pr " size_t i = 0;\n";
+
+ List.iter (
+ function
+ | Device name
+ | String name ->
+ pr " %s = argv[i++];\n" name
+ | Pathname name
+ | Dev_or_Path name ->
+ pr " %s = resolve_win_path (argv[i++]);\n" name;
+ pr " if (%s == NULL) return -1;\n" name
+ | OptString name ->
+ pr " %s = STRNEQ (argv[i], \"\") ? argv[i] : NULL;\n" name;
+ pr " i++;\n"
+ | BufferIn name ->
+ pr " %s = argv[i];\n" name;
+ pr " %s_size = strlen (argv[i]);\n" name;
+ pr " i++;\n"
+ | FileIn name ->
+ pr " %s = file_in (argv[i++]);\n" name;
+ pr " if (%s == NULL) return -1;\n" name
+ | FileOut name ->
+ pr " %s = file_out (argv[i++]);\n" name;
+ pr " if (%s == NULL) return -1;\n" name
+ | StringList name | DeviceList name ->
+ pr " %s = parse_string_list (argv[i++]);\n" name;
+ pr " if (%s == NULL) return -1;\n" name
+ | Key name ->
+ pr " %s = read_key (\"%s\");\n" name name;
+ pr " if (%s == NULL) return -1;\n" name
+ | Bool name ->
+ pr " %s = is_true (argv[i++]) ? 1 : 0;\n" name
+ | Int name ->
+ let range =
+ let min = "(-(2LL<<30))"
+ and max = "((2LL<<30)-1)"
+ and comment =
+ "The Int type in the generator is a signed 31 bit int." in
+ Some (min, max, comment) in
+ parse_integer "xstrtoll" "long long" "int" range name
+ | Int64 name ->
+ parse_integer "xstrtoll" "long long" "int64_t" None name
) (snd style);
(* Call C API function. *)
List.iter (
function
- | Device name | String name
- | OptString name | Bool name
- | Int name | Int64 name
- | BufferIn name -> ()
- | Pathname name | Dev_or_Path name | FileOut name ->
+ | Device _ | String _
+ | OptString _ | Bool _
+ | Int _ | Int64 _
+ | BufferIn _ -> ()
+ | Pathname name | Dev_or_Path name | FileOut name
+ | Key name ->
pr " free (%s);\n" name
| FileIn name ->
pr " free_file_in (%s);\n" name
pr " %s" name;
List.iter (
function
- | Pathname n | Device n | Dev_or_Path n | String n -> pr " %s" n
+ | Pathname n | Device n | Dev_or_Path n | String n ->
+ pr " %s" n
| OptString n -> pr " %s" n
| StringList n | DeviceList n -> pr " '%s ...'" n
| Bool _ -> pr " true|false"
| Int64 n -> pr " %s" n
| FileIn n | FileOut n -> pr " (%s|-)" n
| BufferIn n -> pr " %s" n
+ | Key _ -> () (* keys are entered at a prompt *)
) (snd style);
pr "\n";
pr "\n";
| _ -> false) (snd style) then
pr "Use C<-> instead of a filename to read/write from stdin/stdout.\n\n";
+ if List.exists (function Key _ -> true | _ -> false) (snd style) then
+ pr "This command has one or more key or passphrase parameters.
+Guestfish will prompt for these separately.\n\n";
+
if List.mem ProtocolLimitWarning flags then
pr "%s\n\n" protocol_limit_warning;
| Pathname n
| Device n | Dev_or_Path n
| String n
- | OptString n ->
+ | OptString n
+ | Key n ->
next ();
pr "const char *%s" n
| StringList n | DeviceList n ->
| Device n | Dev_or_Path n
| String n
| FileIn n
- | FileOut n ->
+ | FileOut n
+ | Key n ->
(* Copy strings in case the GC moves them: RHBZ#604691 *)
pr " char *%s = guestfs_safe_strdup (g, String_val (%sv));\n" n n
| OptString n ->
List.iter (
function
| Pathname n | Device n | Dev_or_Path n | String n | OptString n
- | FileIn n | FileOut n | BufferIn n ->
+ | FileIn n | FileOut n | BufferIn n | Key n ->
pr " free (%s);\n" n
| StringList n | DeviceList n ->
pr " ocaml_guestfs_free_strings (%s);\n" n;
List.iter (
function
| Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _
- | BufferIn _ -> pr "string -> "
+ | BufferIn _ | Key _ -> pr "string -> "
| OptString _ -> pr "string option -> "
| StringList _ | DeviceList _ -> pr "string array -> "
| Bool _ -> pr "bool -> "
fun i ->
function
| Pathname n | Device n | Dev_or_Path n | String n
- | FileIn n | FileOut n ->
+ | FileIn n | FileOut n | Key n ->
pr " char *%s;\n" n
| BufferIn n ->
pr " char *%s;\n" n;
| Pathname _ | Device _ | Dev_or_Path _ | String _ | OptString _
| Bool _ | Int _ | Int64 _
| FileIn _ | FileOut _
- | BufferIn _ -> ()
+ | BufferIn _ | Key _ -> ()
| StringList n | DeviceList n -> pr " free (%s);\n" n
) (snd style)
in
match arg with
| Pathname n | Device n | Dev_or_Path n | String n
| OptString n | Bool n | Int n | Int64 n | FileIn n | FileOut n
- | BufferIn n ->
+ | BufferIn n | Key n ->
pr "$%s" n
| StringList n | DeviceList n ->
pr "\\@%s" n
List.iter (
function
- | Pathname n | Device n | Dev_or_Path n | String n
+ | Pathname n | Device n | Dev_or_Path n | String n | Key n
| FileIn n | FileOut n ->
pr " const char *%s;\n" n
| OptString n -> pr " const char *%s;\n" n
pr " if (!PyArg_ParseTuple (args, (char *) \"O";
List.iter (
function
- | Pathname _ | Device _ | Dev_or_Path _ | String _ | FileIn _ | FileOut _ -> pr "s"
+ | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
+ | FileIn _ | FileOut _ -> pr "s"
| OptString _ -> pr "z"
| StringList _ | DeviceList _ -> pr "O"
| Bool _ -> pr "i" (* XXX Python has booleans? *)
pr " &py_g";
List.iter (
function
- | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n -> pr ", &%s" n
+ | Pathname n | Device n | Dev_or_Path n | String n | Key n
+ | FileIn n | FileOut n -> pr ", &%s" n
| OptString n -> pr ", &%s" n
| StringList n | DeviceList n -> pr ", &py_%s" n
| Bool n -> pr ", &%s" n
pr " g = get_handle (py_g);\n";
List.iter (
function
- | Pathname _ | Device _ | Dev_or_Path _ | String _
+ | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
| FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
| BufferIn _ -> ()
| StringList n | DeviceList n ->
List.iter (
function
- | Pathname _ | Device _ | Dev_or_Path _ | String _
+ | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
| FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
| BufferIn _ -> ()
| StringList n | DeviceList n ->
List.iter (
function
- | Pathname n | Device n | Dev_or_Path n | String n | FileIn n | FileOut n ->
+ | Pathname n | Device n | Dev_or_Path n | String n | Key n
+ | FileIn n | FileOut n ->
pr " Check_Type (%sv, T_STRING);\n" n;
pr " const char *%s = StringValueCStr (%sv);\n" n n;
pr " if (!%s)\n" n;
List.iter (
function
- | Pathname _ | Device _ | Dev_or_Path _ | String _
+ | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
| FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
| BufferIn _ -> ()
| StringList n | DeviceList n ->
| String n
| OptString n
| FileIn n
- | FileOut n ->
+ | FileOut n
+ | Key n ->
pr "String %s" n
| BufferIn n ->
pr "byte[] %s" n
| String n
| OptString n
| FileIn n
- | FileOut n ->
+ | FileOut n
+ | Key n ->
pr ", jstring j%s" n
| BufferIn n ->
pr ", jbyteArray j%s" n
| String n
| OptString n
| FileIn n
- | FileOut n ->
+ | FileOut n
+ | Key n ->
pr " const char *%s;\n" n
| BufferIn n ->
pr " jbyte *%s;\n" n;
| Device n | Dev_or_Path n
| String n
| FileIn n
- | FileOut n ->
+ | FileOut n
+ | Key n ->
pr " %s = (*env)->GetStringUTFChars (env, j%s, NULL);\n" n n
| OptString n ->
(* This is completely undocumented, but Java null becomes
| Device n | Dev_or_Path n
| String n
| FileIn n
- | FileOut n ->
+ | FileOut n
+ | Key n ->
pr " (*env)->ReleaseStringUTFChars (env, j%s, %s);\n" n n
| OptString n ->
pr " if (j%s)\n" n;
function
| FileIn n
| FileOut n
- | Pathname n | Device n | Dev_or_Path n | String n ->
+ | Pathname n | Device n | Dev_or_Path n | String n | Key n ->
pr "withCString %s $ \\%s -> " n n
| BufferIn n ->
pr "withCStringLen %s $ \\(%s, %s_size) -> " n n n
| Int n -> sprintf "(fromIntegral %s)" n
| Int64 n -> sprintf "(fromIntegral %s)" n
| FileIn n | FileOut n
- | Pathname n | Device n | Dev_or_Path n | String n | OptString n | StringList n | DeviceList n -> n
+ | Pathname n | Device n | Dev_or_Path n
+ | String n | OptString n
+ | StringList n | DeviceList n
+ | Key n -> n
| BufferIn n -> sprintf "%s (fromIntegral %s_size)" n n
) (snd style) in
pr "withForeignPtr h (\\p -> c_%s %s)\n" name
List.iter (
fun arg ->
(match arg with
- | Pathname _ | Device _ | Dev_or_Path _ | String _ -> pr "%s" string
+ | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _ ->
+ pr "%s" string
| BufferIn _ ->
if hs then pr "String"
else pr "CString -> CInt"
function
| Pathname n | Device n | Dev_or_Path n | String n | OptString n
| FileIn n | FileOut n
+ | Key n
| BufferIn n ->
pr ", [In] string %s" n
| StringList n | DeviceList n ->
function
| Pathname n | Device n | Dev_or_Path n | String n | OptString n
| FileIn n | FileOut n
+ | Key n
| BufferIn n ->
next (); pr "string %s" n
| StringList n | DeviceList n ->
| Device n | Dev_or_Path n
| String n
| FileIn n
- | FileOut n -> pr " printf (\"%%s\\n\", %s);\n" n
+ | FileOut n
+ | Key n -> pr " printf (\"%%s\\n\", %s);\n" n
| BufferIn n ->
pr " {\n";
pr " size_t i;\n";