#!/bin/bash

# Copyright (C) 2005, Kay Sievers <kay.sievers@vrfy.org>
# Copyright (C) 2006, David Zeuthen <david@fubar.dk>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2.

MOUNT_ROOT="/media"

# Check for environment variables
if [ "$HAL_PROP_BLOCK_DEVICE" == "" ] || [ "$HAL_PROP_INFO_UDI" == "" ]; then
    echo "Missing or empty environment variable(s)." >&2
    echo "This script should be started by hald." >&2
    exit 1
fi

# check if device is already mounted
if [ "$HAL_PROP_VOLUME_IS_MOUNTED" = "true" ]; then
    echo "org.freedesktop.Hal.Device.Volume.AlreadyMounted" >&2
    echo "Device is already mounted." >&2
    exit 1
fi

# check if device should be ignored
if [ "$HAL_PROP_VOLUME_IGNORE" = "true" ]; then
    echo "org.freedesktop.Hal.Device.Volume.PermissionDenied" >&2
    echo "Device has volume.ignore set to TRUE. Refusing to mount." >&2
    exit 1
fi


check_fstab()
{
	awk -v dev="$1" \
	'
	BEGIN {
		sub(/^\/dev\//,"", dev)
		cmd = "/usr/bin/udevinfo -q symlink -n " dev
		if (( cmd | getline) < 0 ) {
			print "org.freedesktop.Hal.Device.Volume.PermissionDenied" >/dev/stderr
			exit 1
		}

		for(i=1; i <= NF; i++) {
			a["/dev/" $i] = 1
		}
		a["/dev/" dev] = 1
	}
	{
		if ($1 in a) { 
			print "org.freedesktop.Hal.Device.Volume.PermissionDenied" >"/dev/stderr"
			print $1 " found in /etc/fstab" >"/dev/stderr"
			exit 1
		}
	}
	' /etc/fstab
}

check_fstab "$HAL_PROP_BLOCK_DEVICE" || exit 1

# read parameters
# "MyDisk\n"
# "fuse\n"
# "ro\tsync\n"
#
# only allow ^a-zA-Z0-9_= in the string because otherwise someone may
# pass e.g. umask=0600,suid,dev or umask=`/bin/evil`

# Used to get :alnum: to be somewhat useful
LANG=en_US.UTF-8

read GIVEN_MOUNTPOINT
GIVEN_MOUNTPOINT=${GIVEN_MOUNTPOINT//[^[:alnum:]_=[:space:]:.,+-]/@}
read GIVEN_MOUNTTYPE
GIVEN_MOUNTTYPE=${GIVEN_MOUNTTYPE//[^a-zA-Z0-9_=]/_}
read GIVEN_MOUNTOPTIONS
GIVEN_MOUNTOPTIONS=${GIVEN_MOUNTOPTIONS//[^a-zA-Z0-9_=-[:space:]]/_}

# if no mountpoint is requested, get the mountpoint from the filesystem
# label if it does not contain invalid chars or starts with a "."
if [ "$GIVEN_MOUNTPOINT" == "" ]; then
    case "$HAL_PROP_VOLUME_LABEL" in
	*[!A-Za-z0-9_:.+-]*)
	    ;;
	.*)
	    ;;
	*)
	    GIVEN_MOUNTPOINT="$HAL_PROP_VOLUME_LABEL"
    esac
fi

# if no mountpoint is given, use default name
if [ "$GIVEN_MOUNTPOINT" == "" ]; then
    if [ "$HAL_PROP_STORAGE_MEDIA_CHECK_ENABLED" == "false" ]; then
	GIVEN_MOUNTPOINT="$HAL_PROP_STORAGE_DRIVE_TYPE"
    else
	GIVEN_MOUNTPOINT="disk"
    fi
fi

# last check, we've replaced invalid characters in requested mountpoint
# with '@' and don't allow a specified mountpoint starting with "."
case "$GIVEN_MOUNTPOINT" in
    .*|*@*)
	echo "org.freedesktop.Hal.Device.Volume.InvalidMountpoint" >&2
	echo "The mountpoint is invalid." >&2
	exit 1
	;;
esac
MOUNTPOINT="$GIVEN_MOUNTPOINT"

# pass only whitelisted types; allow anything if it's on a non-pollable drive
if [ "$GIVEN_MOUNTTYPE" != "" ]; then
    if [ "$HAL_PROP_STORAGE_MEDIA_CHECK_ENABLED" == "false" ]; then
	MOUNTTYPE=$GIVEN_MOUNTTYPE
    else
	case "$GIVEN_MOUNTTYPE" in
	    *)
		echo "org.freedesktop.Hal.Device.Volume.InvalidFilesystemType" >&2
		echo "Invalid filesystem type." >&2
		exit 1
	esac
    fi
fi

# if no type is given, use default name
if [ "$MOUNTTYPE" == "" ]; then
    MOUNTTYPE=$HAL_PROP_VOLUME_FSTYPE
