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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 program="virt-sysprep"
22 version="@PACKAGE_VERSION@"
24 # Uncomment this to see every shell command that is executed.
29 --long help,add:,connect:,domain:,enable:,format::,hostname:,list-operations,selinux-relabel,no-selinux-relabel,verbose,version \
32 echo "$program: problem parsing the command line arguments"
37 # This array accumulates the arguments we pass through to guestmount.
44 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 params[i++]="--format=$2"
86 params[i++]="--format"
100 --no-selinux-relabel)
108 echo "$program $version"
111 # Can't pass the -x option directly to guestmount because
112 # that stops guestmount from forking, which means we can't
113 # coordinate with guestmount when it has finished
114 # initializing. So instead set just the underlying option
115 # in libguestfs by exporting LIBGUESTFS_TRACE.
116 # Unfortunately (a) this omits FUSE calls, but don't worry
117 # about that for now, and more importantly (b) trace
118 # messages disappear into never-never land after the fork.
119 export LIBGUESTFS_TRACE=1
125 echo "Internal error!"
130 # Different sysprep operations that can be enabled. Default is to
131 # enable all of these, although some of them are only done on certain
132 # guest types (see details below).
133 if [ -z "$enable" ]; then
135 dhcp_client_state=yes
136 dhcp_server_state=yes
145 udev_persistent_net=yes
148 elif [ "$enable" = "list" ]; then
150 echo "dhcp-client-state"
151 echo "dhcp-server-state"
160 echo "udev-persistent-net"
165 for opt in $(echo "$enable" | sed 's/,/ /g'); do
167 cron-spool) cron_spool=yes ;;
168 dhcp-client-state) dhcp_client_state=yes ;;
169 dhcp-server-state) dhcp_server_state=yes ;;
170 hostname) hostname=yes ;;
171 logfiles) logfiles=yes ;;
172 mail-spool) mail_spool=yes ;;
173 net-hwaddr) net_hwaddr=yes ;;
174 random-seed) random_seed=yes ;;
175 rhn-systemid) rhn_systemid=yes ;;
176 smolt-uuid) smolt_uuid=yes ;;
177 ssh-hostkeys) ssh_hostkeys=yes ;;
178 udev-persistent-net) udev_persistent_net=yes ;;
180 yum-uuid) yum_uuid=yes ;;
182 echo "error: unknown --enable feature: $opt"
188 # Make sure there were no extra parameters on the command line.
189 if [ $# -gt 0 ]; then
190 echo "error: $program: extra parameters on the command line"
195 # Did the user specify at least one -a or -d option?
196 if [ $add_params -eq 0 ]; then
197 echo "error: $program: you need at least one -a or -d option"
202 # end of command line parsing
203 #----------------------------------------------------------------------
207 if [ "$verbose" = "yes" ]; then
208 echo params: "${params[@]}"
211 # Create a temporary directory for general purpose use during operations.
212 tmpdir="$(mktemp -d)"
216 if [ -d $tmpdir/mnt ]; then
217 fusermount -u $tmpdir/mnt >/dev/null 2>&1 ||:
221 trap cleanup EXIT ERR
223 # Run virt-inspector and grab inspection information about this guest.
224 virt-inspector "${params[@]}" > $tmpdir/xml
225 virt-inspector --xpath \
226 "string(/operatingsystems/operatingsystem[position()=1]/name)" \
227 < $tmpdir/xml > $tmpdir/type
228 virt-inspector --xpath \
229 "string(/operatingsystems/operatingsystem[position()=1]/distro)" \
230 < $tmpdir/xml > $tmpdir/distro ||:
231 virt-inspector --xpath \
232 "string(/operatingsystems/operatingsystem[position()=1]/package_format)" \
233 < $tmpdir/xml > $tmpdir/package_format ||:
234 virt-inspector --xpath \
235 "string(/operatingsystems/operatingsystem[position()=1]/package_management)" \
236 < $tmpdir/xml > $tmpdir/package_management ||:
238 type="$(cat $tmpdir/type)"
239 distro="$(cat $tmpdir/distro)"
240 package_format="$(cat $tmpdir/package_format)"
241 package_management="$(cat $tmpdir/package_management)"
245 guestmount --rw -i "${params[@]}" $tmpdir/mnt
249 #----------------------------------------------------------------------
250 # The sysprep operations.
252 if [ "$cron_spool" = "yes" ]; then
253 rm -rf $mnt/var/spool/cron/*
256 if [ "$dhcp_client_state" = "yes" ]; then
259 rm -rf $mnt/var/lib/dhclient/*
261 rm -rf $mnt/var/lib/dhcp/*
266 if [ "$dhcp_server_state" = "yes" ]; then
269 rm -rf $mnt/var/lib/dhcpd/*
274 if [ "$hostname" = "yes" ]; then
275 case "$type/$distro" in
277 echo "HOSTNAME=$hostname_param" > $mnt/etc/sysconfig/network.new
278 sed '/^HOSTNAME=/d' < $mnt/etc/sysconfig/network >> $mnt/etc/sysconfig/network.new
279 mv -f $mnt/etc/sysconfig/network.new $mnt/etc/sysconfig/network
282 linux/debian|linux/ubuntu)
283 echo "$hostname_param" > $mnt/etc/hostname
289 if [ "$logfiles" = "yes" ]; then
292 rm -rf $mnt/var/log/*.log*
293 rm -rf $mnt/var/log/audit/*
294 rm -rf $mnt/var/log/btmp*
295 rm -rf $mnt/var/log/cron*
296 rm -rf $mnt/var/log/dmesg*
297 rm -rf $mnt/var/log/lastlog*
298 rm -rf $mnt/var/log/maillog*
299 rm -rf $mnt/var/log/mail/*
300 rm -rf $mnt/var/log/messages*
301 rm -rf $mnt/var/log/secure*
302 rm -rf $mnt/var/log/spooler*
303 rm -rf $mnt/var/log/tallylog*
304 rm -rf $mnt/var/log/wtmp*
309 if [ "$mail_spool" = "yes" ]; then
310 rm -rf $mnt/var/spool/mail/*
311 rm -rf $mnt/var/mail/*
314 if [ "$net_hwaddr" = "yes" ]; then
315 case "$type/$distro" in
317 if [ -d $mnt/etc/sysconfig/network-scripts ]; then
320 sed '/^HWADDR=/d' < "$1" > "$1.new"
324 find $mnt/etc/sysconfig/network-scripts \
325 -name 'ifcfg-*' -type f \
326 -exec bash -c 'rm_hwaddr "$0"' {} \;
333 if [ "$random_seed" = "yes" -a "$type" = "linux" ]; then
335 if [ -f $mnt/var/lib/random-seed ]; then
337 f=$mnt/var/lib/random-seed
338 elif [ -f $mnt/var/lib/urandom/random-seed ]; then
340 f=$mnt/var/lib/urandom/random-seed
343 dd if=/dev/urandom of="$f" bs=8 count=1 conv=nocreat,notrunc 2>/dev/null
347 if [ "$rhn_systemid" = "yes" -a "$type/$distro" = "linux/rhel" ]; then
348 rm -f $mnt/etc/sysconfig/rhn/systemid
351 if [ "$smolt_uuid" = "yes" -a "$type" = "linux" ]; then
352 rm -f $mnt/etc/sysconfig/hw-uuid
353 rm -f $mnt/etc/smolt/uuid
354 rm -f $mnt/etc/smolt/hw-uuid
357 if [ "$ssh_hostkeys" = "yes" -a "$type" != "windows" ]; then
358 rm -rf $mnt/etc/ssh/*_host_*
361 if [ "$udev_persistent_net" = "yes" -a "$type" = "linux" ]; then
362 rm -f $mnt/etc/udev/rules.d/70-persistent-net.rules
365 if [ "$utmp" = "yes" -a "$type" != "windows" ]; then
366 rm -f $mnt/var/run/utmp
369 if [ "$yum_uuid" = "yes" -a "$package_management" = "yum" ]; then
370 rm -f $mnt/var/lib/yum/uuid
373 #----------------------------------------------------------------------
374 # Clean up and close down.
376 # If we created any new files and the guest uses SELinux, then we have
377 # to relabel the filesystem on boot. Could do with a better way to
378 # test "guest uses SELinux" (XXX).
379 case "$selinux_relabel/$created_files" in
381 touch $mnt/.autorelabel;;
383 case "$type/$distro" in
384 linux/fedora|linux/rhel|linux/centos|linux/scientificlinux|linux/redhat-based)
385 touch $mnt/.autorelabel
393 fusermount -u $tmpdir/mnt