diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-03-31 21:41:10 +0100 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-03-31 23:02:47 +0100 |
commit | ad43dde9c87a6c3d58c626d2fa42dd68c2e15e01 (patch) | |
tree | 2d5669db939a1c7d4e107d8ff8bbe4fcb8a818fd /sysprep | |
parent | 026f616650c41e42b7c3058a8637fe2d76bfb793 (diff) | |
download | libguestfs-ad43dde9c87a6c3d58c626d2fa42dd68c2e15e01.tar.gz libguestfs-ad43dde9c87a6c3d58c626d2fa42dd68c2e15e01.tar.xz libguestfs-ad43dde9c87a6c3d58c626d2fa42dd68c2e15e01.zip |
sysprep: Implement 'script' operation for running general scripts against the guest.
Diffstat (limited to 'sysprep')
-rw-r--r-- | sysprep/Makefile.am | 2 | ||||
-rw-r--r-- | sysprep/sysprep_operation_script.ml | 140 |
2 files changed, 142 insertions, 0 deletions
diff --git a/sysprep/Makefile.am b/sysprep/Makefile.am index 034252e0..d2303a68 100644 --- a/sysprep/Makefile.am +++ b/sysprep/Makefile.am @@ -42,6 +42,7 @@ SOURCES += \ sysprep_operation_net_hwaddr.ml \ sysprep_operation_random_seed.ml \ sysprep_operation_rhn_systemid.ml \ + sysprep_operation_script.ml \ sysprep_operation_smolt_uuid.ml \ sysprep_operation_ssh_hostkeys.ml \ sysprep_operation_udev_persistent_net.ml \ @@ -62,6 +63,7 @@ OBJECTS = \ sysprep_operation_net_hwaddr.cmx \ sysprep_operation_random_seed.cmx \ sysprep_operation_rhn_systemid.cmx \ + sysprep_operation_script.cmx \ sysprep_operation_smolt_uuid.cmx \ sysprep_operation_ssh_hostkeys.cmx \ sysprep_operation_udev_persistent_net.cmx \ diff --git a/sysprep/sysprep_operation_script.ml b/sysprep/sysprep_operation_script.ml new file mode 100644 index 00000000..14a00ebf --- /dev/null +++ b/sysprep/sysprep_operation_script.ml @@ -0,0 +1,140 @@ +(* virt-sysprep + * Copyright (C) 2012 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. + *) + +open Printf +open Unix + +open Utils +open Sysprep_operation + +module G = Guestfs + +let scriptdir = ref None +let set_scriptdir dir = + if !scriptdir <> None then ( + eprintf "virt-sysprep: --scriptdir cannot be used more than once\n"; + exit 1 + ); + scriptdir := Some dir + +let scripts = ref [] +let add_script script = + (* Sanity check that the script is executable. *) + let statbuf = stat script in + if statbuf.st_perm land 0o555 = 0 then ( + eprintf "virt-sysprep: script: %s: script is not executable\n" script; + exit 1 + ); + scripts := script :: !scripts + +let rec script_perform (g : Guestfs.guestfs) root = + let scripts = List.rev !scripts in + if scripts <> [] then ( + (* Create a temporary directory? *) + let scriptdir, cleanup = + match !scriptdir with + | Some dir -> dir, false + | None -> + let tmpdir = Filename.temp_dir_name in + let tmpdir = tmpdir // string_random8 () in + mkdir tmpdir 0o755; + tmpdir, true in + + (* Mount the directory locally. *) + g#mount_local scriptdir; + + (* Run the script(s)/program(s). *) + run_scripts scriptdir scripts; + + (* Run FUSE. *) + g#mount_local_run (); + + (* Remote temporary directory / mountpoint. *) + if cleanup then rmdir scriptdir + ); + [] + +(* Run the scripts in the background and make sure they call + * fusermount afterwards. + *) +and run_scripts mp scripts = + let sh = "/bin/bash" in + let cmd = + sprintf "\ +set -e +sysprep_unmount () +{ + cd / + count=10 + while ! fusermount -u %s && [ $count -gt 0 ]; do + sleep 1 + ((count--)) + done +} +trap sysprep_unmount INT TERM QUIT EXIT ERR\n" (Filename.quote mp) ^ + String.concat "\n" scripts in + let args = [| sh; "-c"; cmd |] in + + let pid = fork () in + if pid = 0 then ( (* child *) + chdir mp; + execv sh args + ) + +let script_op = { + name = "script"; + pod_description = "\ +The C<script> module lets you run arbitrary shell scripts or programs +against the guest. + +Note this feature requires FUSE support. You may have to enable +this in your host, for example by adding the current user to the +C<fuse> group, or by loading a kernel module. + +Use one or more I<--script> parameters to specify scripts or programs +that will be run against the guest. + +The script or program is run with its current directory being the +guest's root directory, so relative paths should be used. For +example: C<rm etc/resolv.conf> in the script would remove a Linux +guest's DNS configuration file, but C<rm /etc/resolv.conf> would +(try to) remove the host's file. + +Normally a temporary mount point for the guest is used, but you +can choose a specific one by using the I<--scriptdir> parameter."; + extra_args = [ + ("--scriptdir", Arg.String set_scriptdir, "dir Mount point on host"), + "\ +The mount point (an empty directory on the host) used when +the C<script> operation is enabled and one or more scripts +are specified using I<--script> parameter(s). + +Note that C<scriptdir> B<must> be an absolute path. + +If I<--scriptdir> is not specified then a temporary mountpoint +will be created."; + ("--script", Arg.String add_script, "script Script or program to run on guest"), + "\ +Run the named C<script> (a shell script or program) against the +guest. The script can be any program on the host. The script's +current directory will be the guest's root directory."; + ]; + perform = script_perform; +} + +let () = register_operation script_op |