#!/bin/sh -efu

export LC_ALL=C LANG=C LANGUAGE=C
export HOME="${HOME:-/root}"
export TMPDIR="${TMPDIR:-/tmp}"

PROG="${0##*/}"
destdir="/mnt/destination"
socket_path="/tmp/alterator/browser-sock"
logfile="/tmp/basesystem.log"

msg() {
	printf %s\\n "${0##*/}: $*" >&2
}

fatal() {
	msg "$*"
	exit 1
}

notify() {
	[ -z "$AUTOINSTALL" ] || return 0
	alterator-mailbox-send "$1" ||:
}

rpminstall() {
	local out= code= fs=
	if [ -z "$AUTOINSTALL" ]; then
		if ! out="$(install2-rpm -i --socket="$socket_path" "$@" 2>&1)"; then
			printf %s\\n "$out" >&2

			fs="$(printf %s "$out" |
				sed 	-e '/installing package .* needs .* on the .* filesystem.*/!d' \
					-e 's#^installing package .* the \(.*\) filesystem.*#\1#' \
					-e 's#^/mnt/destination#/#g' |
				sort -u |
				tr '\n' ' ')"

			if printf %s "$out" |grep -qs 'installing package .* needs .* inodes on the .* filesystem'; then
				code="DISKNODES"
			elif   printf %s "$out" |grep -qs 'installing package .* needs .* on the .* filesystem'; then
				code="DISKSPACE"
			fi

			if [ -n "$code" ]; then
				notify "error $code filesystems \"${fs% }\""
				return 1
			fi
		fi
	else
		rpm -iv "$@" ||:
	fi
}

max() {
	local n="$(wc -l < "$1")"
	echo "$(($n + 1))"
}

mountpoints() {
	df -k |
		sed -e '1,+0d' -e "\#[[:space:]]$destdir#!d" -e 's#[[:space:]]\+#\t#g' |
		egrep "$destdir(/var|/home)?" |
		sort -rgk2,2 |
		head -1 |
		cut --output-delimiter=\  -f2,6-
}

rpms_in="$destdir/.in"
rpms_in_type="fs"
create_in() {
	local max_fs max_swap fs
	fs="$(mountpoints)"
	[ -n "$fs" ] ||
		fatal "no mointpoints found in \`$destdir'"
	max_fs="${fs%% *}"
	fs="${fs#* }"
	msg "Filesystem size [$fs]: $max_fs"

	max_swap="$(sed -ne 's#^\(MemFree\|SwapFree\):[[:space:]]*\([[:digit:]]\+\) kB#\2+#p' /proc/meminfo |tr -d '\n')0"
	max_swap="$(($max_swap))"
	msg "MemFree + SwapFree: $max_swap"

	if [ "$max_fs" -lt "$max_swap" ]; then
		rpms_in_type="swap"
		rpms_in="$destdir/.in.tmpfs"
		mkdir -p -- "$rpms_in"
		mount -n -t tmpfs tmpfs "$rpms_in"
		msg "\`.in' will be created in tmpfs"
	else
		rpms_in_type="fs"
		rpms_in="$fs/.in"
		mkdir -p -- "$rpms_in"
		msg "$rpms_in: will be used"
	fi
}

remove_in() {
	[ "$rpms_in_type" != "swap" ] || umount -l "$rpms_in"
	rm -rf -- "$rpms_in"
}

counter=0
download() {
	local p n
	while read p; do
		n="${p##*/}"
		msg "GET: '$p'"
		[ "$p" != "${p#/}" ] &&
			cp -s -L "$p" "$rpms_in/" ||
			curl -s -S --retry 5 --retry-delay 2 -o "$rpms_in/$n" "$p" < /dev/null
		printf %s\\n "$rpms_in/$n" >>"$rpms_in/manifest.all"
		notify "package \"$n\" step $counter"
		counter=$(($counter + 1))
	done
}

if [ "$#" -eq 0 ]; then
	echo "Usage: ${0##*/} <manifest>" >&2
	exit 1
fi
manifest="$1" && shift
notify "init #t"
create_in

### Prepare
mkdir -p -- \
	"$destdir/etc/rpm" \
	"$destdir/etc/sysconfig" \
	"$destdir/dev/pts" \
	"$destdir/var/lib/rpm" \
	"$destdir/$HOME" \
	"$destdir/$TMPDIR"

# rpm postinstall scripts need this
cp -at "$destdir/dev" -- /dev/null /dev/zero /dev/full /dev/random /dev/urandom /dev/console /dev/tty /dev/ptmx

# We need /etc/rpm/macros to install languages
[ ! -f "/etc/rpm/macros" ] || cp -a /etc/rpm/macros "$destdir/etc/rpm/macros"

# Init rpm database
rpm --initdb --dbpath "$destdir/var/lib/rpm"

>"$rpms_in/manifest.all"

notify "stage download-pkgs max $(max "$manifest")"
# reorder to get setup and filesystem first.
egrep    '/(filesystem|setup)-' -- "$manifest" |download
egrep -v '/(filesystem|setup)-' -- "$manifest" |download
notify "package \" \" step $(max "$manifest")"

export DURING_INSTALL=1
notify "stage install-pkgs max $(max "$rpms_in/manifest.all")"
rc=
rpminstall --root "$destdir" -- "$rpms_in/manifest.all" >"$logfile" 2>&1 || rc=$?
[ -n "$rc" ] || notify "package \" \" step $(max "$rpms_in/manifest.all")"

remove_in
# Final report
[ -n "$rc" ] || notify "done #t"
