#!/bin/sh -ef
#
# Copyright (C) 2003-2007  Dmitry V. Levin <ldv@altlinux.org>
# 
# The contents cache functions for the hsh-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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
#

rebuild_contents_cache=
contents_index_list=
contents_index_bin=chroot/.host/contents_index_bin

archive_contents_cache()
{
	[ -z "$no_contents_indices" -a -n "$rebuild_contents_cache" ] || return 0

	local terminated=
	trap 'terminated=1' HUP INT QUIT TERM

	local contents_archive="cache/contents/contents_index_bin"
	if install -p -m644 $verbose -- "$contents_index_bin" "$contents_archive" && [ -z "$terminated" ]; then
		Verbose "archived contents index"
	else
		rm -f -- "$contents_archive"
		Fatal 'Archiving of contents index failed.'
	fi

	trap - HUP INT QUIT TERM

	# Regenerate data for later cache validation.
	mv -f $verbose cache/contents/list{.new,}/index
	rm -rf $verbose cache/contents/index
	mv -f $verbose cache/contents/index{.new,}
} # archive_contents_cache

unpack_contents_cache()
{
	[ -z "$no_contents_indices" ] || return 0

	local f=cache/contents/contents_index_bin
	install -p -m644 $verbose -- "$f" \
		"$contents_index_bin" &&
		Verbose 'Unpacked contents index.' ||
		Fatal 'Unpacking of contents index failed.'
} # unpack_contents_cache

make_contents_index_list()
{
	[ -z "$no_contents_indices" ] || return 0

	contents_index_list="$(
	local f
	awk '
/^rpm[[:space:]]/ {
	if(NF==4){printf("%s/%s/base/contents_index\n",$2,$3);next}
	if(NF==5){printf("%s/%s/base/contents_index\n",$3,$4);next}
}' <aptbox/etc/apt/sources.list |
		cut -d: -f2- |while read f; do
			[ -r "$f" ] || continue
			printf %s\\n "$f"
		done
	)"
	contents_index_list="$(printf %s "$contents_index_list" |grep -v '^$' ||:)"
}

check_contents_cache()
{
	[ -z "$no_contents_indices" ] || return 0

	make_contents_index_list &&
		Verbose 'Created contents index list.' ||
		Fatal 'Failed to create contents index list.'

	[ -z "$no_cache" ] || return 0

	printf %s "$contents_index_list" >cache/contents/list.new/index
	[ ! -s cache/contents/list.new/index ] || echo >>cache/contents/list.new/index

	local f n
	local bad="cache/contents/list.new/bad"
	rm -f "$bad"
	cat cache/contents/list.new/index |
		while read f; do
			[ -n "$f" ] || continue
			local n
			n="$(printf %s "$f" |sed -e s,/,_,g)"
			if ! touch -r "$f" "cache/contents/index.new/$n"; then
				printf %s\\n "$n" >"$bad"
				break
			fi
		done
	[ ! -f "$bad" ] || Fatal 'Failed to check contents cache.'

	while :; do
		if [ ! -s cache/contents/contents_index_bin ]; then
			Verbose 'Missing contents_index_bin archive, invalidating contents cache.'
			rebuild_contents_cache=1
			break
		fi

		if ! cmp -s cache/contents/list{.new,}/index; then
			Verbose 'Index list changed, invalidating contents cache.'
			rebuild_contents_cache=1
			break
		fi

		rm -f "$bad"
		cat cache/contents/list.new/index |
			while read f; do
				[ -n "$f" ] || continue
				n="$(printf %s "$f" |sed -e s,/,_,g)"
				if [ "cache/contents/index.new/$n" -nt "cache/contents/index/$n" -o \
				     "cache/contents/index.new/$n" -ot "cache/contents/index/$n" ]; then
					Verbose "Index $n changed, invalidating contents cache."
					printf %s\\n "$n" >"$bad"
					break
				fi
			done
		if [ -f "$bad" ]; then
			rebuild_contents_cache=1
			break
		fi
		break
	done
} # check_contents_cache

prepare_contents()
{
	local tmpdir
	tmpdir="$1"
	shift

	local contents="$tmpdir/contents"
	local dups="$tmpdir/dups"
	local uniq="$tmpdir/uniq"
	local index="$tmpdir/index"

	# find dups.
	cut -f1 <"$contents" |
		uniq -c |
		awk '{if ($1 != "1") printf("%s\t%s\n",$2,$2)}' >"$dups"

	# find uniquie lines.
	cut -f1 "$dups" |
		join -v1 "$contents" - |
		tr -s ' ' '\t' >"$uniq"

	sort -u "$dups" "$uniq" >"$index"

	grep '^/bin/' "$index" || [ $? -eq 1 ]
	grep '^/usr/bin/' "$index" || [ $? -eq 1 ]
	grep '^/sbin/' "$index" || [ $? -eq 1 ]
	grep '^/usr/sbin/' "$index" || [ $? -eq 1 ]
	grep '^/usr/X11R6/bin/' "$index" || [ $? -eq 1 ]
	grep '^/etc/' "$index" || [ $? -eq 1 ]
}

create_contents()
{
	if [ -n "$no_contents_indices" ]; then
		contents_index_bin=
		return 0
	fi

	local tmpdir=cache/contents/tmp
	rm -rf "$tmpdir"
	mkdir -p "$tmpdir"
	local bad="$tmpdir/bad"
	local contents="$tmpdir/contents"

	cat cache/contents/list.new/index 2>/dev/null |
		while read f; do
			if ! egrep '^/((usr/)?bin|(usr/)?sbin|usr/X11R6/bin|etc)/' "$f"; then
				Verbose "Failed to process contents index $f."
				printf %s\\n "$f" >"$bad"
				break
			fi
		done >"$contents"

	if [ -f "$bad" ]; then
		rm -rf "$tmpdir"
		Fatal 'Failed to create contents index.'
	fi

	if ! LC_COLLATE=C prepare_contents "$tmpdir" >"$contents_index_bin"; then
		rm -rf "$tmpdir"
		Fatal 'Failed to prepare contents index.'
	fi
	rm -rf "$tmpdir"
	Verbose 'Prepared contents index.'

	if [ -s "$contents_index_bin" ]; then
		chmod 644 "$contents_index_bin"
		archive_contents_cache
	else
		contents_index_bin=
	fi
}
