#!/bin/bash
# Script to create a complete system to build packages in a chroot
# environment.  This script ensures, that all packages given as
# parameter are installed. All other packges will be deleted.
#
# BUILD_ROOT  here the packages will be installed/deleted
# BUILD_RPMS  here we get our packages to install
# BUILD_ARCH  path of the architectures we try
#
# (c) 1997-2005 SuSE GmbH Nuernberg, Germany

#
# needed globals variables
#
export SRC
export YAST_IS_RUNNING="instsys"
PROC_IS_MOUNTED=

# should RPMs be installed with --force ?
USE_FORCE=false

BUILD_IS_RUNNING=$BUILD_ROOT/not-ready
TMPFILE=$BUILD_ROOT/tmpfile
RPMIDFMT="%{NAME}-%{VERSION}-%{RELEASE} %{BUILDHOST}-%{BUILDTIME}\n"

USEUSEDFORBUILD=
LIST_STATE=
if test "$1" = "--list-state" ; then
    LIST_STATE=true
    shift
fi
if test "$1" = "--useusedforbuild" ; then
    USEUSEDFORBUILD=--useusedforbuild
    shift
fi

PKGS=$*

#
# needed functions
#

function cleanup_and_exit {
    test -n "$PROC_IS_MOUNTED" && umount -n $BUILD_ROOT/proc 2>/dev/null
    exit ${1:-0}
}

