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

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

log () {
    logger -t hd-image-detect "$@"
}

# Finds all block devices that might have a filesystem on them.
block_devices () {
	find /dev/discs/ -follow -type b
	sed -e '1,2d' -e 's/ * / /g' /proc/partitions | cut -d' ' -f 5 \
		| sed -e 's,^,/dev/,'
}

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 () {
	# Set the suite used by base-installer and base-config to
	# the suite 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.
	for distlink in stable testing unstable ; do
		relfile=/cdrom/dists/$distlink/Release
		if [ -e $relfile ] ; then
			suite=$(sed -n 's/^Suite: *//p' $relfile)
			log "Detected ISO with '$suite' distribution"
			db_set mirror/suite $suite
			db_subst iso-scan/success SUITE $suite
			
			description=`sed -n 's/^Description: *//p' $relfile`
			db_subst iso-scan/success DESCRIPTION $description
			
			break
		fi
	done
}

# 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
		log "Mounted $1"
		ISO_MOUNT_COUNT=$(expr $ISO_MOUNT_COUNT + 1)
		if is_debian_iso; 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.
			register_cd $iso_to_try $iso_device
			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
			exit 0
		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

# Find all block devices, and get a count of them, for use in progress bar.
DEVS=$(block_devices)
DEV_COUNT=0
for dev in $DEVS; do
	DEV_COUNT=$(expr $DEV_COUNT + 1)
done

log "Searching for Debian installation media..."
db_progress START 0 $DEV_COUNT iso-scan/progress_title

# Load up every filesystem known to man. The drive could have anything.
FS="ext2 ext3 reiserfs fat vfat xfs iso9660 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."
for dev in $DEVS; do
	if mount_device $dev; then
		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
	fi

	# 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

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"
