#! /bin/sh

# Script to generate /etc/auto.media automount map for DIET-PC.

PATH=/bin:/sbin:/usr/sbin:/usr/local/sbin
export PATH
umask 022
TMPFILE="/etc/auto.media.$$"
trap "rm -f $TMPFILE; exit 1" 15

# Brutally murder all running storage_detect processes other than this one -
# they're already out of date.
kill -TERM `ps | awk '$NF ~ /storage_detect/ && $1 != "'$$'" {print $1}'` \
	2>/dev/null

# If it seems we're in a recursive loop, bail out.
[ "$DEPTH" = '3' ] && exit 0

cat >$TMPFILE <<EOF
# The "." entry doesn't do anything, it just makes automount think that it has
# something to manage, so that it doesn't exit if there are no other entries.
.											-null
EOF

NOBODY=`id -u nobody`
NOGROUP=`id -g nobody`
SKIP_KIDS=
for FN in /sys/block/*/dev /sys/block/*/*[0-9]/dev; do
	# Disallowing setuid files and device nodes is a reasonable security
	# precaution for any filesystem that is not mounted permanently.
	# Disabling access time updates on files and directories reduces
	# writes, boosts performance and hurts (almost) nothing.
	OPTS='nosuid,nodev,noatime,nodiratime'
	# In lockdown mode, add "noexec" for additional security.
	if grep -q '\<lockdown\>' /proc/cmdline; then
		OPTS="noexec,$OPTS"
	fi
	[ "$FN" = '/sys/block/*/dev' -o "$FN" = '/sys/block/*/*[0-9]/dev' ] \
			&& continue
	DIRNAME=`dirname $FN`
	SHORTNAME=`basename $DIRNAME`
	ID_FS_TYPE=
	ID_FS_USAGE=
	ID_FS_LABEL=
	if [ -f $DIRNAME/removable ]; then
		if [ "`cat $DIRNAME/removable`" -ne 0 ]; then
			# Select automatic filesystem detection to allow for
			# variations such as UDF instead of ISO9660.
			ID_FS_TYPE='auto'
			# The "sync" option hurts performance a lot, but it's
			# the only way to safeguard against impatient people
			# who pull out removable media the instant a copy has
			# (apparently) finished.  "noexec" is usually a
			# sensible security precaution for removable media.
			OPTS="sync,noexec,$OPTS"
		fi
	fi
	case "$SHORTNAME" in
	loop[0-9]*)
		# Zero-length loopback devices are not in use, skip them.
		[ "`cat $DIRNAME/size`" -eq 0 ] && continue
		;;
	ram[0-9]*)
		# Skip all ramdisks.
		continue
		;;
	*[a-z])
		# If the non-partitioned device holds something recognizable,
		# then it has no partition table, so skip all erroneously
		# detected partitions.
		eval `vol_id --export /dev/$SHORTNAME 2>/dev/null | egrep \
				'^ID_FS_(USAGE|TYPE|LABEL|UUID)='`
		[ -n "$ID_FS_TYPE" -a "$ID_FS_TYPE" != 'auto' ] && \
			SKIP_KIDS="$SHORTNAME $SKIP_KIDS"
		;;
	*[0-9])
		UPNAME=`echo $SHORTNAME | tr -d '[0-9]'`
		[ -n "`echo \"$SKIP_KIDS\" | grep \"\<$UPNAME\>\"`" ] && \
				continue
		;;
	esac
	# Don't let remote users access the root filesystem.
	if [ -L /dev/root -a "`realpath /dev/root`" = "/dev/$SHORTNAME" ]; then
		continue
	fi
	# Unless we have already done so (unpartitioned device) or have chosen
	# not to (removable device), use vol_id to check for a filesystem on
	# the device.
	if [ -z "$ID_FS_TYPE" -o "$ID_FS_TYPE" = 'auto' ]; then
		eval `vol_id --export /dev/$SHORTNAME 2>/dev/null | egrep \
				'^ID_FS_(USAGE|TYPE|LABEL|UUID)='`
	fi
	# If the device appears to contain an LVM2 physical volume that LVM
	# doesn't already know about, then scan it for volumes and activate
	# all that are found.
	if [ "$ID_FS_TYPE" = 'LVM2_member' ]; then
		if [ "`which lvm`" -a -z "`pvs | grep -w \"/dev/$SHORTNAME\"`" \
				]; then
			pvscan >/dev/null
			vgscan >/dev/null
			vgchange -ay >/dev/null
			# Recurse, with a safety counter.
			DEPTH=`expr ${DEPTH:-0} + 1`
			export DEPTH
			rm -f $TMPFILE
			exec $0 $*
		fi
	# Similarly, if the device is a member of an unassembled RAID device,
	# try - quietly and unaggressively - to assemble it.
	elif [ "$ID_FS_TYPE" = 'linux_raid_member' ]; then
		if [ "`which mdadm`" -a -z "`grep -w \"$SHORTNAME\" \
				/proc/mdstat`" ]; then
			mdadm --assemble --scan --uuid=$ID_FS_UUID --auto=yes \
					|| continue
			# Recurse, with a safety counter.
			DEPTH=`expr ${DEPTH:-0} + 1`
			export DEPTH
			rm -f $TMPFILE
			exec $0 $*
		fi
	fi
	[ "$ID_FS_USAGE" != 'filesystem' -o -z "$ID_FS_TYPE" ] && continue
	# If the device is already mounted somewhere, use a bind mount to
	# re-use that mount, rather than attempt a new mount (which would
	# probably fail).
	MOUNT_PT=`awk '$1 == "'"/dev/$SHORTNAME"'" {print $2; exit 0}' \
			/proc/mounts`
	case "$MOUNT_PT" in
	""|/var/chroot/media/*)
		# Don't bind mount an automount mount point!
		;;
	/|/usr|/usr/local)
		# For security reasons, it's not a good idea to let remote users
		# access DIET-PC's own filesystem(s).
		continue
		;;
	*)
		# Everything else is fair game.
		printf '%-8s %-78s %s\n' "${ID_FS_LABEL:-$SHORTNAME}" "--bind" \
				":$MOUNT_PT" >>$TMPFILE
		continue
		;;
	esac
	case "$ID_FS_TYPE" in
	ext3)
		# Fall back to ext2 if ext3 is not available.
		modprobe -q ext3
		grep -q '\<ext3\>' /proc/filesystems || ID_FS_TYPE='ext2'
		# If ext3 is available, omit the "sync" option (if present).
		# Ext3 journaling offsets the risk of buffered writes to some
		# extent, and in most cases you really want the extra
		# performance.  Also use "data=writeback" to reduce overheads
		# associated with the journal.
		if [ "$ID_FS_TYPE" = 'ext3' ]; then
			OPTS="data=writeback,`echo \"$OPTS\" | sed -e \
					's/,sync\>//' -e 's/\<sync,//'`"
		fi
		;;
	ext4)
		# Same as ext3, above, and turn off barriers as well.
		OPTS="barrier=0,data=writeback,`echo \"$OPTS\" | sed -e \
				's/,sync\>//' -e 's/\<sync,//'`"
		;;
	jfs)
		# JFS is journaled, so omit the "sync" option.
		OPTS="`echo \"$OPTS\" | sed -e 's/,sync\>//' -e 's/\<sync,//'`"
		;;
	msdos|vfat|ntfs)
		# Use "vfat" even if it isn't strictly needed - "msdos" might
		# not be supported. 
		[ "$ID_FS_TYPE" = 'msdos' ] && ID_FS_TYPE='vfat'
		OPTS="uid=$NOBODY,gid=$NOGROUP,umask=022,$OPTS"
		;;
	iso9660)
		OPTS="ro,uid=$NOBODY,gid=$NOGROUP,$OPTS"
		;;
	udf|auto)
		# "tolerate sloppy options" or no, mount may not support
		# "umask=022" here.
		OPTS="uid=$NOBODY,gid=$NOGROUP,$OPTS"
		;;
	esac
	printf '%-8s %-78s %s\n' "${ID_FS_LABEL:-$SHORTNAME}" \
			"-fstype=$ID_FS_TYPE,$OPTS" ":/dev/$SHORTNAME" \
			>>$TMPFILE
done

# Autofs4 has a bad habit of deleting the mount point when it exits!
mkdir -m 0755 -p /var/chroot/media

mv $TMPFILE /etc/auto.media

# Start automount if it isn't running, or send it a HUP signal if it is.
#
# -g enables ghosting, so that you can browse /media.
# -t1 requests unmounting after one second idle time.  This is needed so that a
#     medium can be quickly and safely ejected when the user has "finished with
#     it", in an intuitive fashion.  This may degrade performance somewhat for
#     casual browsing from Windows (via SMB or RDP/ICA client drive mapping),
#     but doesn't affect FTP sessions much at all, because the session will
#     chdir into the mount point such that it can't be unmounted.
#
# We're using /var/chroot/media as the real automount mount point and
# symlinking /media to it because the reverse situation isn't possible when
# using a chroot jail.  Tricks to get around this using "mount --rshared"
# and "mount --rbind" don't seem to work.
#
kill -HUP `cat /var/run/auto_media.pid 2>/dev/null` 2>/dev/null || \
	automount -g -t1 -p /var/run/auto_media.pid /var/chroot/media file \
	/etc/auto.media

# If microdc is installed and running, terminate it, to force it to restart and
# reindex.
if [ -f /etc/rc.d/microdc ]; then
	sleep 2
	kill -TERM `ps | awk '$NF ~ /microdc/ {print $1}'` 2>/dev/null
fi
# Similarly, if installed, trigger samba_autoshare to update smb.conf.
[ "`which samba_autoshare`" ] && samba_autoshare
exit 0
