#!/bin/sh -e
#
# $Id: cache_chroot,v 1.42 2005/06/17 10:13:56 ldv Exp $
# Copyright (C) 2003-2005  Dmitry V. Levin <ldv@altlinux.org>
# 
# The chroot cache functions for the initroot
#
# This file 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#

rebuild_chroot_cache=

archive_chroot_cache()
{
	[ -n "$rebuild_chroot_cache" ] || return 0

	local rpmdb_archive="cache/chroot/rpmdb.tar"
	local chroot_archive="cache/chroot/chroot.cpio"

	trap 'rm -f -- "$rpmdb_archive" "$chroot_archive"' EXIT HUP INT QUIT TERM

	# rpmdb
	tar -cf "$rpmdb_archive" -C aptbox/var/lib/rpm/ . &&
		Verbose 'RPM database archivation complete.' ||
		Fatal 'RPM database archivation failed.'

	# chroot
	local list
	list=`ls -1 chroot/ |grep -v ^dev` && [ -n "$list" ] &&
		list=`printf %s "$list" |tr '[:space:]' ' '` ||
		Fatal 'Chroot is not ready for archivation.'

	create_entry_fakeroot_header
	cat >>"$entry" <<__EOF__
cd /
find $list |cpio --create --quiet --format=newc
__EOF__

	wlimit_time_elapsed=$wlimit_time_long wlimit_time_idle=$wlimit_time_long \
	    chrootuid1 >"$chroot_archive" &&
		Verbose 'Chroot archivation complete.' ||
		Fatal 'Chroot archivation failed.'

	trap - EXIT HUP INT QUIT TERM

	# Regenerate data for later cache validation.
	mv -f $verbose cache/chroot/list{.new,}/init
	mv -f $verbose cache/chroot/list{.new,}/build
	rm -rf cache/chroot/package
	mv -f $verbose cache/chroot/package{.new,}
} # archive_chroot_cache

check_chroot_cache()
{
	[ -z "$no_cache" ] || return 0

	local f n
	local bad="cache/chroot/list.new/bad"
	rm -f "$bad"
	cat cache/chroot/list.new/{init,build} |
		while read f; do
			[ -n "$f" ] || continue
			n="${f##*/}"
			if ! touch -r "$f" "cache/chroot/package.new/$n"; then
				printf %s\\n "$n" >"$bad"
				break
			fi
		done
	[ ! -f "$bad" ] || Fatal 'Failed to check chroot cache.'

	while :; do
		for f in cache/chroot/{rpmdb.tar,chroot.cpio}; do
			if [ ! -s "$f" ]; then
				Verbose "Missing $f archive, invalidating chroot cache."
				rebuild_chroot_cache=1
				break 2
			fi
		done

		if ! cmp -s cache/chroot/list{.new,}/init; then
			Verbose 'Init list changed, invalidating chroot cache.'
			rebuild_chroot_cache=1
			break
		fi

		if ! cmp -s cache/chroot/list{.new,}/build; then
			Verbose 'Build list changed, invalidating chroot cache.'
			rebuild_chroot_cache=1
			break
		fi

		rm -f "$bad"
		cat cache/chroot/list.new/{init,build} |
			while read f; do
				n="${f##*/}"
				if [ "cache/chroot/package.new/$n" -nt "cache/chroot/package/$n" -o \
				     "cache/chroot/package.new/$n" -ot "cache/chroot/package/$n" ]; then
					Verbose "package $n changed, invalidating chroot cache"
					printf %s\\n "$n" >"$bad"
					break
				fi
			done
		if [ -f "$bad" ]; then
			rebuild_chroot_cache=1
			break
		fi
		break
	done
} # check_chroot_cache

unpack_chroot_cache()
{
	local f

	# rpmdb
	f="cache/chroot/rpmdb.tar"
	rm -f aptbox/var/lib/rpm/*
	tar -xf "$f" -C aptbox/var/lib/rpm/ &&
		Verbose "Unpacked $f." ||
		Fatal "Unpack of $f failed."
		
	# chroot
	f="cache/chroot/chroot.cpio"
	wlimit_time_elapsed=$wlimit_time_long wlimit_time_idle=$wlimit_time_long \
	    chrootuid1 /.host/cpio --extract --make-directories --sparse --quiet <"$f" &&
		Verbose "Unpacked $f." ||
		Fatal "Unpack of $f failed."
	if [ -n "$save_fakeroot" ]; then
		wlimit_time_elapsed=$wlimit_time_short wlimit_time_idle=$wlimit_time_short \
		    chrootuid1 /bin/touch /.fakedata &&
			Verbose "Created fakedata." ||
			Fatal "Failed to create fakedata."
		create_entry_fakeroot_header
		cat >>"$entry" <<__EOF__
cd /
cpio --extract --make-directories --sparse --quiet --unconditional
__EOF__
		wlimit_time_elapsed=$wlimit_time_long wlimit_time_idle=$wlimit_time_long \
		    chrootuid1 <"$f" &&
			Verbose "Unpacked $f for fakedata." ||
			Fatal "Unpack of $f for fakedata failed."
	fi
	wlimit_time_elapsed=$wlimit_time_short wlimit_time_idle=$wlimit_time_short wlimit_bytes_written=$wlimit_bytes_out \
	    chrootuid1 /bin/chmod $verbose 1777 /usr/src
} # unpack_chroot_cache

create_chroot()
{
	copy_chroot_incoming $initlist

	local f
	for f in $initlist; do
		rpm2cpio "$f" |wlimit_time_elapsed=$wlimit_time_long wlimit_time_idle=$wlimit_time_long \
		    chrootuid1 /.host/cpio --extract --make-directories --sparse --quiet &&
			Verbose "Unpacked ${f##*/}." ||
			Fatal "Unpack of ${f##*/} failed."
	done
	Verbose 'Unpacked initial package list.'
	if [ -n "$save_fakeroot" ]; then
		wlimit_time_elapsed=$wlimit_time_short wlimit_time_idle=$wlimit_time_short \
		    chrootuid1 /bin/touch /.fakedata &&
			Verbose "Created fakedata." ||
			Fatal "Failed to create fakedata."
		create_entry_fakeroot_header
		cat >>"$entry" <<__EOF__
