Chris Dennis wrote:
> John Cooper wrote:
>> Chris Dennis wrote:
>>> Hello folks
>>>
>>> I'm planning to use one or more external USB hard drives to backup a 
>>> headless server running Debian.  I'll probably use rsnapshot, with a 
>>> script that detects for the presence of the right drive.
>>>
>>> But how can the server tell the user when it is safe to unplug the 
>>> drive?  Or maybe the user should somehow tell the server "I want to 
>>> unplug the drive -- stop using it and unmount it".
>>>
>>> The user's only way of communicating with the server is by email or 
>>> possibly via Webmin.
>>>
>>> Has anyone come up with a cunning plan to deal with this?
>>>
>>> cheers
>>>
>>> Chris
> 
> Thanks for the various replies.
> 
> The simple "unmount after backup" idea won't work for me because I'm 
> planning to run rsnapshot via cron every hour while the drive is plugged 
> in, but allow the drive to be taken off-site at weekends or whenever.
> 
> In fact I think Webmin (for all its faults) will allow the user to 
> unmount the drive and/or see whether it is currently mounted.  They can 
> then remove the drive knowing that it will not be used again until the 
> appointed cron time -- 15 minutes past the hour for example.
> 
>  > Have a look at this USB suspend script:-
>  > 
> http://elliotli.blogspot.com/2009/01/safely-remove-usb-hard-drive-in-linux.html
> 
> That all looks very elaborate.  Is it really necessary?  Does this mean 
> that good old 'umount' hasn't been working for USB drives all this time?
> 
> cheers
> 
> Chris
> 

Updated the script to check if hdparm works with the device and fixed
some other errors.

Example run on a USB stick with 2 partitions,/dev/sdc1 and /dev/sdc2
(see mount output after inserting USB device) :-

sudo ./usbsuspend /dev/sdc     ( or su -c './usbsuspend /dev/sdc' )

Unmount device partitions (1 to 9)
Found device /devices/pci0000:00/0000:00:02.1/usb1/1-4 associated to
/dev/sdc; USB bus id is 1-4
flush all buffers: sync
Syncing device /dev/sdc
 drive state is:  unknown
Drive does not support sleep mode, skipping hdparm
Unbinding device 1-4
Checking whether /devices/pci0000:00/0000:00:02.1/usb1/1-4 can be suspended
Suspending /devices/pci0000:00/0000:00:02.1/usb1/1-4 by writing to
/sys/devices/pci0000:00/0000:00:02.1/usb1/1-4/power/level
Completed



Script, cut and paste into file called usbsuspend :-

---- CUT START -----
#!/bin/bash
#
# usbsuspend
#

usage()
{
    cat<<EOF
usbsuspend

This script is designed to properly put an USB device into suspend
mode that can then be unplugged safely. It sends a SYNCHRONIZE CACHE
command followed by a START-STOP command (if the device supports it),
unbinds the device from the driver and then suspends the USB
port. After that you can disconnect your USB device safely.

usage:
$0 [options] dev

Example:
$0 /dev/sdc

options:
  -l     show the device and USB bus ID only
  -h     print this usage

EOF
}

set -e -u

SHOW_DEVICE_ONLY=0
while getopts "vlh" opt; do
    case "$opt" in
        h)
            usage
            exit 2
            ;;
        l)
            SHOW_DEVICE_ONLY=1
            ;;
        ?)
            echo
            usage
            exit 2
            ;;
    esac
done
DEV_NAME=${!OPTIND:-}

if [ -z ${DEV_NAME} ]; then
    usage
    exit 2
fi

echo "Unmount device partitions (1 to 9)"
umount ${DEV_NAME}[1-9]

if mount | grep "^${DEV_NAME}[[:digit:]]* "; then
    1>&2 echo
    1>&2 echo "the above disk or partition is still mounted, can't
suspend device"
    1>&2 echo "unmount it first using umount (may need to be root)"
    exit 1
fi

DEVICE=$(udevadm info --query=path --name=${DEV_NAME} --attribute-walk \
| egrep "looking at parent device" | head -1 | sed -e "s/.*looking at \
parent device '\(\/devices\/.*\)\/.*\/host.*/\1/g")

if [ -z $DEVICE ]; then
    1>&2 echo "cannot find appropriate parent USB/Firewire device, "
    1>&2 echo "perhaps ${DEV_NAME} is not an USB/Firewire device?"
    exit 1
fi

DEV_BUS_ID=${DEVICE##*/}

echo "Found device $DEVICE associated to $DEV_NAME; USB bus id is
$DEV_BUS_ID"

if [ ${SHOW_DEVICE_ONLY} -eq 1 ]; then
    echo Device: ${DEVICE}
    echo Bus ID: ${DEV_BUS_ID}
    exit 0
fi

echo "flush all buffers: sync"
sync
sync

# root check
if [ `id -u` -ne 0 ]
then
        echo "NOT root, required for hdparm to put drive into sleep and
unbind"
        exit
fi

echo "Syncing device $DEV_NAME"

hdparm -C "$DEV_NAME" 2> /dev/null | grep "drive state is:  unknown"
if [ $? -eq 0 ]
then
        echo "Drive does not support sleep mode, skipping hdparm"
 else
        hdparm -f "$DEV_NAME" >/dev/null || true
        hdparm -Y "$DEV_NAME" >/dev/null
fi

echo "Unbinding device $DEV_BUS_ID"
if [[ "${DEV_BUS_ID}" == fw* ]]
then
    echo -n "${DEV_BUS_ID}" > /sys/bus/firewire/drivers/sbp2/unbind
else
    echo -n "${DEV_BUS_ID}" > /sys/bus/usb/drivers/usb/unbind

    echo "Checking whether $DEVICE can be suspended"
    POWER_LEVEL_FILE=/sys${DEVICE}/power/level
    if [ ! -f "$POWER_LEVEL_FILE" ]; then
        1>&2 cat<<EOF
It's safe to remove the USB device now but better can be done. The
power level control file $POWER_LEVEL_FILE
doesn't exist on the system so I have no way to put the USB device
into suspend mode, perhaps you don't have CONFIG_USB_SUSPEND enabled
in your running kernel.

EOF
        exit 3
    fi

    echo "Suspending $DEVICE by writing to $POWER_LEVEL_FILE"
    echo 'suspend' > "$POWER_LEVEL_FILE"
fi
echo "Completed"
---- CUT END -----


-- 
--------------------------------------------------------------
Discover Linux - Open Source Solutions to Business and Schools
http://discoverlinux.co.uk
--------------------------------------------------------------

-- 
Please post to: Hampshire@mailman.lug.org.uk
Web Interface: https://mailman.lug.org.uk/mailman/listinfo/hampshire
LUG URL: http://www.hantslug.org.uk
--------------------------------------------------------------

Reply via email to