function clean_build_root () {
        test -n "$BUILD_ROOT" && {
            umount -n $BUILD_ROOT/proc 2> /dev/null
            umount -n $BUILD_ROOT/dev/pts 2> /dev/null
            umount -n $BUILD_ROOT/mnt 2> /dev/null
            rm -rf $BUILD_ROOT/*
        }
}

PREINSTALLED_PKGS=

function preinstall {
    if test -n "$1" ; then
        echo "preinstalling $1..."
        cd $BUILD_ROOT || cleanup_and_exit 1
        pac_unpack $BUILD_ROOT/.init_b_cache/rpms/$1.rpm
        test -e install/predoinst.sh && mv install/predoinst.sh .init_b_cache/scripts/$1.pre
        test -e install/doinst.sh && mv install/doinst.sh .init_b_cache/scripts/$1.post
        rm -rf install
        PREINSTALLED_PKGS="$PREINSTALLED_PKGS $1"
    fi
    if test -n "$2" ; then
        for PKG in $PREINSTALLED_PKGS ; do
            if test -e "$BUILD_ROOT/.init_b_cache/scripts/$PKG.pre" ; then
                echo "running $PKG preinstall script"
                chroot $BUILD_ROOT sh ".init_b_cache/scripts/$PKG.pre" 0
                rm -f "$BUILD_ROOT/.init_b_cache/scripts/$PKG.pre"
            fi
            if test -e "$BUILD_ROOT/.init_b_cache/scripts/$PKG.post" ; then
                echo "running $PKG postinstall script"
                chroot $BUILD_ROOT sh ".init_b_cache/scripts/$PKG.post" 1
                rm -f "$BUILD_ROOT/.init_b_cache/scripts/$PKG.post"
            fi
        done
        PREINSTALLED_PKGS=
    fi
}

function reorder {
    REORDER_HAVE=
    rm -rf $BUILD_ROOT/.reorder
    mkdir -p $BUILD_ROOT/.reorder/.db
    rpm --initdb --dbpath $BUILD_ROOT/.reorder/.db
    for PKG in "$@" ; do
        touch $BUILD_ROOT/.reorder/$PKG
        test -e $BUILD_ROOT/.init_b_cache/alreadyinstalled/$PKG && continue
        test -f $BUILD_ROOT/.init_b_cache/rpms/$PKG.rpm && REORDER_HAVE="$REORDER_HAVE
$PKG.rpm"
    done
    if test -z "$REORDER_HAVE"; then
        rm -rf $BUILD_ROOT/.reorder
        echo "$@"
        return
    fi
    # manifest must be at least 96 bytes...
    echo "################################################################################################" "$REORDER_HAVE" > $BUILD_ROOT/.reorder/MANIFEST.rpm
    bash -c "cd $BUILD_ROOT/.init_b_cache/rpms && rpm -Uvv --dbpath $BUILD_ROOT/.reorder/.db --nosuggest --nodigest --nosignature --ignoresize --force --nodeps --test $BUILD_ROOT/.reorder/MANIFEST.rpm" 2>&1 | sed -n -e 's/-[^- ]*-[^- ]* / /' -e 's/^D:   install: \([^ ]*\) .*/\1/p' > $BUILD_ROOT/.reorder/.list
    rm -f $BUILD_ROOT/.reorder/MANIFEST.rpm
    REORDER_HAVE=
    for PKG in `cat $BUILD_ROOT/.reorder/.list`; do
        test -e $BUILD_ROOT/.reorder/$PKG || continue
        REORDER_HAVE="$REORDER_HAVE $PKG"
        rm $BUILD_ROOT/.reorder/$PKG
    done
    for PKG in "$@" ; do
        test -e $BUILD_ROOT/.reorder/$PKG || continue
        REORDER_HAVE="$REORDER_HAVE $PKG"
	REORDER_MISSED="$REORDER_MISSED $PKG"
        rm $BUILD_ROOT/.reorder/$PKG
    done
    echo $REORDER_HAVE
}

function create_devs {
    local com file mode arg

    mkdir -m 755 -p $BUILD_ROOT/dev/pts
    while read com file mode arg ; do
	rm -f $BUILD_ROOT/dev/$file
	if test $com = ln ; then
	    ln -s $arg $BUILD_ROOT/dev/$file
	    continue
	fi
	$com -m $mode $BUILD_ROOT/dev/$file $arg
    done << DEVLIST
	mknod null    666 c 1 3
	mknod zero    666 c 1 5
	mknod full    622 c 1 7
	mknod random  666 c 1 8
	mknod urandom 644 c 1 9
	mknod tty     666 c 5 0
	mknod ptmx    666 c 5 2
	mknod loop0   640 b 7 0
	mknod loop1   640 b 7 1
	mknod loop2   640 b 7 2
	mknod loop3   640 b 7 3
	ln    fd      777 /proc/self/fd
	ln    stdin   777 fd/0
	ln    stdout  777 fd/1
	ln    stderr  777 fd/2
DEVLIST
}


#
# now test if there was an incomplete run
#
if test -e $BUILD_IS_RUNNING ; then
    echo It seems that there was an incomplete setup of $BUILD_ROOT.
    echo To be sure, we will build it again completely...
    umount -n $BUILD_ROOT/proc 2> /dev/null
    umount -n $BUILD_ROOT/dev/pts 2> /dev/null
    umount -n $BUILD_ROOT/mnt 2> /dev/null
    echo "Your build system is broken!! Shall I execute"
    echo
    echo "    rm -rf $BUILD_ROOT"
    echo
    echo -n "[y/N] "
    read ANSWER
    test "$ANSWER" != y && {
      exit
    }
    clean_build_root
fi

#
# store that we start to build system
#
mkdir -p $BUILD_ROOT
touch $BUILD_IS_RUNNING

#
# now make sure that all the packages are installed.
#
rm -rf $BUILD_ROOT/.init_b_cache
mkdir -p $BUILD_ROOT/.init_b_cache/scripts

#
# create rpmdeps file
#
CACHE_FILE=$BUILD_ROOT/.srcfiles.cache
test "$BUILD_RPMS" != "$(cat $CACHE_FILE.id 2>/dev/null)" && rm -f $CACHE_FILE.id
test -f $CACHE_FILE || rm -f $CACHE_FILE.id
for SRC in ${BUILD_RPMS//:/ } ; do
    test -z "$SRC" && SRC=.
    test $SRC -nt $CACHE_FILE && rm -f $CACHE_FILE.id
done
if ! test -f $CACHE_FILE.id ; then
    test -z "$LIST_STATE" && echo initializing $CACHE_FILE with find command...
    for SRC in ${BUILD_RPMS//:/ } ; do
	test -z "$SRC" && SRC=.
	find $SRC -type f -name packages -print -o -follow -type f -name "*.rpm" -a ! -name "*src.rpm" -printf '%T@/%s/%i %p\n'
	echo
    done | createrpmdeps $CACHE_FILE > $CACHE_FILE.new
    mv $CACHE_FILE.new $CACHE_FILE
    echo "$BUILD_RPMS" > $CACHE_FILE.id
fi

#
# select and expand packages, rewrite specfile
#
test -z "$LIST_STATE" && echo "expanding package dependencies..."
if ! expanddeps $USEUSEDFORBUILD --dist "$BUILD_DIST" --depfile "$CACHE_FILE" --archpath "$BUILD_ARCH" --configdir /usr/lib/build/configs $PKGS > $BUILD_ROOT/.init_b_cache/rpmlist ; then
    rm -f $BUILD_IS_RUNNING
    cleanup_and_exit 1
fi
if test -n "$LIST_STATE" ; then
    rm -f $BUILD_IS_RUNNING
    while read PKG SRC ; do
	test "$PKG" = "preinstall:" && continue
	test "$PKG" = "dist:" && continue
	echo "${SRC##*/}"
    done < $BUILD_ROOT/.init_b_cache/rpmlist
    rm -rf $BUILD_ROOT/.init_b_cache
    exit 0
fi

PACKAGES_TO_INSTALL=
GUESSED_DIST=unknown
mkdir -p $BUILD_ROOT/.init_b_cache/rpms/$PKG.rpm
while read PKG SRC ; do
    if test "$PKG" = "preinstall:" ; then
	PACKAGES_TO_PREINSTALL=$SRC
	continue
    fi
    if test "$PKG" = "dist:" ; then
	GUESSED_DIST=$SRC
	continue
    fi
    ln -s "$SRC" $BUILD_ROOT/.init_b_cache/rpms/$PKG.rpm
    PACKAGES_TO_INSTALL="$PACKAGES_TO_INSTALL $PKG"
done < $BUILD_ROOT/.init_b_cache/rpmlist
echo "$GUESSED_DIST" > $BUILD_ROOT/.guessed_dist

#
# now test if there is already a build dir.
#
if test ! -f $BUILD_ROOT/var/lib/rpm/packages.rpm -a ! -f $BUILD_ROOT/var/lib/rpm/Packages ; then
    mkdir -p $BUILD_ROOT/var/lib/rpm || cleanup_and_exit 1
    mkdir -p $BUILD_ROOT/usr/src/packages/SOURCES || cleanup_and_exit 1
    mkdir -p $BUILD_ROOT/etc || cleanup_and_exit 1
    if [ ! -f $BUILD_ROOT/etc/HOSTNAME ] ; then
      /bin/hostname -f > $BUILD_ROOT/etc/HOSTNAME
    fi
    rpm_preinstalled=
    for PKG in $PACKAGES_TO_PREINSTALL ; do
	preinstall ${PKG##*/}
    done
    test -c $BUILD_ROOT/dev/null || create_devs
    preinstall '' true
    echo initializing rpm db...
    chroot $BUILD_ROOT rpm --initdb || cleanup_and_exit 1
fi

mkdir -p $BUILD_ROOT/proc
mount -n -tproc none $BUILD_ROOT/proc 2> /dev/null
PROC_IS_MOUNTED=true

test -e $BUILD_ROOT/etc/ld.so.conf || \
    cp $BUILD_ROOT/etc/ld.so.conf.in $BUILD_ROOT/etc/ld.so.conf
chroot $BUILD_ROOT /sbin/ldconfig 2> /dev/null

#
# get list and ids of already installed rpms
#
mkdir -p $BUILD_ROOT/.init_b_cache/alreadyinstalled
if test -f $BUILD_ROOT/var/lib/rpm/packages.rpm -o -f $BUILD_ROOT/var/lib/rpm/Packages ; then
    chroot $BUILD_ROOT rpm -qa --qf "%{NAME} $RPMIDFMT" | (
	while read pp ii; do
	    echo "$ii" > "$BUILD_ROOT/.init_b_cache/alreadyinstalled/$pp"
	done
    )
fi

#
# reorder packages
#
echo -n 'reordering...'
REORDER_MISSED=
PACKAGES_TO_INSTALL_FIRST=`reorder $PACKAGES_TO_INSTALL_FIRST`
PACKAGES_TO_INSTALL=`reorder $PACKAGES_TO_INSTALL`
echo 'done'
test -n "$REORDER_MISSED" && echo "WARNING: reorder missed$REORDER_MISSED"

#
# delete all packages we don't want
#
cp -a $BUILD_ROOT/.init_b_cache/alreadyinstalled $BUILD_ROOT/.init_b_cache/todelete
for PKG in $PACKAGES_TO_INSTALL_FIRST $PACKAGES_TO_INSTALL ; do
    rm -f $BUILD_ROOT/.init_b_cache/todelete/$PKG
done
for PKG in $BUILD_ROOT/.init_b_cache/todelete/* ; do
    PKG=${PKG##*/}
    test "$PKG" = "*" && continue
    echo deleting `sed -e 's/ .*//' < $BUILD_ROOT/.init_b_cache/todelete/$PKG`
    chroot $BUILD_ROOT rpm --nodeps -e $PKG 2>&1 | \
	grep -v -e "^r.*failed: No such file or directory" -e "^error: failed to stat .*: No such file or directory"
done
rm -rf $BUILD_ROOT/.init_b_cache/todelete

rm -rf $BUILD_ROOT/installed-pkg
mkdir -p $BUILD_ROOT/installed-pkg

RPMCHECKOPTS=
test -x $BUILD_ROOT/usr/lib/rpm/rpmi && RPMCHECKOPTS="--nodigest --nosignature"

for PKG in $PACKAGES_TO_INSTALL_FIRST RUN_LDCONFIG $PACKAGES_TO_INSTALL ; do
    case $PKG in
      RUN_LDCONFIG)
        test -x $BUILD_ROOT/sbin/ldconfig && chroot $BUILD_ROOT /sbin/ldconfig 2>&1
        continue
      ;;
    esac
    test -f $BUILD_ROOT/installed-pkg/$PKG && continue
    test -L $BUILD_ROOT/.init_b_cache/rpms/$PKG.rpm || continue

    PKGID=`rpm -qp --qf "$RPMIDFMT" $BUILD_ROOT/.init_b_cache/rpms/$PKG.rpm`

    if test -f $BUILD_ROOT/.init_b_cache/alreadyinstalled/$PKG ; then
	if test "$PKGID" != "`cat $BUILD_ROOT/.init_b_cache/alreadyinstalled/$PKG`" ; then
	    echo deleting unwanted `sed -e 's/ .*//' < $BUILD_ROOT/.init_b_cache/alreadyinstalled/$PKG`
	    chroot $BUILD_ROOT rpm --nodeps -e $PKG 2>&1 | \
		grep -v -e "^r.*failed: No such file or directory" -e "^error: failed to stat .*: No such file or directory"
	elif test "$VERIFY_BUILD_SYSTEM" = true ; then
	    chroot $BUILD_ROOT rpm --verify $PKG 2>&1 | tee $TMPFILE
	    if grep ^missing $TMPFILE > /dev/null ; then
		echo deleting incomplete ${PKGID%% *}
		chroot $BUILD_ROOT rpm --nodeps -e $PKG 2>&1 | \
		    grep -v -e "^r.*failed: No such file or directory" -e "^error: failed to stat .*: No such file or directory"
	    else
		echo "keeping ${PKGID%% *}"
		echo "$PKGID" > $BUILD_ROOT/installed-pkg/$PKG
		continue
	    fi
	else
	    echo "keeping ${PKGID%% *}"
	    echo "$PKGID" > $BUILD_ROOT/installed-pkg/$PKG
	    continue
	fi
    fi
    export ADDITIONAL_PARAMS=
    if test "$USE_FORCE" = true ; then
        export ADDITIONAL_PARAMS="$ADDITIONAL_PARAMS --force"
    fi
    echo "installing ${PKGID%% *}"
    rm -f $BUILD_ROOT/.init_b_cache/$PKG.rpm
    cp $BUILD_ROOT/.init_b_cache/rpms/$PKG.rpm $BUILD_ROOT/.init_b_cache/$PKG.rpm || cleanup_and_exit 1
    ( chroot $BUILD_ROOT rpm --nodeps -U --oldpackage --ignoresize $RPMCHECKOPTS \
		$ADDITIONAL_PARAMS .init_b_cache/$PKG.rpm 2>&1 || \
          touch $BUILD_ROOT/exit ) | \
              grep -v "^warning:.*saved as.*rpmorig$"
    rm -f $BUILD_ROOT/.init_b_cache/$PKG.rpm
    test -e $BUILD_ROOT/exit && cleanup_and_exit 1
    echo "$PKGID" > $BUILD_ROOT/installed-pkg/$PKG
done

rm -f $BUILD_ROOT/pkg-to-install $BUILD_ROOT/pkg-not-to-install

cd $BUILD_ROOT || cleanup_and_exit 1

#
# setup /etc/mtab
#
rm -f $BUILD_ROOT/etc/mtab
cp /proc/mounts $BUILD_ROOT/etc/mtab
chmod 644 $BUILD_ROOT/etc/mtab

#
# to be sure, path is set correctly, we have to source /etc/profile before
# starting rpm.
#
# XXX
#rm -f $BUILD_ROOT/bin/rpm.sh
#cp $BUILD_LIBDIR/lib/rpm.sh $BUILD_ROOT/bin/rpm.sh
#chmod 755 $BUILD_ROOT/bin/rpm.sh
#test -f $BUILD_ROOT/bin/rpm -a ! -L $BUILD_ROOT/bin/rpm && \
#    mv $BUILD_ROOT/bin/rpm $BUILD_ROOT/bin/rpm.bin
#rm -f $BUILD_ROOT/bin/rpm
#ln -s rpm.sh $BUILD_ROOT/bin/rpm

#
# some packages use uname -r to decide which kernel is used to build for.
# this does not work in autobuild always.  Here is a wrapper script, that
# gets Version from kernel sources.
#
# XXX
#rm -f $BUILD_ROOT/bin/uname.sh
#cp -v $BUILD_LIBDIR/lib/uname.sh $BUILD_ROOT/bin/uname.sh
#chmod 755 $BUILD_ROOT/bin/uname.sh
#test -f $BUILD_ROOT/bin/uname -a ! -L $BUILD_ROOT/bin/uname && \
#    mv $BUILD_ROOT/bin/uname $BUILD_ROOT/bin/uname.bin
#rm -f $BUILD_ROOT/bin/uname
#ln -s uname.sh $BUILD_ROOT/bin/uname

#
# some distributions have a /etc/rpmrc or /etc/rpm/macros and some not.
# make sure, that it is setup correctly.
#
# XXX
#rm -f $BUILD_ROOT/etc/rpmrc
#if test -e $BUILD_LIBDIR/lib/rpmrc.$BUILD_BASENAME ; then
#    cp -v $BUILD_LIBDIR/lib/rpmrc.$BUILD_BASENAME $BUILD_ROOT/etc/rpmrc
#elif test -e $BUILD_LIBDIR/lib/rpmrc ; then
#    cp -v $BUILD_LIBDIR/lib/rpmrc $BUILD_ROOT/etc/rpmrc
#fi

# XXX
#rm -f $BUILD_ROOT/etc/rpm/macros $BUILD_ROOT/etc/rpm/suse_macros
#mkdir -p $BUILD_ROOT/etc/rpm
#if test -e $BUILD_LIBDIR/lib/macros.$BUILD_BASENAME ; then
#    cp -v $BUILD_LIBDIR/lib/macros.$BUILD_BASENAME $BUILD_ROOT/etc/rpm/macros
#    cp -v $BUILD_LIBDIR/lib/macros.$BUILD_BASENAME $BUILD_ROOT/etc/rpm/suse_macros
#elif test -e $BUILD_LIBDIR/lib/macros ; then
#    cp -v $BUILD_LIBDIR/lib/macros $BUILD_ROOT/etc/rpm/macros
#    cp -v $BUILD_LIBDIR/lib/macros $BUILD_ROOT/etc/rpm/suse_macros
#fi

#
# make sure, that our nis is not present in the chroot system
#
test -e $BUILD_ROOT/etc/nsswitch.conf && {
    echo removing nis flags from $BUILD_ROOT/etc/nsswitch.conf...
    cat $BUILD_ROOT/etc/nsswitch.conf | sed -e"s:nis::g" > \
        $BUILD_ROOT/etc/nsswitch.conf.tmp
    mv $BUILD_ROOT/etc/nsswitch.conf.tmp $BUILD_ROOT/etc/nsswitch.conf
}

#
# creating some default directories
for DIR in /usr/share/doc/packages \
           /usr/X11R6/include/X11/pixmaps \
           /usr/X11R6/include/X11/bitmaps ; do
    mkdir -p $BUILD_ROOT/$DIR
done

for FILE in /var/run/utmp /var/log/wtmp ; do
    touch $BUILD_ROOT/$FILE
done

echo now finalizing build dir...
CHROOT_RETURN="`chroot $BUILD_ROOT /sbin/ldconfig 2>&1`"
case "$CHROOT_RETURN" in
    *warning:*)
      chroot $BUILD_ROOT /sbin/ldconfig
      echo
      echo chroot $BUILD_ROOT /sbin/ldconfig
      echo
      echo "$CHROOT_RETURN"
      echo
      echo "Problem with ldconfig.  It's better to reinit the build system..."
      echo
      cleanup_and_exit 1
    ;;
esac
chroot $BUILD_ROOT /usr/sbin/Check

mkdir -p $BUILD_ROOT/var/adm/packages
touch $BUILD_ROOT/var/adm/packages
if grep norestarts $BUILD_ROOT/sbin/SuSEconfig > /dev/null ; then
    chroot $BUILD_ROOT /sbin/SuSEconfig --norestarts --force
else
    chroot $BUILD_ROOT /sbin/SuSEconfig --force
fi

if test -x $BUILD_ROOT/usr/X11R6/bin/switch2mesasoft ; then
  chroot $BUILD_ROOT /usr/X11R6/bin/switch2mesasoft
fi

for PROG in /usr/bin/TeX/texhash /usr/bin/texhash ; do
    test -x $BUILD_ROOT/$PROG && \
        chroot $BUILD_ROOT bash -c ". /etc/profile ; $PROG"
done

if test -e $BUILD_ROOT/usr/share/zoneinfo/UTC ; then
    chroot $BUILD_ROOT zic -l UTC
fi

rm -f $BUILD_IS_RUNNING

rm -f $TMPFILE
cleanup_and_exit 0
