(* 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 Std_utils open Tools_utils open Unix_utils open Common_gettext.Gettext open Getopt.OptionName open Sysprep_operation module G = Guestfs let scriptdir = ref None let set_scriptdir dir = if !scriptdir <> None then error (f_"--scriptdir cannot be used more than once"); scriptdir := Some dir let scripts = ref [] let add_script script = List.push_front script scripts let rec script_perform (g : Guestfs.guestfs) root side_effects = 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 = Mkdtemp.temp_dir "virt-sysprep." in tmpdir, true in (* Mount the directory locally. *) g#mount_local scriptdir; (* Run the script(s)/program(s). *) let pid = run_scripts scriptdir scripts in (* Run FUSE. *) g#mount_local_run (); let ok = match snd (waitpid [] pid) with | WEXITED 0 -> true | WEXITED i -> warning (f_"script: failed (code %d)") i; false | WSIGNALED i | WSTOPPED i -> warning (f_"script: killed by signal (%d)") i; false in (* Remote temporary directory / mountpoint. *) if cleanup then rmdir scriptdir; if not ok then failwith (s_"script failed") ) (* Run the scripts in the background and make sure they call * guestunmount afterwards. *) and run_scripts mp scripts = let sh = "/bin/bash" in let cmd = sprintf "\ set -e #set -x cleanup () { status=$? cd / guestunmount %s ||: exit $status } trap cleanup 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 ); pid let op = { defaults with name = "script"; enabled_by_default = true; heading = s_"Run arbitrary scripts against the guest"; pod_description = Some (s_"\ The C