#!/bin/sh -e
#
# $Id: cache_contents,v 1.11 2004/06/23 11:50:17 ldv Exp $
# Copyright (C) 2003, 2004  Dmitry V. Levin <ldv@altlinux.org>
# 
# The contents 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_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
} # 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

	# Regenerate data for later cache validation.
	mv -f $verbose cache/contents/list{.new,}/index
	rm -f cache/contents/index/*
	find cache/contents/index.new/ -type f -maxdepth 1 -print0 |
		xargs -r0 mv -f --target-directory=cache/contents/index/ --
	[ -z "$rebuild_contents_cache" ] || rm -f cache/contents/contents_index_bin
} # 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/index |
		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
}
