#!/bin/dash
########  Click image files to mount & unmount  ########
# Originally by: Terry Becker	aka: SunBurnt
# Rewritten by jamesbond 2012, 2014, 2016, 2018, 2019 for Fatdog64 (License: GPLv3)
# Supported filetypes: iso, sfs, 2fs/ext2, 3fs/ext3, 4fs/ext4, img, initrd/initrd.gz
# parameter: $1 - filename

### configuration
MKINITRD_NAME=repack-initrd

### helper - create a script to re-pack initrd
# create a simple script to rebuild initrd
# $1-location of original initrd, $2-compression type
create_mkinitrd() {
	local COMPRESSOR 
	touch $MKINITRD_NAME; chmod +x $MKINITRD_NAME
	case $2 in
		gzip) COMPRESSOR="gzip -9" ;;
		bzip2) COMPRESSOR="bzip2" ;;
		xz) COMPRESSOR="xz --check=crc32 --lzma2=dict=512KiB" ;;
		none) COMPRESSOR=cat;;
	esac
	cat >> $MKINITRD_NAME << EOF
#!/bin/dash
[ \$(id -u) -ne 0 ] && exec gtksu "Rebuild initrd" \$(readlink -f "\$0")
SOURCE="\$(dirname "\$0")"; cd "\$SOURCE"
exec Xdialog --no-buttons --title "$MKINITRD_NAME" --infobox "Working, please wait ..." 0 0 1000000 &
XPID=\$!
find . | grep -v $MKINITRD_NAME | cpio -o -H newc | $COMPRESSOR > "$1"
kill \$XPID
su \$USER -c "rox -D \"\$SOURCE\""; rm -rf "\$SOURCE"
exec Xdialog --title "$MKINITRD_NAME" --infobox "Repacking done, $1 is now updated." 0 0 10000
EOF
}

# $1-mountpoint
remove_mountpoint() {
	# workaround a nasty aufs bug
	# only remove mountpoint if there is exactly one aufs root
	# otherwise aufs will *hard-lockup*
	if [ $(ls -d /sys/fs/aufs/* | wc -l) -eq 1 ]; then
		rmdir "$1"
	fi
	return 0 # always return success
}

# $1-path to sfs
find_loop_device() {
	local p pp
	for p in /sys/block/loop*; do
		if [ -e $p/loop ]; then
			read pp < $p/loop/backing_file
			if [ "$pp" = "$1" ]; then
				echo /dev/${p##*/}
			fi
		fi
	done
}

############### main ##################
! [ -e "$1" ] && exit 1

### need root
[ $(id -u) -ne 0 ] && exec gtksu "File Mounter" "$0" $(readlink -f "$1")

### get image file and generate mountpoint
fullpath=$(readlink -f "$1")
filename=${1##*/}
extension=${filename##*.}
[ "$extension" = "$filename" ] && extension=
case  "$filename" in
	initrd|initrd.?z|initrd.?z?|initrd-*) extension=$filename ;;
esac
extension=$(echo $extension | tr "A-Z" "a-z")
mountpoint=$(echo $fullpath | tr "'\\\\/ .;:?*[]{}()<>&|\"\`\t" +)
#echo $filename $extension $mountpoint

# mount only if it is not already mounted
if ! grep -q $mountpoint /proc/mounts; then
	case $extension in
		iso|sfs|2fs|3fs|4fs|ext2|ext3|ext4|img)
			# ensure we understand the filesystem. Otherwise bail out.
			case $(guess_fstype "$1") in
				unknown|"")
					Xdialog --title "Error!" --infobox "Cannot mount $filename.\nIt contains unknown filesystem." 0 0 10000
					;;
				*)
					# prepare to mount
					mountpoint="/mnt/$mountpoint"
					mkdir -p "$mountpoint" 2> /dev/null

					# check if it is already mounted elsewhere
					elsewhere=$(find_loop_device "$fullpath")
					if [ "$elsewhere" ]; then
						# yes, do bind mount
						elsewhere="$(awk -v loopdev="$elsewhere" '$1 == loopdev {print $2}' /proc/mounts)"
						mount -o bind "$elsewhere" "$mountpoint"
					else
						# no, do loop mount
						mount -o loop "$1" "$mountpoint"
					fi &&

					su $USER -c "rox $mountpoint" ||
					Xdialog --title "Error!" --infobox "Failed to mount $filename." 0 0 10000 
					;;
			esac
			;;
		initrd|initrd.?z|initrd.?z?|initrd-*)
			tmpdir=$(mktemp -dp /tmp initrd-XXXXXX)
			chgrp $USER $tmpdir
			chmod a+rwx $tmpdir
			cd $tmpdir
			if case $(file -b --mime-type "$fullpath") in
				*gzip) TYPE="gzip" && zcat "$fullpath" | cpio -i ;;
				*xz) TYPE="xz" && xzcat "$fullpath" | cpio -i ;;
				*bzip2) TYPE="bzip2" && bzcat "$fullpath" | cpio -i ;;
				*) TYPE="none" && cat "$fullpath" | cpio -i ;;
			esac; then
				if [ -w "$fullpath" ]; then
					create_mkinitrd "$fullpath" $TYPE &&
					disposition="
When done, you can rebuild $filename by running $MKINITRD_NAME.\n
If you decide otherwise, simply remove $tmpdir."
				else
					disposition="
When done, simply remove $tmpdir.\n\n
NOTE: you can't rebuild $filename because it isn't writable."
				fi
				su $USER -c "rox $tmpdir"
				Xdialog --left --title "Success" --infobox "
$filename is an initrd archive, and it has been extracted to $tmpdir.\n
Do what you want to do with it.\n
$disposition" 0 0 10000 
			else
				Xdialog --title "Error!" --infobox "Failed to extract $filename." 0 0 10000 
			fi
			;;
		*)
			Xdialog --title "Error!" --infobox "Unsupported file type: $extension" 0 0 10000 
			;;
	esac
else
	#if ! grep $mountpoint /proc/mounts && busybox losetup -a | grep $fullpath; then
	#	load_sfs.sh	# in losetup but not in /proc/mounts, probably mounted by SFS loader
	#	exit
	#fi
	
	# already mounted, will try to unmount
	case $extension in
		iso|sfs|2fs|3fs|4fs|ext2|ext3|ext4|img)
			su $USER -c "rox -D /mnt/$mountpoint"
			if umount -d /mnt/$mountpoint && remove_mountpoint /mnt/$mountpoint; then
				Xdialog --title "Success!" --infobox "$filename has been un-mounted." 0 0 10000 
			else
				if Xdialog --title "Error!" --yesno "Failed to un-mount $filename, it is currently used by the following process:
$(fuser -m /mnt/$mountpoint | xargs ps -o cmd -p | sed 's/CMD//')\n\n
Do you want me to stop them and try again?" 0 0; then
					fuser -m -k /mnt/$mountpoint
					$0 $1
				fi
			fi
			;;
		*)
			Xdialog --title "Error!" --infobox "Unsupported file type: $extension" 0 0 10000
			;;
	esac
fi