cd /
cpio --extract --make-directories --sparse --quiet --unconditional
__EOF__
		for f in $initlist; do
			rpm2cpio "$f" |wlimit_time_elapsed=$wlimit_time_long wlimit_time_idle=$wlimit_time_long \
			    chrootuid1 &&
				Verbose "Unpacked ${f##*/} for fakedata." ||
				Fatal "Unpack of ${f##*/} for fakedata failed."
		done
	fi

	create_entry_fakeroot_header
	cat >>"$entry" <<__EOF__
export DURING_INSTALL=1
# WORKAROUND: mtab is missing in setup-2.2.2-alt1
touch /etc/mtab
# /WORKAROUND
# WORKAROUND: filesystem < 2.1.7-alt1 doesn't provide /sys
mkdir -p /sys
# /WORKAROUND
rm -f /etc/rpm/macros.db1
# WORKAROUND: glibc-locales is too large
echo '%_install_langs $install_langs' >>/etc/rpm/macros
# /WORKAROUND
rpmdb --initdb
__EOF__
	Verbose "Created entry point: $entry"

	wlimit_time_elapsed=$wlimit_time_short wlimit_time_idle=$wlimit_time_short wlimit_bytes_written=$wlimit_bytes_out \
	    chrootuid1 &&
		Verbose 'Created RPM database.' ||
		Fatal 'Failed to create RPM database.'

	create_entry_fakeroot_header
	cat >>"$entry" <<__EOF__
export DURING_INSTALL=1
${exclude_docs:+export RPM_EXCLUDEDOCS=1}
rpmi -i $verbose $exclude_docs --justdb --nodeps $(for f in $initlist; do printf %s "\"$(quote_arg "${f##*/}")\" "; done)
__EOF__

	wlimit_time_elapsed=$wlimit_time_long wlimit_time_idle=$wlimit_time_short \
	    chrootuid1 &&
		Verbose 'Installed initial package list.' ||
		Fatal 'Failed to install initial package list.'

	purge_chroot_in
	update_RPM_database --nodeps $initlist

	for f in /etc/host.conf /etc/hosts /etc/resolv.conf; do
		if [ -r "$f" -a -s "$f" ]; then
			create_entry_fakeroot_header
			cat >>"$entry" <<__EOF__
cat >$f
__EOF__
			wlimit_time_elapsed=$wlimit_time_short wlimit_time_idle=$wlimit_time_short wlimit_bytes_written=$wlimit_bytes_out \
			    chrootuid1 <"$f" &&
				Verbose "Installed $f file." ||
				Fatal "Failed to install $f file."
		fi
	done

	# At this stage, RPM inside chroot is fully functional.

	if [ "$buildlist" ]; then
		copy_chroot_incoming $buildlist

		create_entry_fakeroot_header
		cat >>"$entry" <<__EOF__
export DURING_INSTALL=1
${exclude_docs:+export RPM_EXCLUDEDOCS=1}
# WORKAROUND: dev shouldn't be installed
rpmi -i $rpm_verbose $hash $exclude_docs --nodeps $(for f in $buildlist; do f="${f##*/}"; [ -z "${f##dev[-_][0-9]*}" ] || printf %s "\"$(quote_arg "$f")\" "; done)
rpmi -i $verbose $exclude_docs --nodeps --justdb $(for f in $buildlist; do f="${f##*/}"; [ -n "${f##dev[-_][0-9]*}" ] || printf %s "\"$(quote_arg "$f")\" "; done)
# /WORKAROUND
__EOF__

		wlimit_time_elapsed=$wlimit_time_long wlimit_time_idle=$wlimit_time_short \
		    chrootuid1 &&
			Verbose 'Installed build package list.' ||
			Fatal 'Failed to install build package list.'

		purge_chroot_in
		update_RPM_database $buildlist

		# First time scripts.

		create_entry_fakeroot_header
		cat >>"$entry" <<__EOF__
ldconfig
adjust_kernel_headers
groupadd -g $gid0 caller ||:
useradd -M -u $uid0 -g $gid0 -d / caller ||:
groupadd -g $gid1 rooter
useradd -M -u $uid1 -g $gid1 -d /root rooter
groupadd -g $gid2 builder
useradd -M -u $uid2 -g $gid2 -d /usr/src builder
__EOF__

		wlimit_time_elapsed=$wlimit_time_short wlimit_time_idle=$wlimit_time_short wlimit_bytes_written=$wlimit_bytes_out \
		    chrootuid1 /bin/chmod $verbose 1777 /usr/src &&
		wlimit_time_elapsed=$wlimit_time_short wlimit_time_idle=$wlimit_time_short wlimit_bytes_written=$wlimit_bytes_out \
		    chrootuid1 &&
			Verbose 'First time initialization complete.' ||
			Fatal 'First time initialization failed.'
	fi # $buildlist

	archive_chroot_cache
} # create_chroot
