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