|
|
|
|
From 64c1716c4120e8dc69d0106b6ebcf6ccb9d4fc24 Mon Sep 17 00:00:00 2001
|
|
|
|
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
|
|
|
Date: Thu, 29 Jun 2023 13:33:04 +0100
|
|
|
|
|
Subject: [PATCH] generator: Add --chown option for virt-customize
|
|
|
|
|
|
|
|
|
|
Also this updates the common submodule to include the changes.
|
|
|
|
|
|
|
|
|
|
Fixes: https://github.com/rwmjones/guestfs-tools/issues/12
|
|
|
|
|
Acked-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
|
|
(cherry picked from commit d8e48bff212f9b0558480ffedf8158157360d0d5)
|
|
|
|
|
---
|
|
|
|
|
common | 2 +-
|
|
|
|
|
generator/customize.ml | 28 ++++++++++++++++++++++++++++
|
|
|
|
|
2 files changed, 29 insertions(+), 1 deletion(-)
|
|
|
|
|
|
|
|
|
|
Submodule common d61cd820..bbb54714:
|
|
|
|
|
diff --git a/common/mlcustomize/customize-options.pod b/common/mlcustomize/customize-options.pod
|
|
|
|
|
index 22a96e04..22724600 100644
|
|
|
|
|
--- a/common/mlcustomize/customize-options.pod
|
|
|
|
|
+++ b/common/mlcustomize/customize-options.pod
|
|
|
|
|
@@ -63,6 +63,30 @@ Change the permissions of C<FILE> to C<PERMISSIONS>.
|
|
|
|
|
I<Note>: C<PERMISSIONS> by default would be decimal, unless you prefix
|
|
|
|
|
it with C<0> to get octal, ie. use C<0700> not C<700>.
|
|
|
|
|
|
|
|
|
|
+=item B<--chown> UID.GID:PATH
|
|
|
|
|
+
|
|
|
|
|
+Change the owner user and group ID of a file or directory in the guest.
|
|
|
|
|
+Note:
|
|
|
|
|
+
|
|
|
|
|
+=over 4
|
|
|
|
|
+
|
|
|
|
|
+=item *
|
|
|
|
|
+
|
|
|
|
|
+Only numeric UIDs and GIDs will work, and these may not be the same
|
|
|
|
|
+inside the guest as on the host.
|
|
|
|
|
+
|
|
|
|
|
+=item *
|
|
|
|
|
+
|
|
|
|
|
+This will not work with Windows guests.
|
|
|
|
|
+
|
|
|
|
|
+=back
|
|
|
|
|
+
|
|
|
|
|
+For example:
|
|
|
|
|
+
|
|
|
|
|
+ virt-customize --chown '0.0:/var/log/audit.log'
|
|
|
|
|
+
|
|
|
|
|
+See also: I<--upload>.
|
|
|
|
|
+
|
|
|
|
|
=item B<--commands-from-file> FILENAME
|
|
|
|
|
|
|
|
|
|
Read the customize commands from a file, one (and its arguments)
|
|
|
|
|
diff --git a/common/mlcustomize/customize-synopsis.pod b/common/mlcustomize/customize-synopsis.pod
|
|
|
|
|
index d04f421e..e20b12d4 100644
|
|
|
|
|
--- a/common/mlcustomize/customize-synopsis.pod
|
|
|
|
|
+++ b/common/mlcustomize/customize-synopsis.pod
|
|
|
|
|
@@ -1,15 +1,15 @@
|
|
|
|
|
[--append-line FILE:LINE] [--chmod PERMISSIONS:FILE]
|
|
|
|
|
- [--commands-from-file FILENAME] [--copy SOURCE:DEST]
|
|
|
|
|
- [--copy-in LOCALPATH:REMOTEDIR] [--delete PATH] [--edit FILE:EXPR]
|
|
|
|
|
- [--firstboot SCRIPT] [--firstboot-command 'CMD+ARGS']
|
|
|
|
|
- [--firstboot-install PKG,PKG..] [--hostname HOSTNAME]
|
|
|
|
|
- [--inject-qemu-ga METHOD] [--inject-virtio-win METHOD]
|
|
|
|
|
- [--install PKG,PKG..] [--link TARGET:LINK[:LINK..]] [--mkdir DIR]
|
|
|
|
|
- [--move SOURCE:DEST] [--password USER:SELECTOR]
|
|
|
|
|
- [--root-password SELECTOR] [--run SCRIPT]
|
|
|
|
|
- [--run-command 'CMD+ARGS'] [--scrub FILE] [--sm-attach SELECTOR]
|
|
|
|
|
- [--sm-register] [--sm-remove] [--sm-unregister]
|
|
|
|
|
- [--ssh-inject USER[:SELECTOR]] [--truncate FILE]
|
|
|
|
|
+ [--chown UID.GID:PATH] [--commands-from-file FILENAME]
|
|
|
|
|
+ [--copy SOURCE:DEST] [--copy-in LOCALPATH:REMOTEDIR]
|
|
|
|
|
+ [--delete PATH] [--edit FILE:EXPR] [--firstboot SCRIPT]
|
|
|
|
|
+ [--firstboot-command 'CMD+ARGS'] [--firstboot-install PKG,PKG..]
|
|
|
|
|
+ [--hostname HOSTNAME] [--inject-qemu-ga METHOD]
|
|
|
|
|
+ [--inject-virtio-win METHOD] [--install PKG,PKG..]
|
|
|
|
|
+ [--link TARGET:LINK[:LINK..]] [--mkdir DIR] [--move SOURCE:DEST]
|
|
|
|
|
+ [--password USER:SELECTOR] [--root-password SELECTOR]
|
|
|
|
|
+ [--run SCRIPT] [--run-command 'CMD+ARGS'] [--scrub FILE]
|
|
|
|
|
+ [--sm-attach SELECTOR] [--sm-register] [--sm-remove]
|
|
|
|
|
+ [--sm-unregister] [--ssh-inject USER[:SELECTOR]] [--truncate FILE]
|
|
|
|
|
[--truncate-recursive PATH] [--timezone TIMEZONE] [--touch FILE]
|
|
|
|
|
[--uninstall PKG,PKG..] [--update] [--upload FILE:DEST]
|
|
|
|
|
[--write FILE:CONTENT] [--no-logfile]
|
|
|
|
|
diff --git a/common/mlcustomize/customize_cmdline.ml b/common/mlcustomize/customize_cmdline.ml
|
|
|
|
|
index 3c24315d..fd3074ad 100644
|
|
|
|
|
--- a/common/mlcustomize/customize_cmdline.ml
|
|
|
|
|
+++ b/common/mlcustomize/customize_cmdline.ml
|
|
|
|
|
@@ -41,6 +41,8 @@ and op = [
|
|
|
|
|
(* --append-line FILE:LINE *)
|
|
|
|
|
| `Chmod of string * string
|
|
|
|
|
(* --chmod PERMISSIONS:FILE *)
|
|
|
|
|
+ | `Chown of string * string
|
|
|
|
|
+ (* --chown UID.GID:PATH *)
|
|
|
|
|
| `CommandsFromFile of string
|
|
|
|
|
(* --commands-from-file FILENAME *)
|
|
|
|
|
| `Copy of string * string
|
|
|
|
|
@@ -187,6 +189,17 @@ let rec argspec () =
|
|
|
|
|
s_"Change the permissions of a file"
|
|
|
|
|
),
|
|
|
|
|
Some "PERMISSIONS:FILE", "Change the permissions of C<FILE> to C<PERMISSIONS>.\n\nI<Note>: C<PERMISSIONS> by default would be decimal, unless you prefix\nit with C<0> to get octal, ie. use C<0700> not C<700>.";
|
|
|
|
|
+ (
|
|
|
|
|
+ [ L"chown" ],
|
|
|
|
|
+ Getopt.String (
|
|
|
|
|
+ s_"UID.GID:PATH",
|
|
|
|
|
+ fun s ->
|
|
|
|
|
+ let p = split_string_pair "chown" s in
|
|
|
|
|
+ List.push_front (`Chown p) ops
|
|
|
|
|
+ ),
|
|
|
|
|
+ s_"Change the owner user and group ID of a file or directory"
|
|
|
|
|
+ ),
|
|
|
|
|
+ Some "UID.GID:PATH", "Change the owner user and group ID of a file or directory in the guest.\nNote:\n\n=over 4\n\n=item *\n\nOnly numeric UIDs and GIDs will work, and these may not be the same\ninside the guest as on the host.\n\n=item *\n\nThis will not work with Windows guests.\n\n=back\n\nFor example:\n\n virt-customize --chown '0.0:/var/log/audit.log'\n\nSee also: I<--upload>.";
|
|
|
|
|
(
|
|
|
|
|
[ L"commands-from-file" ],
|
|
|
|
|
Getopt.String (
|
|
|
|
|
diff --git a/common/mlcustomize/customize_cmdline.mli b/common/mlcustomize/customize_cmdline.mli
|
|
|
|
|
index 0cc166e6..5883bbe0 100644
|
|
|
|
|
--- a/common/mlcustomize/customize_cmdline.mli
|
|
|
|
|
+++ b/common/mlcustomize/customize_cmdline.mli
|
|
|
|
|
@@ -33,6 +33,8 @@ and op = [
|
|
|
|
|
(* --append-line FILE:LINE *)
|
|
|
|
|
| `Chmod of string * string
|
|
|
|
|
(* --chmod PERMISSIONS:FILE *)
|
|
|
|
|
+ | `Chown of string * string
|
|
|
|
|
+ (* --chown UID.GID:PATH *)
|
|
|
|
|
| `CommandsFromFile of string
|
|
|
|
|
(* --commands-from-file FILENAME *)
|
|
|
|
|
| `Copy of string * string
|
|
|
|
|
diff --git a/common/mltools/curl.ml b/common/mltools/curl.ml
|
|
|
|
|
index 6dba9753..73eed903 100644
|
|
|
|
|
--- a/common/mltools/curl.ml
|
|
|
|
|
+++ b/common/mltools/curl.ml
|
|
|
|
|
@@ -20,11 +20,13 @@ open Printf
|
|
|
|
|
|
|
|
|
|
open Std_utils
|
|
|
|
|
open Tools_utils
|
|
|
|
|
+open Common_gettext.Gettext
|
|
|
|
|
|
|
|
|
|
type t = {
|
|
|
|
|
curl : string;
|
|
|
|
|
args : args;
|
|
|
|
|
tmpdir : string option;
|
|
|
|
|
+ url : string;
|
|
|
|
|
}
|
|
|
|
|
and args = (string * string option) list
|
|
|
|
|
|
|
|
|
|
@@ -40,11 +42,17 @@ let args_of_proxy = function
|
|
|
|
|
| SystemProxy -> []
|
|
|
|
|
| ForcedProxy url -> [ "proxy", Some url; "noproxy", Some "" ]
|
|
|
|
|
|
|
|
|
|
-let create ?(curl = "curl") ?(proxy = SystemProxy) ?tmpdir args =
|
|
|
|
|
+let create ?(curl = "curl") ?(proxy = SystemProxy) ?tmpdir args url =
|
|
|
|
|
+ (* The ["url"] key must not appear in [args]. This was how the
|
|
|
|
|
+ * previous version of this module worked, so lets check there
|
|
|
|
|
+ * are no callers still doing this.
|
|
|
|
|
+ *)
|
|
|
|
|
+ List.iter (function "url", _ -> assert false | _ -> ()) args;
|
|
|
|
|
+
|
|
|
|
|
let args = safe_args @ args_of_proxy proxy @ args in
|
|
|
|
|
- { curl = curl; args = args; tmpdir = tmpdir }
|
|
|
|
|
+ { curl; args; tmpdir; url }
|
|
|
|
|
|
|
|
|
|
-let run { curl; args; tmpdir } =
|
|
|
|
|
+let run { curl; args; tmpdir; url } =
|
|
|
|
|
let config_file, chan = Filename.open_temp_file ?temp_dir:tmpdir
|
|
|
|
|
"guestfscurl" ".conf" in
|
|
|
|
|
List.iter (
|
|
|
|
|
@@ -67,15 +75,16 @@ let run { curl; args; tmpdir } =
|
|
|
|
|
| c -> output_char chan c
|
|
|
|
|
done;
|
|
|
|
|
fprintf chan "\"\n"
|
|
|
|
|
- ) args;
|
|
|
|
|
+ ) (("url", Some url) :: args);
|
|
|
|
|
close_out chan;
|
|
|
|
|
|
|
|
|
|
let cmd = sprintf "%s -q --config %s" (quote curl) (quote config_file) in
|
|
|
|
|
- let lines = external_command ~echo_cmd:false cmd in
|
|
|
|
|
+ let help = sprintf (f_"downloading %s") url in
|
|
|
|
|
+ let lines = external_command ~echo_cmd:false ~help cmd in
|
|
|
|
|
Unix.unlink config_file;
|
|
|
|
|
lines
|
|
|
|
|
|
|
|
|
|
-let to_string { curl; args } =
|
|
|
|
|
+let to_string { curl; args; url } =
|
|
|
|
|
let b = Buffer.create 128 in
|
|
|
|
|
bprintf b "%s -q" (quote curl);
|
|
|
|
|
List.iter (
|
|
|
|
|
@@ -85,7 +94,7 @@ let to_string { curl; args } =
|
|
|
|
|
| "user", Some _ -> bprintf b " --user <hidden>"
|
|
|
|
|
| name, Some value -> bprintf b " --%s %s" name (quote value)
|
|
|
|
|
) args;
|
|
|
|
|
- bprintf b "\n";
|
|
|
|
|
+ bprintf b " %s\n" (quote url);
|
|
|
|
|
Buffer.contents b
|
|
|
|
|
|
|
|
|
|
let print chan t = output_string chan (to_string t)
|
|
|
|
|
diff --git a/common/mltools/curl.mli b/common/mltools/curl.mli
|
|
|
|
|
index a3e98dc6..1606a79a 100644
|
|
|
|
|
--- a/common/mltools/curl.mli
|
|
|
|
|
+++ b/common/mltools/curl.mli
|
|
|
|
|
@@ -27,13 +27,16 @@ type proxy =
|
|
|
|
|
| SystemProxy (** Use the system settings. *)
|
|
|
|
|
| ForcedProxy of string (** The proxy is forced to the specified URL. *)
|
|
|
|
|
|
|
|
|
|
-val create : ?curl:string -> ?proxy:proxy -> ?tmpdir:string -> args -> t
|
|
|
|
|
+val create : ?curl:string -> ?proxy:proxy -> ?tmpdir:string -> args -> string
|
|
|
|
|
+ -> t
|
|
|
|
|
(** Create a curl command handle.
|
|
|
|
|
|
|
|
|
|
The curl arguments are a list of key, value pairs corresponding
|
|
|
|
|
to curl command line parameters, without leading dashes,
|
|
|
|
|
eg. [("user", Some "user:password")].
|
|
|
|
|
|
|
|
|
|
+ The string parameter is the URL (which is required).
|
|
|
|
|
+
|
|
|
|
|
The optional [?curl] parameter controls the name of the curl
|
|
|
|
|
binary (default ["curl"]).
|
|
|
|
|
|
|
|
|
|
diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml
|
|
|
|
|
index 8b611e77..23f16c51 100644
|
|
|
|
|
--- a/common/mltools/tools_utils.ml
|
|
|
|
|
+++ b/common/mltools/tools_utils.ml
|
|
|
|
|
@@ -435,8 +435,12 @@ let create_standard_options argspec ?anon_fun ?(key_opts = false)
|
|
|
|
|
let getopt = Getopt.create argspec ?anon_fun usage_msg in
|
|
|
|
|
{ getopt; ks; debug_gc }
|
|
|
|
|
|
|
|
|
|
+let external_command_failed help cmd reason =
|
|
|
|
|
+ let help_prefix = match help with None -> "" | Some str -> str ^ ": " in
|
|
|
|
|
+ error "%s%s ‘%s’: %s" help_prefix (s_"external command") cmd reason
|
|
|
|
|
+
|
|
|
|
|
(* Run an external command, slurp up the output as a list of lines. *)
|
|
|
|
|
-let external_command ?(echo_cmd = true) cmd =
|
|
|
|
|
+let external_command ?(echo_cmd = true) ?help cmd =
|
|
|
|
|
if echo_cmd then
|
|
|
|
|
debug "%s" cmd;
|
|
|
|
|
let chan = Unix.open_process_in cmd in
|
|
|
|
|
@@ -448,15 +452,18 @@ let external_command ?(echo_cmd = true) cmd =
|
|
|
|
|
(match stat with
|
|
|
|
|
| Unix.WEXITED 0 -> ()
|
|
|
|
|
| Unix.WEXITED i ->
|
|
|
|
|
- error (f_"external command ‘%s’ exited with error %d") cmd i
|
|
|
|
|
+ let reason = sprintf (f_"exited with error %d") i in
|
|
|
|
|
+ external_command_failed help cmd reason
|
|
|
|
|
| Unix.WSIGNALED i ->
|
|
|
|
|
- error (f_"external command ‘%s’ killed by signal %d") cmd i
|
|
|
|
|
+ let reason = sprintf (f_"killed by signal %d") i in
|
|
|
|
|
+ external_command_failed help cmd reason
|
|
|
|
|
| Unix.WSTOPPED i ->
|
|
|
|
|
- error (f_"external command ‘%s’ stopped by signal %d") cmd i
|
|
|
|
|
+ let reason = sprintf (f_"stopped by signal %d") i in
|
|
|
|
|
+ external_command_failed help cmd reason
|
|
|
|
|
);
|
|
|
|
|
lines
|
|
|
|
|
|
|
|
|
|
-let rec run_commands ?(echo_cmd = true) cmds =
|
|
|
|
|
+let rec run_commands ?(echo_cmd = true) ?help cmds =
|
|
|
|
|
let res = Array.make (List.length cmds) 0 in
|
|
|
|
|
let pids =
|
|
|
|
|
List.mapi (
|
|
|
|
|
@@ -482,21 +489,21 @@ let rec run_commands ?(echo_cmd = true) cmds =
|
|
|
|
|
let matching_pair = List.hd matching_pair in
|
|
|
|
|
let idx, _, app, outfd, errfd = matching_pair in
|
|
|
|
|
pids := new_pids;
|
|
|
|
|
- res.(idx) <- do_teardown app outfd errfd stat
|
|
|
|
|
+ res.(idx) <- do_teardown help app outfd errfd stat
|
|
|
|
|
);
|
|
|
|
|
done;
|
|
|
|
|
Array.to_list res
|
|
|
|
|
|
|
|
|
|
-and run_command ?(echo_cmd = true) ?stdout_fd ?stderr_fd args =
|
|
|
|
|
+and run_command ?(echo_cmd = true) ?help ?stdout_fd ?stderr_fd args =
|
|
|
|
|
let run_res = do_run args ~echo_cmd ?stdout_fd ?stderr_fd in
|
|
|
|
|
match run_res with
|
|
|
|
|
| Either (pid, app, outfd, errfd) ->
|
|
|
|
|
let _, stat = Unix.waitpid [] pid in
|
|
|
|
|
- do_teardown app outfd errfd stat
|
|
|
|
|
+ do_teardown help app outfd errfd stat
|
|
|
|
|
| Or code ->
|
|
|
|
|
code
|
|
|
|
|
|
|
|
|
|
-and do_run ?(echo_cmd = true) ?stdout_fd ?stderr_fd args =
|
|
|
|
|
+and do_run ?(echo_cmd = true) ?help ?stdout_fd ?stderr_fd args =
|
|
|
|
|
let app = List.hd args in
|
|
|
|
|
let get_fd default = function
|
|
|
|
|
| None ->
|
|
|
|
|
@@ -522,16 +529,18 @@ and do_run ?(echo_cmd = true) ?stdout_fd ?stderr_fd args =
|
|
|
|
|
debug "%s: %s: executable not found" app fn;
|
|
|
|
|
Or 127
|
|
|
|
|
|
|
|
|
|
-and do_teardown app outfd errfd exitstat =
|
|
|
|
|
+and do_teardown help app outfd errfd exitstat =
|
|
|
|
|
Option.iter Unix.close outfd;
|
|
|
|
|
Option.iter Unix.close errfd;
|
|
|
|
|
match exitstat with
|
|
|
|
|
| Unix.WEXITED i ->
|
|
|
|
|
- i
|
|
|
|
|
+ i
|
|
|
|
|
| Unix.WSIGNALED i ->
|
|
|
|
|
- error (f_"external command ‘%s’ killed by signal %d") app i
|
|
|
|
|
+ let reason = sprintf (f_"killed by signal %d") i in
|
|
|
|
|
+ external_command_failed help app reason
|
|
|
|
|
| Unix.WSTOPPED i ->
|
|
|
|
|
- error (f_"external command ‘%s’ stopped by signal %d") app i
|
|
|
|
|
+ let reason = sprintf (f_"stopped by signal %d") i in
|
|
|
|
|
+ external_command_failed help app reason
|
|
|
|
|
|
|
|
|
|
let shell_command ?(echo_cmd = true) cmd =
|
|
|
|
|
if echo_cmd then
|
|
|
|
|
diff --git a/common/mltools/tools_utils.mli b/common/mltools/tools_utils.mli
|
|
|
|
|
index ec900e63..193ba7b6 100644
|
|
|
|
|
--- a/common/mltools/tools_utils.mli
|
|
|
|
|
+++ b/common/mltools/tools_utils.mli
|
|
|
|
|
@@ -103,13 +103,17 @@ val create_standard_options : Getopt.speclist -> ?anon_fun:Getopt.anon_fun -> ?k
|
|
|
|
|
|
|
|
|
|
Returns a new {!cmdline_options} structure. *)
|
|
|
|
|
|
|
|
|
|
-val external_command : ?echo_cmd:bool -> string -> string list
|
|
|
|
|
+val external_command : ?echo_cmd:bool -> ?help:string -> string -> string list
|
|
|
|
|
(** Run an external command, slurp up the output as a list of lines.
|
|
|
|
|
|
|
|
|
|
[echo_cmd] specifies whether to output the full command on verbose
|
|
|
|
|
- mode, and it's on by default. *)
|
|
|
|
|
+ mode, and it's on by default.
|
|
|
|
|
|
|
|
|
|
-val run_commands : ?echo_cmd:bool -> (string list * Unix.file_descr option * Unix.file_descr option) list -> int list
|
|
|
|
|
+ [help] is an optional string which is printed as a prefix in
|
|
|
|
|
+ case the external command fails, eg as a hint to the user about
|
|
|
|
|
+ what we were trying to do. *)
|
|
|
|
|
+
|
|
|
|
|
+val run_commands : ?echo_cmd:bool -> ?help:string -> (string list * Unix.file_descr option * Unix.file_descr option) list -> int list
|
|
|
|
|
(** Run external commands in parallel without using a shell,
|
|
|
|
|
and return a list with their exit codes.
|
|
|
|
|
|
|
|
|
|
@@ -126,16 +130,24 @@ val run_commands : ?echo_cmd:bool -> (string list * Unix.file_descr option * Uni
|
|
|
|
|
end of the execution of the command for which it was specified.
|
|
|
|
|
|
|
|
|
|
[echo_cmd] specifies whether output the full command on verbose
|
|
|
|
|
- mode, and it's on by default. *)
|
|
|
|
|
+ mode, and it's on by default.
|
|
|
|
|
|
|
|
|
|
-val run_command : ?echo_cmd:bool -> ?stdout_fd:Unix.file_descr -> ?stderr_fd:Unix.file_descr -> string list -> int
|
|
|
|
|
+ [help] is an optional string which is printed as a prefix in
|
|
|
|
|
+ case the external command fails, eg as a hint to the user about
|
|
|
|
|
+ what we were trying to do. *)
|
|
|
|
|
+
|
|
|
|
|
+val run_command : ?echo_cmd:bool -> ?help:string -> ?stdout_fd:Unix.file_descr -> ?stderr_fd:Unix.file_descr -> string list -> int
|
|
|
|
|
(** Run an external command without using a shell, and return its exit code.
|
|
|
|
|
|
|
|
|
|
If [stdout_fd] or [stderr_fd] is specified, the file descriptor
|
|
|
|
|
is automatically closed after executing the command.
|
|
|
|
|
|
|
|
|
|
[echo_cmd] specifies whether output the full command on verbose
|
|
|
|
|
- mode, and it's on by default. *)
|
|
|
|
|
+ mode, and it's on by default.
|
|
|
|
|
+
|
|
|
|
|
+ [help] is an optional string which is printed as a prefix in
|
|
|
|
|
+ case the external command fails, eg as a hint to the user about
|
|
|
|
|
+ what we were trying to do. *)
|
|
|
|
|
|
|
|
|
|
val shell_command : ?echo_cmd:bool -> string -> int
|
|
|
|
|
(** Run an external shell command, and return its exit code.
|
|
|
|
|
diff --git a/generator/customize.ml b/generator/customize.ml
|
|
|
|
|
index aa7ac8e8..8d3dec3e 100644
|
|
|
|
|
--- a/generator/customize.ml
|
|
|
|
|
+++ b/generator/customize.ml
|
|
|
|
|
@@ -95,6 +95,34 @@ I<Note>: C<PERMISSIONS> by default would be decimal, unless you prefix
|
|
|
|
|
it with C<0> to get octal, ie. use C<0700> not C<700>.";
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
+ { op_name = "chown";
|
|
|
|
|
+ op_type = StringPair "UID.GID:PATH";
|
|
|
|
|
+ op_discrim = "`Chown";
|
|
|
|
|
+ op_shortdesc = "Change the owner user and group ID of a file or directory";
|
|
|
|
|
+ op_pod_longdesc = "\
|
|
|
|
|
+Change the owner user and group ID of a file or directory in the guest.
|
|
|
|
|
+Note:
|
|
|
|
|
+
|
|
|
|
|
+=over 4
|
|
|
|
|
+
|
|
|
|
|
+=item *
|
|
|
|
|
+
|
|
|
|
|
+Only numeric UIDs and GIDs will work, and these may not be the same
|
|
|
|
|
+inside the guest as on the host.
|
|
|
|
|
+
|
|
|
|
|
+=item *
|
|
|
|
|
+
|
|
|
|
|
+This will not work with Windows guests.
|
|
|
|
|
+
|
|
|
|
|
+=back
|
|
|
|
|
+
|
|
|
|
|
+For example:
|
|
|
|
|
+
|
|
|
|
|
+ virt-customize --chown '0.0:/var/log/audit.log'
|
|
|
|
|
+
|
|
|
|
|
+See also: I<--upload>.";
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
{ op_name = "commands-from-file";
|
|
|
|
|
op_type = StringFn ("FILENAME", "customize_read_from_file");
|
|
|
|
|
op_discrim = "`CommandsFromFile";
|