On Sun, Apr 22, 2012 at 09:21:02PM +0800, Wanlong Gao wrote: > Remove user accounts from /etc/passwd, /etc/group, > /etc/shadow, and the home directory of the user, > except the root user.
I wrote a small patch last night to implement the 'enabled_by_default' feature. See the attachment. If applied, it would require minor changes to your new operation. Rich. > Signed-off-by: Wanlong Gao <[email protected]> > --- > sysprep/Makefile.am | 2 + > sysprep/sysprep_operation_user_account.ml | 71 > +++++++++++++++++++++++++++++ > 2 files changed, 73 insertions(+) > create mode 100644 sysprep/sysprep_operation_user_account.ml > > diff --git a/sysprep/Makefile.am b/sysprep/Makefile.am > index f51fc07..9b06804 100644 > --- a/sysprep/Makefile.am > +++ b/sysprep/Makefile.am > @@ -48,6 +48,7 @@ SOURCES = \ > sysprep_operation_ssh_hostkeys.ml \ > sysprep_operation_ssh_userdir.ml \ > sysprep_operation_udev_persistent_net.ml \ > + sysprep_operation_user_account.ml \ > sysprep_operation_utmp.ml \ > sysprep_operation_yum_uuid.ml \ > utils.ml > @@ -73,6 +74,7 @@ OBJECTS = \ > sysprep_operation_ssh_hostkeys.cmx \ > sysprep_operation_ssh_userdir.cmx \ > sysprep_operation_udev_persistent_net.cmx \ > + sysprep_operation_user_account.ml \ > sysprep_operation_utmp.cmx \ > sysprep_operation_yum_uuid.cmx \ > main.cmx > diff --git a/sysprep/sysprep_operation_user_account.ml > b/sysprep/sysprep_operation_user_account.ml > new file mode 100644 > index 0000000..45c05d7 > --- /dev/null > +++ b/sysprep/sysprep_operation_user_account.ml > @@ -0,0 +1,71 @@ > +(* virt-sysprep > + * Copyright (C) 2012 FUJITSU LIMITED > + * > + * 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. > + *) > + > +open Sysprep_operation > +open Utils > + > +module G = Guestfs > + > +let user_account_perform g root = > + let typ = g#inspect_get_type root in > + if typ <> "windows" then ( > + g#aug_init "/" 0; > + let uid_min = g#aug_get "/files/etc/login.defs/UID_MIN" in > + let uid_max = g#aug_get "/files/etc/login.defs/UID_MAX" in > + let users = Array.to_list (g#aug_ls "/files/etc/passwd") in > + List.iter ( > + fun user -> > + let uid = user ^ "/uid" in > + let uid = g#aug_get uid in > + if int_of_string uid >= int_of_string uid_min then ( > + if int_of_string uid <= int_of_string uid_max then ( > + let user' = Array.of_list (string_split "/" user) in > + let user = user'.(4) in > + let user_prefix = user ^ ":" in > + let filenames = [ "/etc/passwd"; > + "/etc/shadow"; > + "/etc/group" ] in > + List.iter ( > + fun filename -> > + let lines = Array.to_list (g#read_lines filename) in > + let lines = List.filter ( > + fun line -> not (string_prefix line user_prefix) > + ) lines in > + let file = String.concat "\n" lines ^ "\n" in > + g#write filename file > + ) filenames; > + g#rm_rf ("/home/" ^ user); > + ) > + ) > + ) users; > + [] > + ) > + else [] > + > +let user_account_op = { > + name = "user-account"; > + pod_description = "\ > +Remove the user accounts except \"root\" in the guest. > + > +Remove the user accounts and their home directory except > +the \"root\" account."; > + extra_args = []; > + perform = user_account_perform; > +} > + > +let () = register_operation user_account_op > -- > 1.7.10 -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org
From 8d41470b6fc81b742896996393812b274514bca2 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" <[email protected]> Date: Sat, 21 Apr 2012 22:27:39 +0100 Subject: [PATCH] sysprep: Don't enable every option by default. All current operations are enabled by default. Also: * The POD description is split into a heading and the description body. * An 'enabled_by_default' flag is added to the structure. --- sysprep/sysprep_operation.ml | 70 +++++++++++++++------- sysprep/sysprep_operation.mli | 11 +++- sysprep/sysprep_operation_bash_history.ml | 6 +- sysprep/sysprep_operation_cron_spool.ml | 4 +- sysprep/sysprep_operation_dhcp_client_state.ml | 4 +- sysprep/sysprep_operation_dhcp_server_state.ml | 4 +- sysprep/sysprep_operation_hostname.ml | 8 ++- sysprep/sysprep_operation_logfiles.ml | 9 ++- sysprep/sysprep_operation_mail_spool.ml | 4 +- sysprep/sysprep_operation_net_hwaddr.ml | 8 ++- sysprep/sysprep_operation_random_seed.ml | 4 +- sysprep/sysprep_operation_rhn_systemid.ml | 4 +- sysprep/sysprep_operation_script.ml | 4 +- sysprep/sysprep_operation_smolt_uuid.ml | 4 +- sysprep/sysprep_operation_ssh_hostkeys.ml | 6 +- sysprep/sysprep_operation_ssh_userdir.ml | 6 +- sysprep/sysprep_operation_udev_persistent_net.ml | 4 +- sysprep/sysprep_operation_utmp.ml | 6 +- sysprep/sysprep_operation_yum_uuid.ml | 6 +- sysprep/virt-sysprep.pod | 40 ++++++++++--- 20 files changed, 148 insertions(+), 64 deletions(-) diff --git a/sysprep/sysprep_operation.ml b/sysprep/sysprep_operation.ml index b48d8f8..d3a12fe 100644 --- a/sysprep/sysprep_operation.ml +++ b/sysprep/sysprep_operation.ml @@ -24,12 +24,15 @@ type flag = [ `Created_files ] type operation = { name : string; - pod_description : string; + enabled_by_default : bool; + heading : string; + pod_description : string option; extra_args : ((Arg.key * Arg.spec * Arg.doc) * string) list; perform : Guestfs.guestfs -> string -> flag list; } -let ops = ref [] +let all_operations = ref [] +let enabled_by_default_operations = ref [] module OperationSet = Set.Make ( struct @@ -42,17 +45,21 @@ type set = OperationSet.t let empty_set = OperationSet.empty let add_to_set name set = - let op = List.find (fun { name = n } -> name = n) !ops in + let op = List.find (fun { name = n } -> name = n) !all_operations in OperationSet.add op set -let register_operation op = ops := op :: !ops +let register_operation op = + all_operations := op :: !all_operations; + if op.enabled_by_default then + enabled_by_default_operations := op :: !enabled_by_default_operations let baked = ref false let rec bake () = - let ops' = List.sort (fun { name = a } { name = b } -> compare a b) !ops in - check_no_dupes ops'; - List.iter check ops'; - ops := ops'; + let ops = + List.sort (fun { name = a } { name = b } -> compare a b) !all_operations in + check_no_dupes ops; + List.iter check ops; + all_operations := ops; baked := true and check_no_dupes ops = ignore ( @@ -78,14 +85,28 @@ and check op = eprintf "virt-sysprep: disallowed character (%c) in operation name\n" c; exit 1 done; - let n = String.length op.pod_description in + let n = String.length op.heading in if n = 0 then ( - eprintf "virt-sysprep: operation %s has no POD\n" op.name; + eprintf "virt-sysprep: operation %s has no heading\n" op.name; exit 1 ); - if op.pod_description.[n-1] = '\n' then ( - eprintf "virt-sysprep: POD for %s must not end with newline\n" op.name; + if op.heading.[n-1] = '\n' || op.heading.[n-1] = '.' then ( + eprintf "virt-sysprep: heading for %s must not end with newline or period\n" + op.name; exit 1 + ); + (match op.pod_description with + | None -> () + | Some description -> + let n = String.length description in + if n = 0 then ( + eprintf "virt-sysprep: operation %s has no POD\n" op.name; + exit 1 + ); + if description.[n-1] = '\n' then ( + eprintf "virt-sysprep: POD for %s must not end with newline\n" op.name; + exit 1 + ) ) let extra_args () = @@ -94,7 +115,7 @@ let extra_args () = List.flatten ( List.map (fun { extra_args = extra_args } -> List.map fst extra_args - ) !ops + ) !all_operations ) (* These internal functions are used to generate the man page. *) @@ -104,9 +125,14 @@ let dump_pod () = List.iter ( fun op -> printf "=head2 B<%s>\n" op.name; + if op.enabled_by_default then printf "*\n"; printf "\n"; - printf "%s\n\n" op.pod_description - ) !ops + printf "%s.\n\n" op.heading; + (match op.pod_description with + | None -> () + | Some description -> printf "%s\n\n" description + ) + ) !all_operations let dump_pod_options () = assert !baked; @@ -114,7 +140,7 @@ let dump_pod_options () = let args = List.map ( fun { name = op_name; extra_args = extra_args } -> List.map (fun ea -> op_name, ea) extra_args - ) !ops in + ) !all_operations in let args = List.flatten args in let args = List.map ( fun (op_name, ((arg_name, spec, _), pod)) -> @@ -152,17 +178,19 @@ let dump_pod_options () = let list_operations () = assert !baked; - (* For compatibility with old shell version, list just the operation - * names, sorted. - *) - List.iter (fun op -> print_endline op.name ) !ops + List.iter ( + fun op -> + printf "%s %s %s\n" op.name + (if op.enabled_by_default then "*" else " ") + op.heading + ) !all_operations let perform_operations ?operations ?(quiet = false) g root = assert !baked; let ops = match operations with - | None -> !ops (* all operations *) + | None -> !enabled_by_default_operations | Some opset -> (* just the operation names listed *) OperationSet.elements opset in diff --git a/sysprep/sysprep_operation.mli b/sysprep/sysprep_operation.mli index 0f58510..ab7da93 100644 --- a/sysprep/sysprep_operation.mli +++ b/sysprep/sysprep_operation.mli @@ -26,8 +26,15 @@ type operation = { line. Must contain only alphanumeric and '-' (dash) character. *) - pod_description : string; - (** POD-format description, used for the man page. *) + enabled_by_default : bool; + (** If true, then enabled by default when no [--enable] option is + given on the command line. *) + + heading : string; + (** One-line description, NO trailing period. *) + + pod_description : string option; + (** POD-format long description, used for the man page. *) extra_args : ((Arg.key * Arg.spec * Arg.doc) * string) list; (** Extra command-line arguments, if any. eg. The [hostname] diff --git a/sysprep/sysprep_operation_bash_history.ml b/sysprep/sysprep_operation_bash_history.ml index 4367973..dbd6c50 100644 --- a/sysprep/sysprep_operation_bash_history.ml +++ b/sysprep/sysprep_operation_bash_history.ml @@ -34,9 +34,9 @@ let bash_history_perform g root = let bash_history_op = { name = "bash-history"; - pod_description = "\ -Remove the bash history in the guest. - + enabled_by_default = true; + heading = "Remove the bash history in the guest"; + pod_description = Some "\ Remove the bash history of user \"root\" and any other users who have a C<.bash_history> file in their home directory."; extra_args = []; diff --git a/sysprep/sysprep_operation_cron_spool.ml b/sysprep/sysprep_operation_cron_spool.ml index e67688b..daa3c68 100644 --- a/sysprep/sysprep_operation_cron_spool.ml +++ b/sysprep/sysprep_operation_cron_spool.ml @@ -26,7 +26,9 @@ let cron_spool_perform g root = let cron_spool_op = { name = "cron-spool"; - pod_description = "Remove user at-jobs and cron-jobs."; + enabled_by_default = true; + heading = "Remove user at-jobs and cron-jobs"; + pod_description = None; extra_args = []; perform = cron_spool_perform; } diff --git a/sysprep/sysprep_operation_dhcp_client_state.ml b/sysprep/sysprep_operation_dhcp_client_state.ml index e3e87cb..279893d 100644 --- a/sysprep/sysprep_operation_dhcp_client_state.ml +++ b/sysprep/sysprep_operation_dhcp_client_state.ml @@ -31,7 +31,9 @@ let dhcp_client_state_perform g root = let dhcp_client_state_op = { name = "dhcp-client-state"; - pod_description = "Remove DHCP client leases."; + enabled_by_default = true; + heading = "Remove DHCP client leases"; + pod_description = None; extra_args = []; perform = dhcp_client_state_perform; } diff --git a/sysprep/sysprep_operation_dhcp_server_state.ml b/sysprep/sysprep_operation_dhcp_server_state.ml index c5251ce..b28aa69 100644 --- a/sysprep/sysprep_operation_dhcp_server_state.ml +++ b/sysprep/sysprep_operation_dhcp_server_state.ml @@ -26,7 +26,9 @@ let dhcp_server_state_perform g root = let dhcp_server_state_op = { name = "dhcp-server-state"; - pod_description = "Remove DHCP server leases."; + enabled_by_default = true; + heading = "Remove DHCP server leases"; + pod_description = None; extra_args = []; perform = dhcp_server_state_perform; } diff --git a/sysprep/sysprep_operation_hostname.ml b/sysprep/sysprep_operation_hostname.ml index 51f9386..395691c 100644 --- a/sysprep/sysprep_operation_hostname.ml +++ b/sysprep/sysprep_operation_hostname.ml @@ -52,9 +52,11 @@ let hostname_perform g root = let hostname_op = { name = "hostname"; - pod_description = "\ -Changes the hostname of the guest to the value given in the I<--hostname> -parameter. + enabled_by_default = true; + heading = "Change the hostname of the guest"; + pod_description = Some "\ +This operation changes the hostname of the guest to the value +given in the I<--hostname> parameter. If the I<--hostname> parameter is not given, then the hostname is changed to C<localhost.localdomain>."; diff --git a/sysprep/sysprep_operation_logfiles.ml b/sysprep/sysprep_operation_logfiles.ml index b4c6ea9..2ad3726 100644 --- a/sysprep/sysprep_operation_logfiles.ml +++ b/sysprep/sysprep_operation_logfiles.ml @@ -59,10 +59,13 @@ let logfiles_perform g root = let logfiles_op = { name = "logfiles"; - pod_description = sprintf "\ -Remove many log files. On Linux the following files are removed: + enabled_by_default = true; + heading = "Remove many log files from the guest"; + pod_description = Some ( + sprintf "\ +On Linux the following files are removed: -%s" globs_as_pod; +%s" globs_as_pod); extra_args = []; perform = logfiles_perform; } diff --git a/sysprep/sysprep_operation_mail_spool.ml b/sysprep/sysprep_operation_mail_spool.ml index 74f2d94..25f4272 100644 --- a/sysprep/sysprep_operation_mail_spool.ml +++ b/sysprep/sysprep_operation_mail_spool.ml @@ -31,7 +31,9 @@ let mail_spool_perform g root = let mail_spool_op = { name = "mail-spool"; - pod_description = "Remove email from the local mail spool directory."; + enabled_by_default = true; + heading = "Remove email from the local mail spool directory"; + pod_description = None; extra_args = []; perform = mail_spool_perform; } diff --git a/sysprep/sysprep_operation_net_hwaddr.ml b/sysprep/sysprep_operation_net_hwaddr.ml index 02e3b5e..57ca2b9 100644 --- a/sysprep/sysprep_operation_net_hwaddr.ml +++ b/sysprep/sysprep_operation_net_hwaddr.ml @@ -44,9 +44,11 @@ let net_hwaddr_perform g root = let net_hwaddr_op = { name = "net-hwaddr"; - pod_description = "\ -Remove HWADDR (hard-coded MAC address) configuration. For Fedora and -Red Hat Enterprise Linux, this is removed from C<ifcfg-*> files."; + enabled_by_default = true; + heading = "Remove HWADDR (hard-coded MAC address) configuration"; + pod_description = Some "\ +For Fedora and Red Hat Enterprise Linux, +this is removed from C<ifcfg-*> files."; extra_args = []; perform = net_hwaddr_perform; } diff --git a/sysprep/sysprep_operation_random_seed.ml b/sysprep/sysprep_operation_random_seed.ml index 989ffe8..c6e8d85 100644 --- a/sysprep/sysprep_operation_random_seed.ml +++ b/sysprep/sysprep_operation_random_seed.ml @@ -45,7 +45,9 @@ let random_seed_perform g root = let random_seed_op = { name = "random-seed"; - pod_description = "\ + enabled_by_default = true; + heading = "Generate random seed for guest"; + pod_description = Some "\ Write some random bytes from the host into the random seed file of the guest. diff --git a/sysprep/sysprep_operation_rhn_systemid.ml b/sysprep/sysprep_operation_rhn_systemid.ml index 35849e4..9d9f2f8 100644 --- a/sysprep/sysprep_operation_rhn_systemid.ml +++ b/sysprep/sysprep_operation_rhn_systemid.ml @@ -32,7 +32,9 @@ let rhn_systemid_perform g root = let rhn_systemid_op = { name = "rhn-systemid"; - pod_description = "Remove the RHN system ID."; + enabled_by_default = true; + heading = "Remove the RHN system ID"; + pod_description = None; extra_args = []; perform = rhn_systemid_perform; } diff --git a/sysprep/sysprep_operation_script.ml b/sysprep/sysprep_operation_script.ml index 977d41f..bcbba73 100644 --- a/sysprep/sysprep_operation_script.ml +++ b/sysprep/sysprep_operation_script.ml @@ -113,7 +113,9 @@ trap cleanup INT TERM QUIT EXIT ERR\n" let script_op = { name = "script"; - pod_description = "\ + enabled_by_default = true; + heading = "Run arbitrary scripts against the guest"; + pod_description = Some "\ The C<script> module lets you run arbitrary shell scripts or programs against the guest. diff --git a/sysprep/sysprep_operation_smolt_uuid.ml b/sysprep/sysprep_operation_smolt_uuid.ml index a85aa9b..85e788e 100644 --- a/sysprep/sysprep_operation_smolt_uuid.ml +++ b/sysprep/sysprep_operation_smolt_uuid.ml @@ -36,7 +36,9 @@ let smolt_uuid_perform g root = let smolt_uuid_op = { name = "smolt-uuid"; - pod_description = "Remove the Smolt hardware UUID."; + enabled_by_default = true; + heading = "Remove the Smolt hardware UUID"; + pod_description = None; extra_args = []; perform = smolt_uuid_perform; } diff --git a/sysprep/sysprep_operation_ssh_hostkeys.ml b/sysprep/sysprep_operation_ssh_hostkeys.ml index 8da405b..db45b44 100644 --- a/sysprep/sysprep_operation_ssh_hostkeys.ml +++ b/sysprep/sysprep_operation_ssh_hostkeys.ml @@ -31,9 +31,9 @@ let ssh_hostkeys_perform g root = let ssh_hostkeys_op = { name = "ssh-hostkeys"; - pod_description = "\ -Remove the SSH host keys in the guest. - + enabled_by_default = true; + heading = "Remove the SSH host keys in the guest"; + pod_description = Some "\ The SSH host keys are regenerated (differently) next time the guest is booted. diff --git a/sysprep/sysprep_operation_ssh_userdir.ml b/sysprep/sysprep_operation_ssh_userdir.ml index 962ea8b..9ea1017 100644 --- a/sysprep/sysprep_operation_ssh_userdir.ml +++ b/sysprep/sysprep_operation_ssh_userdir.ml @@ -34,9 +34,9 @@ let ssh_userdir_perform g root = let ssh_userdir_op = { name = "ssh-userdir"; - pod_description = "\ -Remove C<.ssh> directories in the guest. - + enabled_by_default = true; + heading = "Remove \".ssh\" directories in the guest"; + pod_description = Some "\ Remove the C<.ssh> directory of user \"root\" and any other users who have a C<.ssh> directory in their home directory."; extra_args = []; diff --git a/sysprep/sysprep_operation_udev_persistent_net.ml b/sysprep/sysprep_operation_udev_persistent_net.ml index e54e140..95133d1 100644 --- a/sysprep/sysprep_operation_udev_persistent_net.ml +++ b/sysprep/sysprep_operation_udev_persistent_net.ml @@ -31,7 +31,9 @@ let udev_persistent_net_perform g root = let udev_persistent_net_op = { name = "udev-persistent-net"; - pod_description = "\ + enabled_by_default = true; + heading = "Remove udev persistent net rules"; + pod_description = Some "\ Remove udev persistent net rules which map the guest's existing MAC address to a fixed ethernet device (eg. eth0). diff --git a/sysprep/sysprep_operation_utmp.ml b/sysprep/sysprep_operation_utmp.ml index 69867e1..cdcf01f 100644 --- a/sysprep/sysprep_operation_utmp.ml +++ b/sysprep/sysprep_operation_utmp.ml @@ -30,9 +30,9 @@ let utmp_perform g root = let utmp_op = { name = "utmp"; - pod_description = "\ -Remove the utmp file. - + enabled_by_default = true; + heading = "Remove the utmp file"; + pod_description = Some "\ This file records who is currently logged in on a machine. In modern Linux distros it is stored in a ramdisk and hence not part of the virtual machine's disk, but it was stored on disk in older distros."; diff --git a/sysprep/sysprep_operation_yum_uuid.ml b/sysprep/sysprep_operation_yum_uuid.ml index 396cac5..cc5fec1 100644 --- a/sysprep/sysprep_operation_yum_uuid.ml +++ b/sysprep/sysprep_operation_yum_uuid.ml @@ -30,9 +30,9 @@ let yum_uuid_perform g root = let yum_uuid_op = { name = "yum-uuid"; - pod_description = "\ -Remove the yum UUID. - + enabled_by_default = true; + heading = "Remove the yum UUID"; + pod_description = Some "\ Yum creates a fresh UUID the next time it runs when it notices that the original UUID has been erased."; extra_args = []; diff --git a/sysprep/virt-sysprep.pod b/sysprep/virt-sysprep.pod index a8cffb6..e5b89dc 100755 --- a/sysprep/virt-sysprep.pod +++ b/sysprep/virt-sysprep.pod @@ -86,8 +86,11 @@ list of operations, for example: would enable ONLY C<ssh-hostkeys> and C<udev-persistent-net> operations. -If the I<--enable> option is not given, then we default to trying all -possible sysprep operations. But some sysprep operations are skipped +If the I<--enable> option is not given, then we default to trying most +sysprep operations (see I<--list-operations> to show which are +enabled). + +Regardless of the I<--enable> option, sysprep operations are skipped for some guest types. Use I<--list-operations> to list operations supported by a particular @@ -124,6 +127,24 @@ security problem with malicious guests (CVE-2010-3851). List the operations supported by the virt-sysprep program. +These are listed one per line, with one or more single-space-separated +fields, eg: + + $ virt-sysprep --list-operations + bash-history * Remove the bash history in the guest + cron-spool * Remove user at-jobs and cron-jobs + dhcp-client-state * Remove DHCP client leases + dhcp-server-state * Remove DHCP server leases + [etc] + +The first field is the operation name, which can be supplied +to I<--enable>. The second field is a C<*> character if the +operation is enabled by default or blank if not. Subsequent +fields on the same line are the description of the operation. + +Before libguestfs 1.17.33 only the first (operation name) field was +shown and all operations were enabled by default. + =item B<-q> =item B<--quiet> @@ -164,22 +185,25 @@ Enable tracing of libguestfs API calls. =head1 OPERATIONS -If the I<--enable> option is I<not> given, then -I<all sysprep operations are enabled>, although some are skipped -depending on the type of guest. +If the I<--enable> option is I<not> given, then most sysprep +operations are enabled. + +Use C<virt-sysprep --list-operations> to list all operations for your +virt-sysprep binary. The ones which are enabled by default are marked +with a C<*> character. Regardless of the I<--enable> option, sysprep +operations are skipped for some guest types. Operations can be individually enabled using the I<--enable> option. Use a comma-separated list, for example: virt-sysprep --enable=ssh-hostkeys,udev-persistent-net [etc..] -To list the operations supported by the current version of -virt-sysprep, use I<--list-operations>. - Future versions of virt-sysprep may add more operations. If you are using virt-sysprep and want predictable behaviour, specify only the operations that you want to have enabled. +C<*> = enabled by default when no I<--enable> option is given. + @OPERATIONS@ =head1 COPYING AND CLONING -- 1.7.9.3
_______________________________________________ Libguestfs mailing list [email protected] https://www.redhat.com/mailman/listinfo/libguestfs
