#!/bin/sh
. /usr/share/debconf/confmodule
set -e

ARCH=$(udpkg --print-architecture)

ISO_COUNT=0
ISO_MOUNT_COUNT=0
MOUNTABLE_DEVS_COUNT=0
TOPLEVEL_DIRS_COUNT=0

log () {
    logger -t iso-scan "$@"
}

mount_device () {
	dev_to_mount=$1
	db_subst iso-scan/progress_mount DRIVE $dev_to_mount
	db_progress INFO iso-scan/progress_mount
	mount -t auto -o ro $dev_to_mount /hd-media 2>/dev/null
}
		
is_debian_iso () {
	test -e /cdrom/.disk/info
}

register_cd () {
	# Make sure that the iso is usable for the architecture. If so,
	# set the suite and codename to the suite/codename that is on the CD.
	# This assumes that there will be no more than one distribution on
	# the CD, and that one of the testing, stable, or unstable links will
	# point to it. Since the CDs currently have many links, parse the
	# Release file to get the actual suite name to use.
	# Prefer the suite in default-release.
	for dir in $(cat /etc/default-release) $(ls -1 /cdrom/dists/); do
		relfile=/cdrom/dists/$dir/Release
		if [ -e $relfile ] && \
		   egrep -q "Architectures:.* $ARCH( |$)" $relfile; then
			suite=$(sed -n 's/^Suite: *//p' $relfile)
			codename=$(sed -n 's/^Codename: *//p' $relfile)
			log "Detected ISO with '$suite' ($codename) distribution"
			db_set cdrom/suite $suite
			db_set cdrom/codename $codename
			db_subst iso-scan/success SUITE $suite

			description=`sed -n 's/^Description: *//p' $relfile`
			db_subst iso-scan/success DESCRIPTION $description

			return 0
		fi
	done

	return 1
}

# Try to mount a file as an iso, and see if it's a Debian cd.
try_iso () {
	iso_to_try=$1
	iso_device=$2
	if mount -t iso9660 -o loop,ro,exec $iso_to_try /cdrom 2>/dev/null; then
		ISO_MOUNT_COUNT=$(expr $ISO_MOUNT_COUNT + 1)
		if is_debian_iso; then
			if register_cd $iso_to_try $iso_device; then
				# This could be more sophisticated, and try
				# to deal with multiple Debian ISO's. For
				# now, once we've got a Debian ISO, any 
				# Debian ISO, we're done.
				db_progress STOP
				db_subst iso-scan/success FILENAME $iso_to_try
				db_set iso-scan/filename $iso_to_try
				db_subst iso-scan/success DEVICE $iso_device
				db_input medium iso-scan/success || true
				db_go || true
	
				anna-install apt-mirror-setup || true
				if [ ! -e /cdrom/.disk/base_installable ]; then
					log "Base system not installable from CD image, requesting choose-mirror"
					anna-install choose-mirror || true
				else
					anna-install apt-cdrom-setup || true

					# Install <codename>-support udeb (if available).
					db_get cdrom/codename
					anna-install $RET-support || true
				fi
				exit 0
			else
				log "Debian ISO not usable, skipping"
			fi
		else
			log "Not a Debian ISO"
			umount /cdrom
		fi
	else
		log "Failed mounting $iso_to_try"
	fi
}

# Try to unmount anything that was previously mounted.
umount /cdrom 2>/dev/null || true
umount /hd-media 2>/dev/null || true

# Hopefully this will find the drive.
hw-detect iso-scan/detect_progress_title || true

# Load up every filesystem known to man. The drive could have anything.
FS="ext2 ext3 ext4 reiserfs fat vfat xfs jfs iso9660 hfsplus hfs ntfs"
for fs in $FS; do
	modprobe $fs >/dev/null 2>&1 || true
done
modprobe loop >/dev/null || true

mkdir /cdrom 2>/dev/null || true
mkdir /hd-media 2>/dev/null || true

