#!/bin/bash -
# clone/virt-sysprep.  Generated from virt-sysprep.in by configure.
# libguestfs virt-sysprep tool
# Copyright (C) 2011 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.

unset CDPATH
program="virt-sysprep"
version="1.14.8"

# Uncomment this to see every shell command that is executed.
#set -x

TEMP=`getopt \
        -o a:c:d:vVx \
        --long help,add:,connect:,domain:,enable:,format::,hostname:,list-operations,selinux-relabel,no-selinux-relabel,verbose,version \
        -n $program -- "$@"`
if [ $? != 0 ]; then
    echo "$program: problem parsing the command line arguments"
    exit 1
fi
eval set -- "$TEMP"

# This array accumulates the arguments we pass through to guestmount.
declare -a params
i=0

verbose=
add_params=0
enable=
hostname_param=localhost.localdomain
selinux_relabel=auto

usage ()
{
    echo "Usage:"
    echo "  $program [--options] -d domname"
    echo "  $program [--options] -a disk.img [-a disk.img ...]"
    echo
    echo "Read $program(1) man page for more information."
    echo
    echo "NOTE: $program modifies the guest or disk image *in place*."
    exit $1
}

while true; do
    case "$1" in
        -a|--add)
            params[i++]="-a"
            params[i++]="$2"
            ((add_params++))
            shift 2;;
        -c|--connect)
            params[i++]="-c"
            params[i++]="$2"
            shift 2;;
        -d|--domain)
            params[i++]="-d"
            params[i++]="$2"
            ((add_params++))
            shift 2;;
        --enable)
            if [ -n "$enable" ]; then
                echo "error: --enable option can only be given once"
                exit 1
            fi
            enable="$2"
            shift 2;;
        --format)
            if [ -n "$2" ]; then
                params[i++]="--format=$2"
            else
                params[i++]="--format"
            fi
            shift 2;;
        --help)
            usage 0;;
        --hostname)
            hostname_param="$2"
            shift 2;;
        --list-operations)
            enable=list
            shift;;
        --selinux-relabel)
            selinux_relabel=yes
            shift;;
        --no-selinux-relabel)
            selinux_relabel=no
            shift;;
        -v|--verbose)
            params[i++]="-v"
            verbose=yes
            shift;;
        -V|--version)
            echo "$program $version"
            exit 0;;
        -x)
            # Can't pass the -x option directly to guestmount because
            # that stops guestmount from forking, which means we can't
            # coordinate with guestmount when it has finished
            # initializing.  So instead set just the underlying option
            # in libguestfs by exporting LIBGUESTFS_TRACE.
            # Unfortunately (a) this omits FUSE calls, but don't worry
            # about that for now, and more importantly (b) trace
            # messages disappear into never-never land after the fork.
            export LIBGUESTFS_TRACE=1
            shift;;
        --)
            shift
            break;;
        *)
            echo "Internal error!"
            exit 1;;
    esac
done

# Different sysprep operations that can be enabled.  Default is to
# enable all of these, although some of them are only done on certain
# guest types (see details below).
if [ -z "$enable" ]; then
    cron_spool=yes
    dhcp_client_state=yes
    dhcp_server_state=yes
    hostname=yes
    logfiles=yes
    mail_spool=yes
    net_hwaddr=yes
    random_seed=yes
    rhn_systemid=yes
    smolt_uuid=yes
    ssh_hostkeys=yes
    udev_persistent_net=yes
    utmp=yes
    yum_uuid=yes
elif [ "$enable" = "list" ]; then
    echo "cron-spool"
    echo "dhcp-client-state"
    echo "dhcp-server-state"
    echo "hostname"
    echo "logfiles"
    echo "mail-spool"
    echo "net-hwaddr"
    echo "random-seed"
    echo "rhn-systemid"
    echo "smolt-uuid"
    echo "ssh-hostkeys"
    echo "udev-persistent-net"
    echo "utmp"
    echo "yum-uuid"
    exit 0
