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