#!/bin/sh

# With the 'powerdown' arg suspends the flash drive
# iff there seems to be nothing mounted from it (under /auto).
# This inspects the /sys/bus/usb/devices list for the right device.
# This can for example run from a poll and/or
# be event driven such as from an inotifywatch on the automount mount point.
#
# With the 'powerup' arg this ensures that the device is powered up.
# This can be hooked into the automounter (eg via a program map).
#
# This is clearly race-prone and risks trashing any mounted filesystems.
#
# There is a 'watch' option which waits for a delete operation
# at the mountpoint and tries an immediate powerdown.
# Only one will be allowed to run at once.

# If the target USB device cannot be found as expected,
# or seems already to be mounted,
# or there is any other unexpectedness,
# then this returns with an error.

action="$1"

DEV=`/etc/findUSBdir.sh "Kingston" "DataTraveler 200"`
if [ "x$DEV" = "x" -o ! -d "$DEV" ]; then
    echo Cannot find Kingston DataTraveler 200 device.
    exit 1
fi

# Lockfile to try to eliminate powerup-mount vs powerdown races.
# Only held while attempting to suspend
# and while attempting to bring it up for a few seconds to allow mounting.
LOCKFILE=/var/run/USBFlash-powerchange.lock

# Lockfile to allow only one 'watch' to run at once.
WATCHLOCKFILE=/var/run/USBFlash-powerchange.watch.lock


case $action in

    powerup)
        # Let kernel do what it can to manage power.
        # Attempt for <30s to lock the file to avoid automount locking up)
        # and break stale locks in about half an hour.
        lockfile -7 -r4 -l1700 $LOCKFILE || exit 1
logger -p daemon.err Spinning up galleryDB...
        echo auto > $DEV/power/level
        # Retain the lock long enough after we return
        # to allow any subsequent (fsck and) mount to have completed
        # locking out any attempt to suspend the USB device during this time.
        # Keep this time shorter than the timeout above
        # so that multiple mounts under the same mountpoint
        # could in theory be possible.
        # After removing our main lock, watch for an unmount and powerdown.
        sh -c "sleep 90; rm -f $LOCKFILE; $0 watch" </dev/null >/dev/null 2>&1 &
        ;;

    powerdown)
        # Force suspension; DANGEROUS.
        # Seem to have to force a transition...
        # Abort immediately without retrying if we can't get the lock
        # as it's clearly not quiescent and not safe to attempt powerdown.
        lockfile -r0 $LOCKFILE || exit 1

# Abort of there seems to be an active mount from the flash drive.
# Fragment of /proc/mounts with partition not mounted:
# /etc/auto.auto.sh /auto autofs rw,relatime,fd=5,pgrp=5809,timeout=300,minproto=5,maxproto=5,indirect 0 0
#
# Fragment with partition mounted...
# /etc/auto.auto.sh /auto autofs rw,relatime,fd=5,pgrp=5809,timeout=300,minproto=5,maxproto=5,indirect 0 0
# /dev/sda2 /auto/galleryDB ext3 rw,noatime,errors=continue,commit=600,data=ordered 0 0
#
# So a first field starting with "/dev/" and
# a second field starting with "/auto/"
# can be taken to indicate an active mount.
#
# Do this in the scope of the lock.
#
# WE MUST CLEAR THE LOCK ON ABORT.
if egrep -q "^/dev/[^ ]+ /auto/" /proc/mounts; then
    rm -f $LOCKFILE
    echo "Live mount under /auto; aborting."
    exit 1
fi

if [ "Xsuspend" != "X`cat $DEV/power/level`" ]; then logger -p daemon.err Spinning down galleryDB...; fi
        echo on > $DEV/power/level
        echo suspend > $DEV/power/level
        rm -f $LOCKFILE
        ;;

    watch)
         # Don't run a watcher if one is already running.
        lockfile -r0 -l1700 $WATCHLOCKFILE || exit 1
        # Wait for a delete at the mountpoint and try an immediate powerdown.
        # This is best-efforts: powerdown should be periodically tried anyway.
        inotifywait -t 1800 -q -e delete /auto && $0 powerdown
        rm -f $WATCHLOCKFILE
        exit 0
        ;;

    *)
        echo "Command $action not recognised: aborting."
        exit 1
        ;;
esac

exit 0
