UPDATE root issue discussed below was fixed in Ubuntu 9.10 – unmounting and spinning down the drive works just fine from GUI
As some people know there are problems with correct unplugging of external USB hard drives on linux, Ubuntu in particular. The problem is that none of graphical managers support drive spindown when unmounting/ejecting the external hard drive. This can cause severe damage to HDD.
There’s an old bug in LP for that. The summary is that you can use a script by Clem-Vangelis and Dave Rosky to do the work. Later someone posted a link to scipt by Yan Li, which does even some more stuff.
But since Ubuntu 9.04 those scripts have stopped working – the drive kept spinning. Googling around I found a similar problem and found out the problem was in udev rules. There was a manul solution in comments of LP bug #388506 mentioning udev rules editing: in ubuntu 9.04 I needed to copy the 60-persistent-storage.rules
file, modify ACTION!="add|change"
to ACTION!="add"
. This way the scripts worked. Somehow when this rule is present my home partition couldn’t be mounted. So this rules file must be removed after external drive unmount.
To make things easier I merged the scripts by Clem-Vangelis, Dave Rosky and Yan Li, updated it with udev rules workaround and done some other things. The script is as follows:
#!/bin/bash # # suspend-usb-device: an easy-to-use script to properly put an USB # device into suspend mode that can then be unplugged safely # # Copyright (C) 2009, Yan Li elliot.li.tech@gmail.com # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see http://www.gnu.org/licenses/. # # To reach the auther, please write an email to the address as stated # above. # ACKNOWLEDGEMENTS: # Christian Schmitt chris@ilovelinux.de for firewire supporting # David d.tonhofer@m-plify.com for improving parent device # search and verbose output message # # CHANGELOG: # v2 11 Aug 2009 by Sergei Sergejev https://sserzant.wordpress.com # * using predefined mountpoint instead of device drive name from parameters # * checking if sdparm is installed (bu default it's not) # * added unmount command from the script by Clem-Vangelis and D. Rosky # * created dynamic logic to process both mounted and unmounted drives # * some validation for the input # * updated for ubuntu 9.04 to overcome udev rule conflict # # change this to match your drive's mountpoint MOUNTPOINT='/media/wd' usage() { cat<<EOF suspend-usb-device Copyright (C) 2009 Yan Li elliot.li.tech@gmail.com 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. NB! Before using this script set correct mountpoint. In file manager (Nautilus) right click on the drive and put 'Location' and 'Volume' together. Volume is usually the name of the drive assigned during file system format usage: $0 [options] options: -l show the device and USB bus ID only -h print this usage -v verbose This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions; for details please read the licese at the beginning of the source code file. EOF } set -e -u SHOW_DEVICE_ONLY=0 VERBOSE=0 while getopts "vlh" opt; do case "$opt" in h) usage exit 2 ;; l) SHOW_DEVICE_ONLY=1 ;; v) VERBOSE=1 ;; ?) echo usage exit 2 ;; esac done if which sdparm >/dev/null; then echo "" else echo "sdparm is not present. Install it by running sudo apt-get install sdparm" fi # root check if [ `id -u` -ne 0 ]; then 1>&2 echo error, must be run as root, exiting... exit 1 fi # See if drive is mounted CCOUNT=$(grep $MOUNTPOINT /etc/mtab | wc -c) if [ $CCOUNT -eq 0 ]; then echo "No mountpoint $MOUNTPOINT. It is most likely you unmounted the drive" echo "" echo "Do you want to continue and try to suspend the device anyway? y/n" read ANSWER if [ $ANSWER = "Y" ] || [ $ANSWER = "y" ]; then echo "Plese give drive name eg /dev/sdb" read DEV_NAME if [ -b $DEV_NAME ]; then echo "Will try to suspend device $DEV_NAME" else echo "no such drive. Find out the drive name and run the script again" exit 1 fi else echo "exiting" exit 1 fi else #Get the physical device from mtab DRIVELINE=$(grep $MOUNTPOINT /etc/mtab) LENG=$(expr match "$DRIVELINE" '[A-Za-z0-9\/]*') DEV_NAME=$(expr substr "$DRIVELINE" 1 $LENG) #Try Unmounting the drive echo "unmounting $MOUNTPOINT" umount $MOUNTPOINT sleep 3 CCOUNT=$(grep $MOUNTPOINT /etc/mtab | wc -c) if [ $CCOUNT -ne 0 ] then echo "Could not unmount $MOUNTPOINT, drive may be in use." echo "Verify all files and programs that may use the drive are closed" echo "and run the script again" exit 1 fi fi # looking for the parent of the device with type "usb-storage:usb", it # is the grand-parent device of the SCSI host, and it's devpath is # like # /devices/pci0000:00/0000:00:1d.7/usb5/5-8 (or /fw5/fw5-8 for firewire devices) # without an USB hub, the device path looks like: # /devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host5/target5:0:0/5:0:0:0 # here the grand-parent of host5 is 2-1 # when there's a USB HUB, the device path is like: # /devices/pci0000:00/0000:00:1d.0/usb5/5-2/5-2.2/5-2.2:1.0/host4/target4:0:0/4:0:0:0 # and the grand-parent of host4 is 5-2.2 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 # the trailing basename of ${DEVICE} is DEV_BUS_ID ("5-8" in the # sample above) DEV_BUS_ID=${DEVICE##*/} [[ $VERBOSE == 1 ]] && 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 # hack for ubuntu 9.04 to overcome the udev rules # please note that leaving this rule may leave your home folder unmountable # if this happens remove the rule (sudo rm /etc/udev/rules.d/60-persistent-storage.rules) and reboot RULE_BEFORE="ACTION!=\"add|change\", GOTO=\"persistent_storage_end\"" RULE_AFTER="ACTION!=\"add\", GOTO=\"persistent_storage_end\"" sed "s/$RULE_BEFORE/$RULE_AFTER/" /lib/udev/rules.d/60-persistent-storage.rules >> /etc/udev/rules.d/60-persistent-storage.rules # flush all buffers sync # send SCSI sync command, some devices don't support this so we just # ignore errors with "|| true" [[ $VERBOSE == 1 ]] && echo "Syncing device $DEV_NAME" sdparm --command=sync "$DEV_NAME" >/dev/null || true # send SCSI stop command [[ $VERBOSE == 1 ]] && echo "Stopping device $DEV_NAME" sdparm --command=stop "$DEV_NAME" >/dev/null # unbind it; if this yields "no such device", we are trying to unbind the wrong device [[ $VERBOSE == 1 ]] && 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 # suspend it if it's an USB device (we have no way to suspend a # firewire device yet) # check if CONFIG_USB_SUSPEND is enabled [[ $VERBOSE == 1 ]] && 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. Read http://elliotli.blogspot.com/2009/01/safely-remove-usb-hard-drive-in-linux.html for an detailed explanation. EOF exit 3 fi [[ $VERBOSE == 1 ]] && echo "Suspending $DEVICE by writing to $POWER_LEVEL_FILE" echo 'suspend' > "$POWER_LEVEL_FILE" fi if [ -s /etc/udev/rules.d/60-persistent-storage.rules ]; then echo "removing temporary udev rule" rm /etc/udev/rules.d/60-persistent-storage.rules else "temporary udev rule file not found... something went wrong" fi echo "" echo "Drive can be safely unplugged"
To use the script
- copy it contents to a text file. Name it unmountwd (for example)
- put the correct mountpoint in the beginning of the script
- make it executable: right click on it in file manager, go to ‘Permissions‘ tab, tick ‘Allow executing‘ or run
chmod +x
in terminal - move the file to
/usr/bin
- enjoy it by calling from a terminal
sudo unmountwd
- push Gnome, KDE, XFCE developers to develop proper external drive unmount in file managers
Update: some drives are still not spinned down correctly – there was one issue in Launchpad and one in the comments by Sap. In both cases the drive didn’t do so both on Windows and Mac too. This a hardware, not software issue.
You are welcome to comment and fix/post bugs (if any) 🙂
Thanks for the research and improvement.
According to https://bugs.launchpad.net/ubuntu/+source/hdparm/+bug/388506 , a new hdparm has a fix. Have you tried that?
LikeLike
If I’m not mistaken, then hdparm is not suitable for me: both PCs I have by hand use SATA drives and hdparm is for ATA ones.
LikeLike
” 6. push Gnome, KDE, XFCE developers to develop proper external drive unmount in file managers”
>>> I think it should be properly well integrated upstream…It is not a desktop environment stuff…
LikeLike
Works great.
Thanks.
LikeLike
Thanks a lot for this!
I actually changed line 40 to read “MOUNTPOINT=$1” so that I could pass the mount point at the time of command since I use a couple drives with custom mount points
now I run “sudo ~/bin/nameofscript /media/wd320”
LikeLike
That is how the original script worked. Glad it helped 🙂
LikeLike
Thanks a lot for the script. I think it is working, though I am not sure. Should the device power down as well? The USB light is still on, but the drive does spin down. I’m running 9.04 as well, with a WD Passport. I don’t have a windows machine, so not sure what it is normally supposed to do. Thanks!
LikeLike
I have the same drive and blue led is on after the script is executed. Originally drive and led should be powered off. I believe it’s enough if the drive did spin down 🙂
LikeLike
Cool. In that case, thanks a lot for the script 🙂
LikeLike
Hello
I’ve been trying all sort of techniques to spin down my external usb hard drive without any success. My trials included utilities like sg3-utils, scsiadd, hdparm, sdparm, sg_start, umount, eject and Yan Li’s and your scripts.
All of them have failed to get my drive to spin down. The maximum I’ve got working with your script is that the usb-light turns off but the hard drive still keeps spinning, which results in the typical emergency-park ‘click’ sound.
I’d appreciate any help in this regard. I’m running Xubuntu 9.04 on a Dell D600 laptop and my external hdd is a 100GB Fujitsu laptop one (sata) for which I’m using a generic external usb-enclosure.
Thanks.
LikeLike
My system has an external USB WD MyBook Essential (1Tb).
When I first tried this script (very nice) to stop it I had the same problem of Sap: disk light was still on after script completion.
I tried to ececute by hand all the command script do… I was surprised that in this case the disk was correctly stopped.
After some more tests I found this behaviour on my USB disk: when the commands “sdparm –command=sync” and “sdparm –command=stop” are sent to the device, sdparam immediately return to unix prompt but the disk lignt flashes for some seconds (6-12″ for sync command and 5″ for stop).
I inserted in the script a copule of sleep just after these two commands of 20 and 10 seconsds and now it switch off correctly all my USB devices.
Sleep in procedures is not a nice solution. If someone have an idea of how to check when disk has completed the command this will make a perfect solution.
LikeLike
To FornaF, good catch! That sounds interesting… Let me try it on my MyBook.
LikeLike
Dear Sergei,
I would like to thank you as well, but being a newbie (to Ubuntu (running 9,04), to Linux) this is rather challenging for me… please delete my post if you think I am polluting your page. I am hoping this may help others in the same boat, as this should be a common functionality for an operating system… in my opinion.
I followed your instructions, was able to do #1…
#2 also I think, I changed the line to ” MOUNTPOINT=’/media/My Passport’ ”
#3 OK
#4 was difficult, as I could not drag and drop the file in the location you are instructing. Instead, I found the command ” gksudo nautilus ”
This opened another Terminal window, and I was able to move the file.
I am stuck with #5; here is the return from Terminal:
christoph@christoph-laptop:~$ sudo unmountwd
[sudo] password for christoph:
sdparm is not present. Install it by running sudo apt-get install sdparm
grep: Passport: No such file or directory
No mountpoint /media/My Passport. It is most likely you unmounted the drive
Do you want to continue and try to suspend the device anyway? y/n
y
Plese give drive name eg /dev/sdb
/dev/sdbb
no such drive. Find out the drive name and run the script again
How do you find out the drive name? I tried ” /dev/sdbb ” but obviously that didn’t work.
I figured out that sdparm was missing and tried to install it:
christoph@christoph-laptop:~$ sudo apt-get install sdparm
Reading package lists… Done
Building dependency tree
Reading state information… Done
The following packages will be REMOVED:
dcp8020lpr
The following NEW packages will be installed:
sdparm
0 upgraded, 1 newly installed, 1 to remove and 3 not upgraded.
1 not fully installed or removed.
Need to get 116kB of archives.
After this operation, 381kB of additional disk space will be used.
Do you want to continue [Y/n]? Y
Get:1 http://us.archive.ubuntu.com jaunty/universe sdparm 1.02-1 [116kB]
Fetched 116kB in 1s (97.1kB/s)
(Reading database … 129079 files and directories currently installed.)
Removing dcp8020lpr …
/var/lib/dpkg/info/dcp8020lpr.postrm: 3: /etc/init.d/lpd: not found
dpkg: error processing dcp8020lpr (–remove):
subprocess post-removal script returned error exit status 127
Errors were encountered while processing:
dcp8020lpr
E: Sub-process /usr/bin/dpkg returned an error code (1)
…..
Didn’t know what to do then.
I tried System/Administration/Synaptic Package Manager, looked for sdparm, found it, but could not install it (a bunch of error messages that were Chinese to me).
Probably, the fix is very simple…. but I’m still learning and this is too challenging for me.
Anyone want to help??!
Not sure this is needed, but I am running 9.04, Toshiba Tecra A10, and WD Passport 320GB.
Thanks a lot, and I’ll post again (results?) if I get some help!
Christoph
PS: in the meantime, I just unplug the hard drive “hot”… not great.
LikeLike
>as this should be a common functionality for an operating system
it’s sure must be
/dev/sdbb is incorrect drive name. It consists only of 3 letters as far as I know
Please plugin your drive and tell me the name of the drive icon on the desktop that will appear
then open a terminal and run this
ls /dev | grep sd
and then
ls /dev | grep hd
Please post the results here. Then I will know if you use SATA or ATA drive. Knowing this I’ll be able to give further instructions. Be sure to back-up most valuable information and don’t forget at least to unmount the drive in GUI from the desktop (right click the drive icon)
To fix the package manager (apt) run
sudo apt-get install -f
LikeLike
Hello Sergei,
Thank you for taking the time to help me out.
Here’s the name of my drive, once plugged in: “My Passport”
Here is the Terminal output after both commands:
christoph@christoph-laptop:~$ ls /dev | grep sd
sda
sda1
sda2
sda5
sdb
sdb1
christoph@christoph-laptop:~$ ls /dev | grep hd
watchdog
christoph@christoph-laptop:~$
As for the package manager errors, I’ll try to fix it myself as I believe this is a separate issue and doesn’t belong here. “sudo apt-get install -f” still returns errors.
Christoph
LikeLike
@Christoph S
Blind me 🙂 You use different quotes in MOUNTPOINT. You should use
MOUNTPOINT=’/media/My Passport’
Note that you used ´ instead of ‘, these are different things. If above doesn’t help, try to use MOUNTPOINT=’/media/My\ Passport’
And FYI your drive name is /dev/sdb
LikeLike
Sorry for the newbie question, but will this work on Ubuntu 9.10? I’m planning on buying a WD My Passport for Christmas, and I want to use this drive for my computer (that runs 9.10). I have made the script and uploaded it to http://dl.getdropbox.com/u/1928926/unmountwd
Changes I made:
1) added some text to the begining (comments)
2) added some sleep commands to one part so it looks like this:
# send SCSI sync command, some devices don’t support this so we just
# ignore errors with “|| true”
[[ $VERBOSE == 1 ]] && echo “Syncing device $DEV_NAME”
sdparm –command=sync “$DEV_NAME” >/dev/null || true
sleep 12
# send SCSI stop command
[[ $VERBOSE == 1 ]] && echo “Stopping device $DEV_NAME”
sdparm –command=stop “$DEV_NAME” >/dev/null
sleep 5
LikeLike
There were messages in the bug mentioned in the post that unmounting and suspending the drive works from GUI in 9.10.
I have a WD Passport and I’ll be able to answer if it works with it in a few days 🙂
LikeLike
Just in case you want more info, I’m getting a 250GB Western Digital My Passport Essential
LikeLike
Unmounting from GUI works just fine with WD Passport 160Gb and Ubuntu 9.10
LikeLike
I saw the integrated “Safely Remove Hardware” with nautilus on 9.10. Really nice.
Is it possible to have it on 9.04? Perhaps a nautilus script?
LikeLike
I also found that GNOME 2.28 has the “eject” function now. But I can’t find detail introduction of it. Anyone has such kind of info? Thank you.
LikeLike
I only found this
https://bugzilla.gnome.org/show_bug.cgi?id=598690
LikeLike
Thank you. It’s very useful.
LikeLike
I also needed to add sleeps after the sdparm commands to put my WD Passport to sleep (running Kubuntu 9.10). Thanks a lot for the script.
LikeLike
I ran into the same issue while looking for these scripts to make my backup drive save power and found out what was really going on. The issue is indeed exactly the same as with the hdparm bug you referenced. Both the linux command line utils that can be used to send these commands to the drive erraneously open the disk in read-write mode and it’s fixed simply by changing one line in for example sg_start. https://bugs.launchpad.net/ubuntu/+source/sdparm/+bug/444818 has more.
LikeLike