#!/bin/sh -e
#
# $Id: cache_contents,v 1.5 2003/10/23 12:25:55 ldv Exp $
# Copyright (C) 2003  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

	install -p -m644 $verbose -- "$contents_index_bin" \
		cache/contents/contents_index_bin &&
		Verbose "archived contents index" ||
		Fatal "archiving of contents index failed."
} # 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
			echo "$f"
		done
	)"
}

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

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

	local f
	cat cache/contents/list.new/index |
		while read f; do
			local n
			n="$(echo "$f" |sed -e s,/,_,g)"
			touch -r "$f" "cache/contents/index.new/$n"
		done

	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

		local bad="cache/contents/list.new/bad"
		rm -f "$bad"
		cat cache/contents/list.new/index |
			while read f; do
				local n
				n="$(echo "$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"
					echo "$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()
{
	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"
				echo "$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
}
