mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
This command run over the source: perl -pi.bak -e 's/(20[01][0-9])-2018/$1-2019/g' `git ls-files`
335 lines
12 KiB
OCaml
335 lines
12 KiB
OCaml
(* virt-builder
|
||
* Copyright (C) 2013-2019 Red Hat Inc.
|
||
*
|
||
* This program is free software; you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation; either version 2 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License along
|
||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
*)
|
||
|
||
(* Command line argument parsing. *)
|
||
|
||
open Std_utils
|
||
open Tools_utils
|
||
open Common_gettext.Gettext
|
||
open Getopt.OptionName
|
||
|
||
open Customize_cmdline
|
||
|
||
open Utils
|
||
|
||
module G = Guestfs
|
||
|
||
open Unix
|
||
open Printf
|
||
|
||
type cmdline = {
|
||
mode : [ `Cache_all | `Delete_cache | `Get_kernel | `Install | `List
|
||
| `Notes | `Print_cache ];
|
||
arg : string;
|
||
arch : string;
|
||
attach : (string option * string) list;
|
||
cache : string option;
|
||
check_signature : bool;
|
||
curl : string;
|
||
customize_ops : Customize_cmdline.ops;
|
||
delete_on_failure : bool;
|
||
format : string option;
|
||
gpg : string;
|
||
list_format : List_entries.format;
|
||
memsize : int option;
|
||
network : bool;
|
||
output : string option;
|
||
size : int64 option;
|
||
smp : int option;
|
||
sources : (string * string) list;
|
||
sync : bool;
|
||
warn_if_partition : bool;
|
||
}
|
||
|
||
let parse_cmdline () =
|
||
let mode = ref `Install in
|
||
let list_mode () = mode := `List in
|
||
let notes_mode () = mode := `Notes in
|
||
let get_kernel_mode () = mode := `Get_kernel in
|
||
let cache_all_mode () = mode := `Cache_all in
|
||
let print_cache_mode () = mode := `Print_cache in
|
||
let delete_cache_mode () = mode := `Delete_cache in
|
||
|
||
let arch = ref "" in
|
||
|
||
let attach = ref [] in
|
||
let attach_format = ref None in
|
||
let set_attach_format = function
|
||
| "auto" -> attach_format := None
|
||
| s -> attach_format := Some s
|
||
in
|
||
let attach_disk s = List.push_front (!attach_format, s) attach in
|
||
|
||
let cache = ref Paths.xdg_cache_home in
|
||
let set_cache arg = cache := Some arg in
|
||
let no_cache () = cache := None in
|
||
|
||
let check_signature = ref true in
|
||
let curl = ref "curl" in
|
||
|
||
let delete_on_failure = ref true in
|
||
|
||
let fingerprints = ref [] in
|
||
let add_fingerprint arg = List.push_front arg fingerprints in
|
||
|
||
let format = ref "" in
|
||
let gpg =
|
||
try which "gpg2"
|
||
with Executable_not_found _ ->
|
||
try which "gpg"
|
||
with Executable_not_found _ ->
|
||
"" in
|
||
let gpg = ref gpg in
|
||
|
||
let list_format = ref List_entries.Short in
|
||
let list_set_long () = list_format := List_entries.Long in
|
||
let list_set_format arg =
|
||
(* Do not catch the Invalid_argument that list_format_of_string
|
||
* throws on invalid input, as it is already checked by the
|
||
* Getopt handling of Symbol. *)
|
||
list_format := List_entries.list_format_of_string arg in
|
||
|
||
let memsize = ref None in
|
||
let set_memsize arg = memsize := Some arg in
|
||
|
||
let network = ref true in
|
||
let output = ref "" in
|
||
|
||
let size = ref None in
|
||
let set_size arg = size := Some (parse_size arg) in
|
||
|
||
let smp = ref None in
|
||
let set_smp arg = smp := Some arg in
|
||
|
||
let sources = ref [] in
|
||
let add_source arg = List.push_front arg sources in
|
||
|
||
let sync = ref true in
|
||
let warn_if_partition = ref true in
|
||
|
||
let formats = List_entries.list_formats
|
||
and formats_string = String.concat "|" List_entries.list_formats in
|
||
|
||
let argspec = [
|
||
[ L"arch" ], Getopt.Set_string ("arch", arch), s_"Set the output architecture";
|
||
[ L"attach" ], Getopt.String ("iso", attach_disk), s_"Attach data disk/ISO during install";
|
||
[ L"attach-format" ], Getopt.String ("format", set_attach_format),
|
||
s_"Set attach disk format";
|
||
[ L"cache" ], Getopt.String ("dir", set_cache), s_"Set template cache dir";
|
||
[ L"no-cache" ], Getopt.Unit no_cache, s_"Disable template cache";
|
||
[ L"cache-all-templates" ], Getopt.Unit cache_all_mode,
|
||
s_"Download all templates to the cache";
|
||
[ L"check-signature"; L"check-signatures" ], Getopt.Set check_signature,
|
||
s_"Check digital signatures";
|
||
[ L"no-check-signature"; L"no-check-signatures" ], Getopt.Clear check_signature,
|
||
s_"Disable digital signatures";
|
||
[ L"curl" ], Getopt.Set_string ("curl", curl), s_"Set curl binary/command";
|
||
[ L"delete-cache" ], Getopt.Unit delete_cache_mode,
|
||
s_"Delete the template cache";
|
||
[ L"no-delete-on-failure" ], Getopt.Clear delete_on_failure,
|
||
s_"Don’t delete output file on failure";
|
||
[ L"fingerprint" ], Getopt.String ("AAAA..", add_fingerprint),
|
||
s_"Fingerprint of valid signing key";
|
||
[ L"format" ], Getopt.Set_string ("raw|qcow2", format), s_"Output format (default: raw)";
|
||
[ L"get-kernel" ], Getopt.Unit get_kernel_mode,
|
||
s_"Get kernel from image";
|
||
[ L"gpg" ], Getopt.Set_string ("gpg", gpg), s_"Set GPG binary/command";
|
||
[ S 'l'; L"list" ], Getopt.Unit list_mode, s_"List available templates";
|
||
[ L"long" ], Getopt.Unit list_set_long, s_"Shortcut for --list-format long";
|
||
[ L"list-format" ], Getopt.Symbol (formats_string, formats, list_set_format),
|
||
s_"Set the format for --list (default: short)";
|
||
[ S 'm'; L"memsize" ], Getopt.Int ("mb", set_memsize), s_"Set memory size";
|
||
[ L"network" ], Getopt.Set network, s_"Enable appliance network (default)";
|
||
[ L"no-network" ], Getopt.Clear network, s_"Disable appliance network";
|
||
[ L"notes" ], Getopt.Unit notes_mode, s_"Display installation notes";
|
||
[ S 'o'; L"output" ], Getopt.Set_string ("file", output), s_"Set output filename";
|
||
[ L"print-cache" ], Getopt.Unit print_cache_mode,
|
||
s_"Print info about template cache";
|
||
[ L"size" ], Getopt.String ("size", set_size), s_"Set output disk size";
|
||
[ L"smp" ], Getopt.Int ("vcpus", set_smp), s_"Set number of vCPUs";
|
||
[ L"source" ], Getopt.String ("URL", add_source), s_"Set source URL";
|
||
[ L"no-sync" ], Getopt.Clear sync, s_"Do not fsync output file on exit";
|
||
[ L"no-warn-if-partition" ], Getopt.Clear warn_if_partition,
|
||
s_"Do not warn if writing to a partition";
|
||
] in
|
||
let customize_argspec, get_customize_ops = Customize_cmdline.argspec () in
|
||
let customize_argspec =
|
||
List.map (fun (spec, _, _) -> spec) customize_argspec in
|
||
let argspec = argspec @ customize_argspec in
|
||
|
||
let args = ref [] in
|
||
let anon_fun s = List.push_front s args in
|
||
let usage_msg =
|
||
sprintf (f_"\
|
||
%s: build virtual machine images quickly
|
||
|
||
virt-builder OS-VERSION
|
||
virt-builder -l
|
||
virt-builder --notes OS-VERSION
|
||
virt-builder --print-cache
|
||
virt-builder --cache-all-templates
|
||
virt-builder --delete-cache
|
||
virt-builder --get-kernel IMAGE
|
||
|
||
A short summary of the options is given below. For detailed help please
|
||
read the man page virt-builder(1).
|
||
")
|
||
prog in
|
||
let opthandle = create_standard_options argspec ~anon_fun ~machine_readable:true usage_msg in
|
||
Getopt.parse opthandle.getopt;
|
||
|
||
(* Dereference options. *)
|
||
let args = List.rev !args in
|
||
let mode = !mode in
|
||
let arch = !arch in
|
||
let attach = List.rev !attach in
|
||
let cache = !cache in
|
||
let check_signature = !check_signature in
|
||
let curl = !curl in
|
||
let delete_on_failure = !delete_on_failure in
|
||
let fingerprints = List.rev !fingerprints in
|
||
let format = match !format with "" -> None | s -> Some s in
|
||
let gpg = !gpg in
|
||
let list_format = !list_format in
|
||
let memsize = !memsize in
|
||
let network = !network in
|
||
let ops = get_customize_ops () in
|
||
let output = match !output with "" -> None | s -> Some s in
|
||
let size = !size in
|
||
let smp = !smp in
|
||
let sources = List.rev !sources in
|
||
let sync = !sync in
|
||
let warn_if_partition = !warn_if_partition in
|
||
|
||
(* No arguments and machine-readable mode? Print some facts. *)
|
||
(match args, machine_readable () with
|
||
| [], Some { pr } ->
|
||
pr "virt-builder\n";
|
||
pr "arch\n";
|
||
pr "config-file\n";
|
||
pr "customize\n";
|
||
pr "json-list\n";
|
||
if Pxzcat.using_parallel_xzcat () then pr "pxzcat\n";
|
||
exit 0
|
||
| _, _ -> ()
|
||
);
|
||
|
||
(* Check options. *)
|
||
let arg =
|
||
match mode with
|
||
| `Install ->
|
||
(match args with
|
||
| [arg] -> arg
|
||
| [] ->
|
||
error (f_"virt-builder os-version\nMissing ‘os-version’. Use ‘--list’ to list available template names.")
|
||
| _ ->
|
||
error (f_"too many parameters, expecting ‘os-version’")
|
||
)
|
||
| `List ->
|
||
if format <> None then
|
||
error (f_"--list: use ‘--list-format’, not ‘--format’");
|
||
(match args with
|
||
| [arg] -> arg
|
||
| [] -> ""
|
||
| _ ->
|
||
error (f_"too many parameters, at most one ‘os-version’ is allowed for --list")
|
||
)
|
||
| `Notes ->
|
||
(match args with
|
||
| [arg] -> arg
|
||
| [] ->
|
||
error (f_"virt-builder --notes os-version\nMissing ‘os-version’. Use ‘--list’ to list available template names.")
|
||
| _ ->
|
||
error (f_"--notes: too many parameters, expecting ‘os-version’");
|
||
)
|
||
| `Cache_all
|
||
| `Print_cache
|
||
| `Delete_cache ->
|
||
(match args with
|
||
| [] -> ""
|
||
| _ ->
|
||
error (f_"--cache-all-templates/--print-cache/--delete-cache does not need any extra arguments")
|
||
)
|
||
| `Get_kernel ->
|
||
(match args with
|
||
| [arg] -> arg
|
||
| [] ->
|
||
error (f_"virt-builder --get-kernel image\nMissing ‘image’ (disk image file) argument")
|
||
| _ ->
|
||
error (f_"--get-kernel: too many parameters")
|
||
) in
|
||
|
||
(* Check source(s) and fingerprint(s). *)
|
||
let sources =
|
||
let rec repeat x = function
|
||
| 0 -> [] | 1 -> [x]
|
||
| n -> x :: repeat x (n-1)
|
||
in
|
||
|
||
let nr_sources = List.length sources in
|
||
let fingerprints =
|
||
if check_signature then (
|
||
match fingerprints with
|
||
| [fingerprint] ->
|
||
(* You're allowed to have multiple sources and one fingerprint: it
|
||
* means that the same fingerprint is used for all sources.
|
||
*)
|
||
repeat fingerprint nr_sources
|
||
| xs -> xs
|
||
) else
|
||
(* We are not checking signatures, so just ignore any fingerprint
|
||
* specified. *)
|
||
repeat "" nr_sources in
|
||
|
||
if List.length fingerprints <> nr_sources then
|
||
error (f_"source and fingerprint lists are not the same length");
|
||
|
||
(* Combine the sources and fingerprints into a single list of pairs. *)
|
||
List.combine sources fingerprints in
|
||
|
||
(* Check the architecture. *)
|
||
let arch =
|
||
match arch with
|
||
| "" -> Guestfs_config.host_cpu
|
||
| arch -> arch in
|
||
let arch = normalize_arch arch in
|
||
|
||
(* If user didn't elect any root password, that means we set a random
|
||
* root password.
|
||
*)
|
||
let customize_ops =
|
||
let has_set_root_password = List.exists (
|
||
function `RootPassword _ -> true | _ -> false
|
||
) ops.ops in
|
||
if has_set_root_password then ops
|
||
else (
|
||
let pw = Password.parse_selector "random" in
|
||
{ ops with ops = ops.ops @ [ `RootPassword pw ] }
|
||
) in
|
||
|
||
{ mode = mode; arg = arg;
|
||
arch = arch; attach = attach; cache = cache;
|
||
check_signature = check_signature; curl = curl;
|
||
customize_ops = customize_ops;
|
||
delete_on_failure = delete_on_failure; format = format;
|
||
gpg = gpg; list_format = list_format; memsize = memsize;
|
||
network = network; output = output;
|
||
size = size; smp = smp; sources = sources; sync = sync;
|
||
warn_if_partition = warn_if_partition;
|
||
}
|