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


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`

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

if [ -z "$GIVEN_MOUNTPOINT" ]; then
    if [ -n "$HAL_PROP_VOLUME_LABEL" ]; then
	GIVEN_MOUNTPOINT="$HAL_PROP_VOLUME_LABEL"
    elif [ -n "$HAL_PROP_STORAGE_DRIVE_TYPE" ]; then
	GIVEN_MOUNTPOINT="$HAL_PROP_STORAGE_DRIVE_TYPE"
    else
        GIVEN_MOUNTPOINT="disk"
    fi
fi

# sanitize
GIVEN_MOUNTPOINT=${GIVEN_MOUNTPOINT//[^a-zA-Z0-9_+-]/_}
GIVEN_MOUNTPOINT=${GIVEN_MOUNTPOINT/./_}

MOUNTPOINT="$GIVEN_MOUNTPOINT"

# pass only whitelisted types
if [ "$GIVEN_MOUNTTYPE" != "" ]; then
    case "$GIVEN_MOUNTTYPE" in
	subfs)
	    MOUNTTYPE="subfs"
	    ;;
	ntfsmount)
	    if [ "$HAL_PROP_VOLUME_FSTYPE" == "ntfs" ]; then
                MOUNTTYPE="ntfsmount"
            else
                echo "org.freedesktop.Hal.Device.Volume.InvalidMountType" >&2
                echo "Could not use ntfsmount with $HAL_PROP_VOLUME_FSTYPE" >&2
                exit 1;
	    fi
            ;;
	captive)
	    if [ "$HAL_PROP_VOLUME_FSTYPE" == "ntfs" ]; then
                MOUNTTYPE="captive"
            else
                echo "org.freedesktop.Hal.Device.Volume.InvalidMountType" >&2
                echo "Could not use ntfsmount with $HAL_PROP_VOLUME_FSTYPE" >&2
                exit 1;
	    fi
            ;;
	msdos)
            if ["$HAL_PROP_VOLUME_FSTYPE" == "vfat" ]; then
                MOUNTTYPE="msdos"
            else
                echo "org.freedesktop.Hal.Device.Volume.InvalidMountType" >&2
                echo "Replace other filesystems then vfat with msdos is not allowed." >&2
                exit 1
            fi
            ;;
	*)
	    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'"

# cleanup no longer used mount points
if [ -e /usr/lib/hal/scripts/hal-system-storage-cleanup-mountpoints ]; then
        /usr/lib/hal/scripts/hal-system-storage-cleanup-mountpoints
elif [ -e /usr/lib64/hal/scripts/hal-system-storage-cleanup-mountpoints ]; then
        /usr/lib64/hal/scripts/hal-system-storage-cleanup-mountpoints
fi

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

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