fi

# retrieve white-list from device properties (see fdi/policy/osvendor/20-storage-methods.fdi)
LEGAL_MOUNT_OPTIONS="$HAL_PROP_VOLUME_MOUNT_VALID_OPTIONS "
# pass only whitelisted mount options, bail out on anything not in the whitelist
if [ "$GIVEN_MOUNTOPTIONS" != "" ]; then
    for OPTION in $GIVEN_MOUNTOPTIONS; do
	OPTION_WAS_OK="0"
	for LEGAL_OPTION in $LEGAL_MOUNT_OPTIONS; do
	    if [ "$OPTION" == "$LEGAL_OPTION" ]; then
		MOUNTOPTIONS="$MOUNTOPTIONS,$OPTION"
		OPTION_WAS_OK="1"
	    elif [ "${LEGAL_OPTION:${#LEGAL_OPTION}-1}" == "=" ]; then
		# support for LEGAL_OPTION="umask=", e.g. support any $OPTION that starts with "umask="
		if [ "${OPTION:0:${#LEGAL_OPTION}}" == "$LEGAL_OPTION" ]; then			

		    # special handling for uid; only allow uid=$HAL_METHOD_INVOKED_BY_UID expect if
		    # $HAL_METHOD_INVOKED_BY_UID is 0
		    if [ "$LEGAL_OPTION" == "uid=" ]; then
			if [ "$HAL_METHOD_INVOKED_BY_UID" != "0" ]; then
			    if [ "uid=$HAL_METHOD_INVOKED_BY_UID" != "$OPTION" ]; then
				echo "org.freedesktop.Hal.Device.Volume.InvalidMountOption" >&2
				echo "The option '$OPTION' is not allowed for uid=$HAL_METHOD_INVOKED_BY_UID" >&2
				exit 1
			    fi
			fi
		    fi
		    MOUNTOPTIONS="$MOUNTOPTIONS,$OPTION"
		    OPTION_WAS_OK="1"
		fi
	    fi
	done
	if [ "$OPTION_WAS_OK" != "1" ]; then
	    echo "org.freedesktop.Hal.Device.Volume.InvalidMountOption" >&2
	    echo "The option '$OPTION' is not allowed" >&2
	    exit 1
	fi
    done
fi

# echo "options = '$MOUNTOPTIONS'"

# append number to mountpoint if it already exists
if [ -e "$MOUNT_ROOT/$MOUNTPOINT" ]; then
    NUM=1;
    while [ -e "$MOUNT_ROOT/$MOUNTPOINT-$NUM" ]; do
	NUM=$(($NUM + 1))
    done
    MOUNTPOINT="$MOUNTPOINT-$NUM"
fi

# create directory and mark it for cleanup with an extended attribute
if [ ! -e "$MOUNT_ROOT/$MOUNTPOINT" ]; then
    MOUNTPOINT_CREATED=1
    mkdir "$MOUNT_ROOT/$MOUNTPOINT"
    touch "$MOUNT_ROOT/$MOUNTPOINT/.created-by-hal"
fi

if [ ! -e "$MOUNT_ROOT/$MOUNTPOINT" ]; then
    echo "org.freedesktop.Hal.Device.Volume.FailedToCreateMountpoint" >&2
    echo "Failed to create moutpoint $MOUNT_ROOT/$MOUNTPOINT." >&2
    exit 1
fi

if [ "$MOUNTTYPE" != "" ]; then
    MOUNTTYPE_EXPANDED="-t $MOUNTTYPE"
else
    MOUNTTYPE_EXPANDED=""
fi

# mount and return status
RESULT=$(mount -o "noexec,nosuid,nodev$MOUNTOPTIONS" $MOUNTTYPE_EXPANDED "$HAL_PROP_BLOCK_DEVICE" "$MOUNT_ROOT/$MOUNTPOINT" 2>&1)
if [ $? -ne 0 ]; then
    case "$RESULT" in
	*"unknown filesystem"*)
	    echo "org.freedesktop.Hal.Device.Volume.UnknownFilesystemType" >&2
	    echo "Invalid filesystem type." >&2
	    ;;
	*)
	    echo "org.freedesktop.Hal.Device.Volume.UnknownFailure" >&2
	    echo "Failed to mount device." >&2
    esac
    if [ -n "$MOUNTPOINT_CREATED" ]; then
	rm -f "$MOUNT_ROOT/$MOUNTPOINT/.created-by-hal"
	rmdir "$MOUNT_ROOT/$MOUNTPOINT"
    fi
    exit 1
fi

hal-set-property --udi $UDI --key info.hal_mount.created_mount_point --string "$MOUNT_ROOT/$MOUNTPOINT" > /dev/null 2>&1
hal-set-property --udi $UDI --key info.hal_mount.mounted_by_uid --int "$HAL_METHOD_INVOKED_BY_UID" > /dev/null 2>&1

exit 0
