3 # libguestfs virt-sysprep tool
4 # Copyright (C) 2011 Red Hat Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 program="virt-sysprep"
22 version="@PACKAGE_VERSION@"
26 --long help,add:,connect:,domain:,enable:,format::,hostname:,list-operations,verbose,version \
29 echo "$program: problem parsing the command line arguments"
34 # This array accumulates the arguments we pass through to guestfish.
36 guestfish[0]="guestfish"
38 guestfish[2]="--listen"
45 hostname_param=localhost.localdomain
50 echo " $program [--options] -d domname"
51 echo " $program [--options] -a disk.img [-a disk.img ...]"
53 echo "Read $program(1) man page for more information."
55 echo "NOTE: $program modifies the guest or disk image *in place*."
76 if [ -n "$enable" ]; then
77 echo "error: --enable option can only be given once"
84 guestfish[i++]="--format=$2"
86 guestfish[i++]="--format"
102 echo "$program $version"
111 echo "Internal error!"
116 # Different sysprep operations that can be enabled. Default is to
117 # enable all of these, although some of them are only done on certain
118 # guest types (see details below).
119 if [ -z "$enable" ]; then
123 udev_persistent_net=yes
124 elif [ "$enable" = "list" ]; then
128 echo "udev-persistent-net"
131 for opt in $(echo "$enable" | sed 's/,/ /g'); do
133 hostname) hostname=yes ;;
134 net-hwaddr) net_hwaddr=yes ;;
135 ssh-hostkeys) ssh_hostkeys=yes ;;
136 udev-persistent-net) udev_persistent_net=yes ;;
138 echo "error: unknown --enable feature: $opt"
144 # Make sure there were no extra parameters on the command line.
145 if [ $# -gt 0 ]; then
146 echo "error: $program: extra parameters on the command line"
151 # Did the user specify at least one -a or -d option?
152 if [ $add_params -eq 0 ]; then
153 echo "error: $program: you need at least one -a or -d option"
158 # end of command line parsing
159 #----------------------------------------------------------------------
163 if [ "$verbose" = "yes" ]; then
164 echo command: "${guestfish[@]}"
167 # Create a temporary directory for general purpose use during operations.
168 tmpdir="$(mktemp -d)"
170 # Increase the amount of memory allocated to the appliance because
171 # we're using augeas. The user can override this by setting
172 # $LIBGUESTFS_MEMSIZE before running the script.
173 export LIBGUESTFS_MEMSIZE=${LIBGUESTFS_MEMSIZE:-2048}
177 eval $("${guestfish[@]}")
178 if [ -z "$GUESTFISH_PID" ]; then
179 echo "$program: guestfish didn't start up, see error messages above"
184 gf="guestfish --remote --"
188 $gf exit >/dev/null 2>&1 ||:
191 trap cleanup EXIT ERR
193 # Launch back-end, inspect for operating systems, and get the guest
195 root=$($gf inspect-get-roots)
197 if [ "$root" = "" ]; then
198 echo "$program: no operating system was found on this disk"
202 if [ "$verbose" = "yes" ]; then
206 # Get the guest type.
207 type="$($gf -inspect-get-type $root)"
209 if [ "$type" = "linux" ]; then
210 distro="$($gf -inspect-get-distro $root)"
213 if [ "$type" = "windows" ]; then
214 systemroot="$($gf -inspect-get-windows-systemroot $root)"
217 # Start Augeas if it's a Linux guest.
218 if [ "$type" = "linux" ]; then
223 #----------------------------------------------------------------------
226 # erase_line filename regex
228 # Erase line(s) in a file that match the given regex.
231 $gf download "$1" "$tmpdir/file"
232 sed "/$2/d" < "$tmpdir/file" > "$tmpdir/file.1"
233 $gf upload "$tmpdir/file.1" "$1"
236 # prepend_line filename line
238 # Prepend a line to a file (this is better than appending, because it
239 # works even when the original file isn't terminated with a newline).
242 $gf download "$1" "$tmpdir/file"
243 echo "$2" > "$tmpdir/file.1"
244 cat "$tmpdir/file.1" "$tmpdir/file" >> "$tmpdir/file.2"
245 $gf upload "$tmpdir/file.2" "$1"
250 # Remove files. Doesn't fail if no files exist. Note the wildcard
251 # parameter cannot contain spaces or characters that need special
255 files=$($gf glob-expand "$1")
263 # Remove a single file. No error if the file doesn't exist or is not
267 t=$($gf is-file "$1")
268 if [ "$t" = "true" ]; then
273 #----------------------------------------------------------------------
274 # The sysprep operations.
276 if [ "$hostname" = "yes" ]; then
277 case "$type/$distro" in
279 $gf aug-set /files/etc/sysconfig/network/HOSTNAME "$hostname_param"
280 augeas_save_needed=yes
282 linux/debian|linux/ubuntu)
283 $gf write /etc/hostname "$hostname_param"
288 if [ "$net_hwaddr" = "yes" ]; then
289 case "$type/$distro" in
291 # XXX these filenames can have spaces and untrusted chars in them!
292 nodes=$( $gf aug-ls /files/etc/sysconfig/network-scripts |
293 grep /files/etc/sysconfig/network-scripts/ifcfg- )
294 for node in $nodes; do
295 $gf -aug-rm "$node/HWADDR" >/dev/null
296 augeas_save_needed=yes
302 if [ "$ssh_hostkeys" = "yes" -a "$type" != "windows" ]; then
303 rm_files "/etc/ssh/*_host_*"
306 if [ "$udev_persistent_net" = "yes" -a "$type" = "linux" ]; then
307 rm_file /etc/udev/rules.d/70-persistent-net.rules
310 #----------------------------------------------------------------------
311 # Clean up and close down.
313 if [ "$using_augeas" = "yes" -a "$augeas_save_needed" = "yes" ]; then