#!/bin/bash -e # # debtakeover # # $Id: debtakeover 159 2004-05-09 09:34:46Z guillem $ # # Convert a new non-Debian distribution to Debian proper # # Copyright (C) 2003, 2004 Guillem Jover # # 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; version 2 of the License. # # 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. # # # User modifiable variables # REMOVE_EXCLUDES="/etc/mtab /etc/fstab /etc/hostname /etc/hosts /etc/resolv.conf /etc/lilo.conf /etc/modules /etc/modules.conf /etc/passwd /etc/shadow /etc/group /etc/gshadow /etc/grub.conf /etc/ssh/ssh_host_* /etc/network/interfaces" STD_EXCLUDES="/tmp /root /home /opt /dev /proc /sys" WORKDIR=~ # # Function definitions # logpipe() { if [ "$VERBOSE" = "yes" ]; then tee -a $LOGFILE else cat >> $LOGFILE fi } log() { echo -e "$@" | logpipe } msg() { echo -e "$@" | tee -a $LOGFILE } warning() { msg "warning: $@" >&2 } error() { code=$1 shift msg "error: $@" >&2 if [ $code != 0 ]; then exit $code fi } sigerror() { echo "Unexpected error, please report it with full logs it to: " echo " $BUGS_ADDRESS" } usage() { cat <<-HERE usage: $PROGRAM [options] options: --profile=string Installation profile (default "$DEFAULT_PROFILE") --suite=string Debian suite (default "$DEFAULT_SUITE") --mirror=url Debian mirror (default "$DEFAULT_MIRROR") --tarball=file Debian base tarball --debootstrap=path Debootstrap compatible binary (default "$DEFAULT_DEBOOTSTRAP") --force-purify Force the purification (non-interactive) --force-retakeover Force taking over a Debian system --verbose Be more verbose --version Print program version --help Print this help HERE exit 0 } setup_shell() { msg "Stage (Setting up the shell)" msg "-----" msg "-> Disable bash executable path hashing." set +h # Some old bash versions does not support SIGERR on errors from set -e if trap -p ERR >& /dev/null; then msg "-> Setting signal handler." trap sigerror ERR fi } check_needed() { msg "Stage (Checking for needed components)" msg "-----" check_print() { msg -n "-> Checking for $@ ... "; } check_print "superuser privileges" if [ `id -u` = 0 ]; then msg "ok." else msg "failed." error 4 "You need superuser privileges to run this program." fi if [ -z "$TARBALL" ]; then local DEBOOTSTRAP_NEEDED="$DEBOOTSTRAP wget ar MAKEDEV" # MAKEDEV may be only on /dev local NEWPATH=$PATH:/dev else local NEWPATH=$PATH fi local DEBTAKEOVER_NEEDED="grep sed diff tar gzip bzip2" for bin in $DEBOOTSTRAP_NEEDED $DEBTAKEOVER_NEEDED; do check_print "$bin" if PATH=$NEWPATH which $bin >& /dev/null; then msg "found." else msg "missing." local CHECK_MISSING=yes fi done if [ "$CHECK_MISSING" = yes ]; then error 2 "Please install missing software and try again." fi if [ "$FORCE_PURIFY" != yes ]; then REPLY_CHECK="Yes I am" warning "Are you sure what are you going to do ? [$REPLY_CHECK]" read if [ "$REPLY" != "$REPLY_CHECK" ]; then error 20 "Ok, you are not sure. Leaving $DISTRO distro untouched." fi fi } distro_detect() { msg "Stage (Detecting current Distro)" msg "-----" # Set default redhat style network conf dir. NETWORK_REDHAT_CONF_DIR=/etc/sysconfig/network-scripts if [ -e /etc/mandrake-release ] then DISTRO=mandrake NETWORK_TYPE=redhat elif [ -e /etc/fedora-release ] then DISTRO=fedora NETWORK_TYPE=redhat elif [ -e /etc/redhat-release ] then DISTRO=redhat NETWORK_TYPE=redhat elif [ -e /etc/SuSE-release ] then DISTRO=suse NETWORK_TYPE=redhat # SuSE version < 8.0 used /etc/rc.config NETWORK_REDHAT_CONF_DIR=/etc/sysconfig/network elif [ -e /etc/slackware-version ] then DISTRO=slackware elif [ -e /etc/gentoo-release ] then DISTRO=gentoo elif [ -e /etc/cobalt-release ] then DISTRO=cobalt elif [ -e /etc/yellowdog-release ] then DISTRO=yellowdog elif [ -e /etc/turbolinux-release ] then DISTRO=turbolinux fi if [ -e /etc/debian_version ] then if [ "$DISTRO" = unknown ]; then if [ "$FORCE_RETAKEOVER" = yes ]; then DISTRO=debian NETWORK_TYPE=debian warning "Taking over a Debian system" else error 1 "You already have a Debian system" fi else warning "You have a mixed system, trying to continue" DISTRO_MIXED=yes fi fi msg $DISTRO } generic_exclusion_list() { msg "Stage (Building the generic exclusion list)" msg "-----" msg "-> Generating exclusion file list" echo ${REMOVE_EXCLUDES} ${STD_EXCLUDES} ${DISTRO_EXCLUDES} \ | xargs -n1 > $WORKDIR/debianize-exclude.list sed -e 's:^/::' $WORKDIR/debianize-exclude.list > $WORKDIR/debianize-tar-exclude.list STD_FIND_EXCLUDES=`for e in $STD_EXCLUDES; do echo "-path $e -prune -o "; done` } debian_tarball_build() { msg "Stage (Building the base-tarball)" msg "-----" msg "-> Debootstrapping" $DEBOOTSTRAP --include="$DEBOOTSTRAP_INCLUDES" \ --exclude="$DEBOOTSTRAP_EXCLUDES" \ $DEBIAN_VERSION $DEBIAN_DIR $DEBIAN_MIRROR/debian 2>&1 | logpipe msg "-> Checking chroot sanity" for d in $DEBOOTSTRAP_CHECK_DIRS; do [ -d $DEBIAN_DIR$d ] || error 2 "Bad chroot, clean, correct, and try again." done msg "-> Removing unneeded files" rm -f $DEBIAN_DIR/var/lib/apt/lists/*_{Sources,Packages,Release} rm -f $DEBIAN_DIR/var/cache/apt/{*.bin,archives/*.deb} rm -rf $DEBIAN_DIR/dev msg "-> Setting up APT sources.list" cat > $DEBIAN_DIR/etc/apt/sources.list <<-EOF deb $DEBIAN_MIRROR_SECURITY/debian-security $DEBIAN_VERSION/updates main deb $DEBIAN_MIRROR/debian $DEBIAN_VERSION main deb $DEBIAN_MIRROR/debian-non-US $DEBIAN_VERSION/non-US main deb-src $DEBIAN_MIRROR_SECURITY/debian-security $DEBIAN_VERSION/updates main deb-src $DEBIAN_MIRROR/debian $DEBIAN_VERSION main deb-src $DEBIAN_MIRROR/debian-non-US $DEBIAN_VERSION/non-US main EOF msg "-> Generating Debian files list" chroot $DEBIAN_DIR find / $STD_FIND_EXCLUDES -print \ | sort > $WORKDIR/debianize-debian.list msg "-> Packaging Debian chroot" ( cd $DEBIAN_DIR; \ tar cf $DEBIAN_TARBALL $DEBIAN_TARBALL_COMPRESSOR * ) msg "-> Cleaning Debian chroot" rm -rf $DEBIAN_DIR } debian_tarball_prebuilt() { msg "Stage (Setting up pre-built base-tarball)" msg "-----" msg "-> Generating Debian files list from pre-built tarball" tar tf $DEBIAN_TARBALL $DEBIAN_TARBALL_COMPRESSOR \ | sort | sed -e 's,^,/,' > $WORKDIR/debianize-debian.list } distro_remove_list() { msg "Stage (Building the remove list)" msg "-----" msg "-> Generating $DISTRO distro files list" find / \ $STD_FIND_EXCLUDES \ -path '/boot' -prune \ -o -path '/var/run' -prune \ -o -path '/var/log' -prune \ -o -path '/var/local' -prune \ -o -path '/usr/local' -prune \ -o -path '/usr/src' -prune \ -o -path '/lib/modules' -prune \ -o -print | sort > $WORKDIR/debianize-$DISTRO.list msg "-> Generating $DISTRO distro files removal list" diff -u $WORKDIR/debianize-$DISTRO.list $WORKDIR/debianize-debian.list \ | tail +2 | grep '^-' | sed -e 's,^-,,' \ | grep -vxf $WORKDIR/debianize-exclude.list > $WORKDIR/debianize-remove.list } setup_network_debian() { msg "-> Keeping Debian network config" >&2 } setup_network_redhat() { if [ -f /etc/sysconfig/network ]; then . /etc/sysconfig/network fi for f in $NETWORK_REDHAT_CONF_DIR/ifcfg-*; do unset DEVICE BROADCAST BOOTPROTO IPADDR NETMASK NETWORK ONBOOT || true . $f [ "$ONBOOT" = yes -o "$STARTMODE" = onboot ] && echo "auto $DEVICE" if [ "$DEVICE" = lo -o "$NAME" = loopback ]; then NET_METHOD=loopback elif [ -z "$BOOTPROTO" -o "$BOOTPROTO" = static -o "$BOOTPROTO" = none ]; then NET_METHOD=static else NET_METHOD=$BOOTPROTO fi echo "iface $DEVICE inet $NET_METHOD" if [ "$NET_METHOD" = static ]; then [ -n "$IPADDR" ] && echo " address $IPADDR" [ -n "$BROADCAST" ] && echo " broadcast $BROADCAST" [ -n "$NETMASK" ] && echo " netmask $NETMASK" [ -n "$NETWORK" ] && echo " network $NETWORK" [ -n "$GATEWAY" ] && echo " gateway $GATEWAY" fi echo done } setup_network_gentoo() { cat /etc/conf.d/net | grep -v '^ *#' | while read line do : done } setup_network_bsd() { # /etc/rc.d/rc.inet1 : } setup_network_none() { warning "Distro $DISTRO does not have yet a network conversion scripts." } debian_preconfigure() { msg "Stage (PreConfiguring)" msg "-----" msg "-> Preserving $DISTRO distro network configuration" mkdir -p /etc/network setup_network_${NETWORK_TYPE} > /etc/network/interfaces if [ ! -f /etc/hostname ]; then hostname -s > /etc/hostname fi msg "-> Preserving $DISTRO distro module configuration" mkdir -p /etc/modutils if [ -f /etc/conf.modules ]; then cat /etc/conf.modules >> /etc/modutils/$DISTRO fi if [ -f /etc/modules.conf ] && ! grep update-modules /etc/modules.conf &> /dev/null; then cat /etc/modules.conf >> /etc/modutils/$DISTRO fi } debian_configure() { msg "Stage (Configuring)" msg "-----" msg "-> Sanitizing user databases" update-passwd if [ ! -e /dev/.devfsd ]; then msg "-> Updating device nodes" cd /dev ln -sf /sbin/MAKEDEV ./MAKEDEV update || true cd - fi msg "-> Disabling unneeded network services" update-inetd --multi --disable discard,daytime,time if [ "$DEBTAKEOVER_PROFILE" = colo ]; then msg "-> Setting up specific colo configurations" # TODO: Add a kernel paramater "panic=30" if [ -f /etc/default/rcS ]; then sed -e 's/^FSCKFIX=no/FSCKFIX=yes/;s/^TMPTIME=0/TMPTIME=15/' \ < /etc/default/rcS > /tmp/rcS && mv -f /tmp/rcS /etc/default/ fi msg "-> Converting halt to behave as reboot" rm -f /etc/rc0.d/S??halt cp -fd /etc/rc6.d/S??reboot /etc/rc0.d fi msg "-> Setting up module configurations" if [ ! -f /etc/modules ]; then > /etc/modules fi update-modules force msg "-> Setting up remaining configurations" dpkg --configure -a if ! grep '# Begin:.*debtakeover' ~/.bash_profile &> /dev/null; then msg "-> Sanitizing root PATH environment variable" cat >> ~/.bash_profile <<-EOF # Begin: automatically added by debtakeover PATH=/sbin:/usr/sbin:/usr/local/sbin:\$PATH # End EOF fi } debian_dump() { msg "Stage (Dump the tarball)" msg "-----" cd / msg "-> Making backups of important data" tar czvf $WORKDIR/$DISTRO-etc.tgz /etc 2>&1 | logpipe tar czvf $WORKDIR/$DISTRO-log.tgz /var/log 2>&1 | logpipe msg "-> Removing symlinks to directories" find / $STD_FIND_EXCLUDES -type l -xtype d -print | xargs rm -f || true msg "-> Dumping Debian over $DISTRO distro" tar xvf $DEBIAN_TARBALL $DEBIAN_TARBALL_COMPRESSOR --numeric-owner \ -p -U -X $WORKDIR/debianize-tar-exclude.list 2>&1 | logpipe || true msg "-> Regenerating linker configuration" ldconfig } distro_trash() { msg "Stage (Trash the old system)" msg "-----" msg "-> Removing remaining $DISTRO distro files" cat $WORKDIR/debianize-remove.list | xargs rm -f 2> /dev/null \ | ( ldconfig; logpipe ) || true msg "-> Regenerating linker configuration" ldconfig msg "-> Removing remaining $DISTRO distro directories" cat $WORKDIR/debianize-remove.list | sort -r | xargs rmdir 2> /dev/null \ | ( ldconfig; logpipe ) || true } # # Main program # export LC_ALL=C PROGRAM=debtakeover VERSION=0.8 BUGS_ADDRESS="Guillem Jover " DEFAULT_MIRROR=http://ftp.no.debian.org DEFAULT_MIRROR_SECURITY=http://security.debian.org DEFAULT_SUITE=woody DEFAULT_PROFILE=colo DEFAULT_DEBOOTSTRAP=debootstrap # Process command line arguments for arg do arg_value=`echo $arg | sed 's/--[^= ]*=//'` if echo $arg | grep -- '--[^= ]*=' >& /dev/null && [ -z "$arg_value" ]; then error 8 "Missing option value for '$arg'." fi case $arg in --verbose) VERBOSE=yes ;; --profile=*) PROFILE=$arg_value ;; --mirror=*) MIRROR=$arg_value ;; --suite=*) SUITE=$arg_value ;; --tarball=*) TARBALL=$arg_value local TARBALL_DIR=`dirname $TARBALL` if [ ${TARBALL_DIR:0:1} = / ]; then TARBALL=`pwd`/$TARBALL fi if [ ! -e $TARBALL ]; then error 11 "Tarball does not exist." fi case $TARBALL in *.tar.gz|*.tgz) TARBALL_COMPRESSOR=--gzip ;; *.tar.bz2) TARBALL_COMPRESSOR=--bzip2 ;; *.tar.Z|*.taz) TARBALL_COMPRESSOR=--compress ;; *) error 10 "Tarball extension not recognized." ;; esac ;; --debootstrap=*) USER_DEBOOTSTRAP=$arg_value ;; --force-purify) FORCE_PURIFY=yes ;; --force-retakeover) FORCE_RETAKEOVER=yes ;; --version) echo "$PROGRAM $VERSION" exit 0 ;; --help) usage ;; *) error 0 "Unrecognized '$arg' option or value for option not specified." usage ;; esac shift done # Initialize some variables LOGFILE=$WORKDIR/$PROGRAM.log DISTRO=unknown DISTRO_MIXED=no NETWORK_TYPE=none DEBIAN_MIRROR=${MIRROR:-$DEFAULT_MIRROR} DEBIAN_MIRROR_SECURITY=${MIRROR_SECURITY:-$DEFAULT_MIRROR_SECURITY} DEBIAN_VERSION=${SUITE:-$DEFAULT_SUITE} DEBIAN_TARBALL=${TARBALL:-$WORKDIR/debian-$DEBIAN_VERSION.tar.bz2} DEBIAN_TARBALL_COMPRESSOR=${TARBALL_COMPRESSOR:---bzip2} DEBIAN_DIR=debian-$DEBIAN_VERSION-chroot DEBTAKEOVER_PROFILE=${PROFILE:-$DEFAULT_PROFILE} DEBOOTSTRAP=${USER_DEBOOTSTRAP:-$DEFAULT_DEBOOTSTRAP} DEBOOTSTRAP_CHECK_DIRS="/etc/apt /bin /sbin /dev /var/lib/dpkg/info \ /var/lib/apt/lists /var/cache/apt" DEBOOTSTRAP_INCLUDES="ssh,grub,libssl0.9.6,zlib1g" if [ "$DEBTAKEOVER_PROFILE" = "colo" ]; then DEBOOTSTRAP_EXCLUDES="setserial,fdutils,ipchains,pcmcia-cs,ppp,pppconfig,\ pppoe,pppoeconf" else DEBOOTSTRAP_EXCLUDES="" fi # Impure non-Debian system log "-> $PROGRAM started on `date -Iseconds | tr 'T' ' '`" msg "-> Running $PROGRAM $VERSION" setup_shell distro_detect check_needed if [ "$DISTRO_MIXED" = no ]; then generic_exclusion_list if [ "$TARBALL" ]; then debian_tarball_prebuilt else debian_tarball_build fi distro_remove_list debian_dump fi # Mixed system debian_preconfigure distro_trash # Pure Debian system debian_configure msg "Congratulations, you have now a Debian $DEBIAN_VERSION system !" log "-> $PROGRAM finished on `date -Iseconds | tr 'T' ' '`" exit 0