#!/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

if [ "$HAL_METHOD_INVOKED_BY_UID" == "" ]; then
    echo "org.freedesktop.Hal.Device.Volume.PermissionDenied" >&2
    echo "" >&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

# 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`

read GIVEN_MOUNTPOINT
GIVEN_MOUNTPOINT=${GIVEN_MOUNTPOINT//[^a-zA-Z0-9_+-]/@}
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, get mountpoint from label
if [ "$GIVEN_MOUNTPOINT" == "" ]; then
    case "$HAL_PROP_VOLUME_LABEL" in
	*[!A-Za-z0-9_\-\+:]*)
	    break
	    ;;
	*)
	    GIVEN_MOUNTPOINT="$HAL_PROP_VOLUME_LABEL"
    esac
fi

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

# we've replaced invalid characters in requested mountpoint 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
if [ "$GIVEN_MOUNTTYPE" != "" ]; then
    case "$GIVEN_MOUNTTYPE" in
	subfs)
	    MOUNTTYPE="subfs"
	    ;;
	*)
	    echo "org.freedesktop.Hal.Device.Volume.InvalidFilesystemType" >&2
	    echo "Invalid filesystem type." >&2
	    exit 1
   esac
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

# mount and return status
RESULT=$(mount -o "noexec,nosuid,nodev$MOUNTOPTIONS" -t "$MOUNTTYPE" "$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

exit 0