else
    for opt in $(echo "$enable" | sed 's/,/ /g'); do
        case "$opt" in
            cron-spool)            cron_spool=yes ;;
            dhcp-client-state)     dhcp_client_state=yes ;;
            dhcp-server-state)     dhcp_server_state=yes ;;
            hostname)              hostname=yes ;;
            logfiles)              logfiles=yes ;;
            mail-spool)            mail_spool=yes ;;
            net-hwaddr)            net_hwaddr=yes ;;
            random-seed)           random_seed=yes ;;
            rhn-systemid)          rhn_systemid=yes ;;
            smolt-uuid)            smolt_uuid=yes ;;
            ssh-hostkeys)          ssh_hostkeys=yes ;;
            udev-persistent-net)   udev_persistent_net=yes ;;
            utmp)                  utmp=yes ;;
            yum-uuid)              yum_uuid=yes ;;
            *)
                echo "error: unknown --enable feature: $opt"
                exit 1
        esac
    done
fi

# Make sure there were no extra parameters on the command line.
if [ $# -gt 0 ]; then
    echo "error: $program: extra parameters on the command line"
    echo
    usage 1
fi

# Did the user specify at least one -a or -d option?
if [ $add_params -eq 0 ]; then
    echo "error: $program: you need at least one -a or -d option"
    echo
    usage 1
fi

# end of command line parsing
#----------------------------------------------------------------------

set -e

if [ "$verbose" = "yes" ]; then
    echo params: "${params[@]}"
fi

# Create a temporary directory for general purpose use during operations.
tmpdir="$(mktemp -d)"

cleanup ()
{
    if [ -d $tmpdir/mnt ]; then
        fusermount -u $tmpdir/mnt >/dev/null 2>&1 ||:
    fi
    rm -rf $tmpdir ||:
}
trap cleanup EXIT ERR

# Run virt-inspector and grab inspection information about this guest.
virt-inspector "${params[@]}" > $tmpdir/xml
virt-inspector --xpath \
    "string(/operatingsystems/operatingsystem[position()=1]/name)" \
    < $tmpdir/xml > $tmpdir/type
virt-inspector --xpath \
    "string(/operatingsystems/operatingsystem[position()=1]/distro)" \
    < $tmpdir/xml > $tmpdir/distro ||:
virt-inspector --xpath \
    "string(/operatingsystems/operatingsystem[position()=1]/package_format)" \
    < $tmpdir/xml > $tmpdir/package_format ||:
virt-inspector --xpath \
    "string(/operatingsystems/operatingsystem[position()=1]/package_management)" \
    < $tmpdir/xml > $tmpdir/package_management ||:

type="$(cat $tmpdir/type)"
distro="$(cat $tmpdir/distro)"
package_format="$(cat $tmpdir/package_format)"
package_management="$(cat $tmpdir/package_management)"

# Mount the disk.
mkdir $tmpdir/mnt
guestmount --rw -i "${params[@]}" $tmpdir/mnt

mnt="$tmpdir/mnt"

#----------------------------------------------------------------------
# The sysprep operations.

if [ "$cron_spool" = "yes" ]; then
    rm -rf $mnt/var/spool/cron/*
fi

if [ "$dhcp_client_state" = "yes" ]; then
    case "$type" in
        linux)
            rm -rf $mnt/var/lib/dhclient/*
            # RHEL 3:
            rm -rf $mnt/var/lib/dhcp/*
            ;;
    esac
fi

if [ "$dhcp_server_state" = "yes" ]; then
    case "$type" in
        linux)
            rm -rf $mnt/var/lib/dhcpd/*
            ;;
    esac
fi

if [ "$hostname" = "yes" ]; then
    case "$type/$distro" in
        linux/fedora)
            echo "HOSTNAME=$hostname_param" > $mnt/etc/sysconfig/network.new
            sed '/^HOSTNAME=/d' < $mnt/etc/sysconfig/network >> $mnt/etc/sysconfig/network.new
            mv -f $mnt/etc/sysconfig/network.new $mnt/etc/sysconfig/network
            created_files=yes
            ;;
        linux/debian|linux/ubuntu)
            echo "$hostname_param" > $mnt/etc/hostname
            created_files=yes
            ;;
    esac
fi

if [ "$logfiles" = "yes" ]; then
    case "$type" in
        linux)
            rm -rf $mnt/var/log/*.log*
            rm -rf $mnt/var/log/audit/*
            rm -rf $mnt/var/log/btmp*
            rm -rf $mnt/var/log/cron*
            rm -rf $mnt/var/log/dmesg*
            rm -rf $mnt/var/log/lastlog*
            rm -rf $mnt/var/log/maillog*
            rm -rf $mnt/var/log/mail/*
            rm -rf $mnt/var/log/messages*
            rm -rf $mnt/var/log/secure*
            rm -rf $mnt/var/log/spooler*
            rm -rf $mnt/var/log/tallylog*
            rm -rf $mnt/var/log/wtmp*
            ;;
    esac
fi

if [ "$mail_spool" = "yes" ]; then
    rm -rf $mnt/var/spool/mail/*
    rm -rf $mnt/var/mail/*
fi

if [ "$net_hwaddr" = "yes" ]; then
    case "$type/$distro" in
        linux/fedora)
            if [ -d $mnt/etc/sysconfig/network-scripts ]; then
                rm_hwaddr ()
                {
                    sed '/^HWADDR=/d' < "$1" > "$1.new"
                    mv -f "$1.new" "$1"
                }
                export -f rm_hwaddr
                find $mnt/etc/sysconfig/network-scripts \
                    -name 'ifcfg-*' -type f \
                    -exec bash -c 'rm_hwaddr "$0"' {} \;
                created_files=yes
            fi
            ;;
    esac
fi

if [ "$random_seed" = "yes" -a "$type" = "linux" ]; then
    f=
    if [ -f $mnt/var/lib/random-seed ]; then
        # Fedora
        f=$mnt/var/lib/random-seed
    elif [ -f $mnt/var/lib/urandom/random-seed ]; then
        # Debian
        f=$mnt/var/lib/urandom/random-seed
    fi
    if [ -n "$f" ]; then
        dd if=/dev/urandom of="$f" bs=8 count=1 conv=nocreat,notrunc 2>/dev/null
    fi
fi

if [ "$rhn_systemid" = "yes" -a "$type/$distro" = "linux/rhel" ]; then
    rm -f $mnt/etc/sysconfig/rhn/systemid
fi

if [ "$smolt_uuid" = "yes" -a "$type" = "linux" ]; then
    rm -f $mnt/etc/sysconfig/hw-uuid
    rm -f $mnt/etc/smolt/uuid
    rm -f $mnt/etc/smolt/hw-uuid
fi

if [ "$ssh_hostkeys" = "yes" -a "$type" != "windows" ]; then
    rm -rf $mnt/etc/ssh/*_host_*
fi

if [ "$udev_persistent_net" = "yes" -a "$type" = "linux" ]; then
    rm -f $mnt/etc/udev/rules.d/70-persistent-net.rules
fi

if [ "$utmp" = "yes" -a "$type" != "windows" ]; then
    rm -f $mnt/var/run/utmp
fi

if [ "$yum_uuid" = "yes" -a "$package_management" = "yum" ]; then
    rm -f $mnt/var/lib/yum/uuid
fi

#----------------------------------------------------------------------
# Clean up and close down.

# If we created any new files and the guest uses SELinux, then we have
# to relabel the filesystem on boot.  Could do with a better way to
# test "guest uses SELinux" (XXX).
case "$selinux_relabel/$created_files" in
    yes/*)
        touch $mnt/.autorelabel;;
    auto/yes)
        case "$type/$distro" in
            linux/fedora|linux/rhel|linux/centos|linux/scientificlinux|linux/redhat-based)
                touch $mnt/.autorelabel
                ;;
        esac
        ;;
esac

sync

fusermount -u $tmpdir/mnt
rm -rf $tmpdir

trap - EXIT ERR

exit 0