log "First pass: Look for ISOs near top-level of each filesystem."
DEVS="$(list-devices partition; list-devices disk; list-devices maybe-usb-floppy)"
# Repeat twice if necessary, to accomodate devices that need some
# time to initialise, like USB devices.
for i in 1 2; do
	DEV_COUNT=0
	for dev in $DEVS; do
		DEV_COUNT=$(expr $DEV_COUNT + 1)
	done

	db_progress START 0 $DEV_COUNT iso-scan/progress_title

	for dev in $DEVS; do
		if ! mount_device $dev; then
			log "Waiting for $dev to possibly get ready.."
			sleep 3
			if ! mount_device $dev; then
				continue
			fi
		fi

		db_subst iso-scan/progress_scan DRIVE $dev
		log "Mounted $dev for first pass"
		MOUNTABLE_DEVS="$MOUNTABLE_DEVS $dev"
		MOUNTABLE_DEVS_COUNT=$(expr $MOUNTABLE_DEVS_COUNT + 1)
		cd /hd-media
		for dir in . *; do
			if [ -d "$dir" ]; then
				if [ "$dir" != "." ]; then 
					TOPLEVEL_DIRS_COUNT=$(expr $TOPLEVEL_DIRS_COUNT + 1)
				fi
				db_subst iso-scan/progress_scan DIRECTORY "$dir/"
				db_progress INFO iso-scan/progress_scan
				for iso in $dir/*.iso $dir/*.ISO; do
					if [ -e $iso ]; then
						log "Found ISO $iso on $dev"
						ISO_COUNT=$(expr $ISO_COUNT + 1)
						try_iso $iso $dev
					fi
				done
			fi
		done
		cd /
		umount /hd-media

		# It's possible that the ISO was written right to the front of a
		# device, and not to a filesystem. (Hey, we may even be spinning
		# a real CD here, though that would be pretty weird..)
		try_iso $dev $dev

		db_progress STEP 1
	done

	db_progress STOP

	OLDDEVS="$DEVS"
	DEVS="$(list-devices partition; list-devices disk; list-devices maybe-usb-floppy)"
	if [ "$OLDDEVS" != "$DEVS" ]; then
		# Give USB time to settle, make sure all devices are seen
		# this time though.
		sleep 5
	else
		break
	fi
done

if [ "$MOUNTABLE_DEVS_COUNT" != 0 ]; then
	# Ask about the more expensive second pass.
	db_subst iso-scan/ask_second_pass NUM_FILESYSTEMS $MOUNTABLE_DEVS_COUNT
	db_subst iso-scan/ask_second_pass NUM_DIRS $TOPLEVEL_DIRS_COUNT
	db_input critical iso-scan/ask_second_pass || true
	db_go || true

	db_get iso-scan/ask_second_pass
	if [ "$RET" = true ]; then
		db_progress START 0 $TOPLEVEL_DIRS_COUNT iso-scan/progress_title
		log "Second pass: Search whole filesystems for ISOs."
		# To save time, only ones we mounted successfully before.
		for dev in $MOUNTABLE_DEVS; do
			if mount_device $dev; then
				db_subst iso-scan/progress_scan DRIVE $dev
				log "Mounted $dev for second pass"
				cd /hd-media
				for dir in *; do
					if [ -d "$dir" ]; then
						db_subst iso-scan/progress_scan DIRECTORY "$dir/"
						db_progress INFO iso-scan/progress_scan
						for iso in $(find $dir 2>/dev/null | grep -i '\.iso$'); do
							log "Found ISO $iso on $dev"
							ISO_COUNT=$(expr $ISO_COUNT + 1)
							try_iso $iso $dev
						done
						db_progress STEP 1
					fi
				done
				cd /
				umount /hd-media
			fi

		done

		db_progress STOP
	fi
fi

# Failure. Display the best message we can about what happened.
# Let them know the second pass failed too.
if [ "$ISO_COUNT" = 0 ]; then
	db_input critical iso-scan/no-isos || true
elif [ "$ISO_MOUNT_COUNT" != "$ISO_COUNT" ]; then
	db_input critical iso-scan/bad-isos || true
else
	db_input critical iso-scan/other-isos || true
fi
db_go || true
log "Failing with ISO_COUNT = $ISO_COUNT, MOUNTABLE_DEVS_COUNT = $MOUNTABLE_DEVS_COUNT, ISO_MOUNT_COUNT = $ISO_MOUNT_COUNT"
exit 1
