Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm running Debian Squeeze on a plug computer (so SSH only, no GUI) and what I'm trying to do is get it so that when a USB stick is plugged in, it gets automatically mounted.

What I've done is install autofs which from what I gather handles the automounting providing it knows where the device is in /dev.

The problem is that the USB stick isn't always on the same device name. Sometime's it's /dev/sdc1, sometimes /dev/sdd1, etc.

I gather that to remedy this, I need to use udev to ensure that the USB stick is always given the same name.

I got the following info out of udevadm:

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/block/sdd/sdd1':
    KERNEL=="sdd1"
    SUBSYSTEM=="block"
    DRIVER==""
    ATTR{partition}=="1"
    ATTR{start}=="63"
    ATTR{size}=="129339"
    ATTR{ro}=="0"
    ATTR{alignment_offset}=="0"
    ATTR{discard_alignment}=="0"
    ATTR{stat}=="      31      244      275      190        0        0        0        0        0      190      190"
    ATTR{inflight}=="       0        0"

  looking at parent device '/devices/platform/orion-ehci.0/usb1/1-1/1-1.2/1-1.2:1.0/host8/target8:0:0/8:0:0:0/block/sdd':
    KERNELS=="sdd"
    SUBSYSTEMS=="block"
    DRIVERS==""
    ATTRS{range}=="16"
    ATTRS{ext_range}=="256"
    ATTRS{removable}=="1"
    ATTRS{ro}=="0"
    ATTRS{size}=="129439"
    ATTRS{alignment_offset}=="0"
    ATTRS{discard_alignment}=="0"
    ATTRS{capability}=="51"
    ATTRS{stat}=="      56      727      783      520        0        0        0        0        0      520      520"
    ATTRS{inflight}=="       0        0"
    ATTRS{events}=="media_change"
    ATTRS{events_async}==""
    ATTRS{events_poll_msecs}=="-1"

  looking at parent device '/devices/platform/orion-ehci.0/usb1/1-1/1-1.2/1-1.2:1.0/host8/target8:0:0/8:0:0:0':
    KERNELS=="8:0:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS=="sd"
    ATTRS{device_blocked}=="0"
    ATTRS{type}=="0"
    ATTRS{scsi_level}=="3"
    ATTRS{vendor}=="        "
    ATTRS{model}=="Flash Disk      "
    ATTRS{rev}=="2.00"
    ATTRS{state}=="running"
    ATTRS{timeout}=="30"
    ATTRS{iocounterbits}=="32"
    ATTRS{iorequest_cnt}=="0x90"
    ATTRS{iodone_cnt}=="0x90"
    ATTRS{ioerr_cnt}=="0x0"
    ATTRS{modalias}=="scsi:t-0x00"
    ATTRS{evt_media_change}=="0"
    ATTRS{queue_depth}=="1"
    ATTRS{queue_type}=="none"
    ATTRS{max_sectors}=="240"

  looking at parent device '/devices/platform/orion-ehci.0/usb1/1-1/1-1.2/1-1.2:1.0/host8/target8:0:0':
    KERNELS=="target8:0:0"
    SUBSYSTEMS=="scsi"
    DRIVERS==""

  looking at parent device '/devices/platform/orion-ehci.0/usb1/1-1/1-1.2/1-1.2:1.0/host8':
    KERNELS=="host8"
    SUBSYSTEMS=="scsi"
    DRIVERS==""

  looking at parent device '/devices/platform/orion-ehci.0/usb1/1-1/1-1.2/1-1.2:1.0':
    KERNELS=="1-1.2:1.0"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb-storage"
    ATTRS{bInterfaceNumber}=="00"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bNumEndpoints}=="02"
    ATTRS{bInterfaceClass}=="08"
    ATTRS{bInterfaceSubClass}=="06"
    ATTRS{bInterfaceProtocol}=="50"
    ATTRS{modalias}=="usb:v1976p6025d0100dc00dsc00dp00ic08isc06ip50"
    ATTRS{supports_autosuspend}=="1"

  looking at parent device '/devices/platform/orion-ehci.0/usb1/1-1/1-1.2':
    KERNELS=="1-1.2"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{configuration}==""
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bmAttributes}=="80"
    ATTRS{bMaxPower}=="100mA"
    ATTRS{urbnum}=="383"
    ATTRS{idVendor}=="1976"
    ATTRS{idProduct}=="6025"
    ATTRS{bcdDevice}=="0100"
    ATTRS{bDeviceClass}=="00"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{speed}=="12"
    ATTRS{busnum}=="1"
    ATTRS{devnum}=="11"
    ATTRS{devpath}=="1.2"
    ATTRS{version}==" 1.10"
    ATTRS{maxchild}=="0"
    ATTRS{quirks}=="0x0"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{authorized}=="1"

  looking at parent device '/devices/platform/orion-ehci.0/usb1/1-1':
    KERNELS=="1-1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{configuration}==""
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bmAttributes}=="e0"
    ATTRS{bMaxPower}=="100mA"
    ATTRS{urbnum}=="197"
    ATTRS{idVendor}=="1a40"
    ATTRS{idProduct}=="0101"
    ATTRS{bcdDevice}=="0111"
    ATTRS{bDeviceClass}=="09"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="01"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{speed}=="480"
    ATTRS{busnum}=="1"
    ATTRS{devnum}=="2"
    ATTRS{devpath}=="1"
    ATTRS{version}==" 2.00"
    ATTRS{maxchild}=="4"
    ATTRS{quirks}=="0x0"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{authorized}=="1"
    ATTRS{product}=="USB 2.0 Hub"

  looking at parent device '/devices/platform/orion-ehci.0/usb1':
    KERNELS=="usb1"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{configuration}==""
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bmAttributes}=="e0"
    ATTRS{bMaxPower}=="  0mA"
    ATTRS{urbnum}=="24"
    ATTRS{idVendor}=="1d6b"
    ATTRS{idProduct}=="0002"
    ATTRS{bcdDevice}=="0206"
    ATTRS{bDeviceClass}=="09"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="01"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{speed}=="480"
    ATTRS{busnum}=="1"
    ATTRS{devnum}=="1"
    ATTRS{devpath}=="0"
    ATTRS{version}==" 2.00"
    ATTRS{maxchild}=="1"
    ATTRS{quirks}=="0x0"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{authorized}=="1"
    ATTRS{manufacturer}=="Linux 2.6.38.8 ehci_hcd"
    ATTRS{product}=="Marvell Orion EHCI"
    ATTRS{serial}=="orion-ehci.0"
    ATTRS{authorized_default}=="1"

  looking at parent device '/devices/platform/orion-ehci.0':
    KERNELS=="orion-ehci.0"
    SUBSYSTEMS=="platform"
    DRIVERS=="orion-ehci"
    ATTRS{modalias}=="platform:orion-ehci"

  looking at parent device '/devices/platform':
    KERNELS=="platform"
    SUBSYSTEMS==""
    DRIVERS==""

I've been trying to write udev rules to force the USB stick to take the name /dev/usbstick but so far I haven't been successful.

Can someone help out with what rule I need to specify in my rules file to get this USB stick to always get the same name?

-- Or, is there much easier way to automount the USB stick that I'm missing entirely?

UPDATE

OK so I have made some progress. I added the following rule:

SUBSYSTEMS=="scsi", ATTRS{model}=="Flash Disk ", DRIVERS=="sd", NAME="usbstick-%k" RUN+="mkdir /mnt/usbstick-%k; mount /dev/usbstick-%k /mnt/usbstick-%k"

I know this still needs some work in terms of handling add/remove, but it's just a basic test for now.

The effect of this is that I now manage to get three new device nodes in /dev, namely /dev/usbstick-sdc, /dev/usbstick-sdc1 and usbstick-sg2.

However, what I've found is that the code in the RUN section only executes once and just makes a directory mnt/usbstick-sdc. I've also found that the directory is always empty, so something is clearly still going wrong! (although I'm making progress).

share|improve this question
    
Was that second /dev/sdc1 supposed to be sdd1? And you can use blkid to uniquely identify the drive (well, actually the partition; it'll change if you reformat). –  Kevin Nov 16 '11 at 15:03
    
Correct, just fixed that. All I want to happen is that when a USB stick is plugged in it gets mounted to some directory. I'm pretty sure I should be using a udev rule to create device nodes for each partition, but I'm not sure what level of the udevadm output to be making rules for! –  jon Nov 16 '11 at 15:09
    
Your rule looks too complicated. Try to make a simple one, with just one ACTION==, one KERNEL== and one ATTRS{something}== (it is completely doable - this is what I use). Also, consider running a single script instaed of the chain of commands in RUN+=. –  rozcietrzewiacz Nov 16 '11 at 16:38
    
Thanks for the advice, but the question remains: which level of the device tree should I be targeting with my rule? This all seems terribly confusing and there really isn't much info online to explain this. I really appreciate the time you've taken to explain it to me so far, I feel like I'm almost there but just missing the level to be targeting. –  jon Nov 16 '11 at 16:42
    
I've now tried this very basic rule: KERNEL=="sd??", NAME="%k", RUN+="mkdir /mnt/usbstick-%k; mount /dev/usbstick-%k /mnt/usbstick-%k" -- but no, of course this doesn't work either. I'm now getting increasingly frustrated after spending nearly the whole day simply trying to work out how to get a USB stick that's plugged in to mount itself. Should things really be this difficult? The output from udevadm test /sys/block/sdd is -- of course -- practically unreadable, so I have no means of knowing where I'm going wrong. Can anyone point me in the right direction on this? –  jon Nov 16 '11 at 17:22

4 Answers 4

Figured there should be a much easier way to address such a common problem, and there is. Here's what I tried on my wheezy/sid server:

sudo apt-get install usbmount

Plug in usb stick, done! My stick is now accessible through /media/usb.

Btw, usbmount doesn't have a man page, please read /usr/share/doc/usbmount/README.gz instead. It seems usbmount mounts your stick with the sync option by default. It might be a whole lot better for your stick to mount it async and run sync or umount before unplugging it. That is configurable.

share|improve this answer
    
see also pumount –  Alex Aug 18 '13 at 18:59
    
Pay attention that usbmount no longer support NTFS since debian jessie: bugs.debian.org/774149 –  malat May 19 at 15:32

Notice that you can't just have a single device node to represent any possible pendrive attached. What if you plug two of them? Or when the pendrive has more than one partition?

Generally, what you use to create a custom-named device node, is SYMLINK+=. grep for it in the rules to see how it's used: grep SYMLINK /etc/udev/rules.d/*. As in all udev-triggered commands, you can use some meaningful variables that are described in man udev. You might realize you don't really need to give a custom name to the device, since you can feed it's name to a script (via the %k variable).

As for the auto-mount solution, have a look at UAM, which I've described a little bit in the answer to this question.

share|improve this answer
    
I understand these constraints. As it happens, I only ever need to support a single USB stick connected at any one time to this particular system. However, I would need to support multiple partitions on the USB stick (it would be nice if these could be mounted into subfolders from the mount point). Given these requirements, do you have any advice for a potential solution? Due to the nature of the project, I need to avoid using additional third-party software if at all possible. –  jon Nov 16 '11 at 14:59
    
Then have a look at the edit I just made (the middle part). Would this be enough? –  rozcietrzewiacz Nov 16 '11 at 15:07
    
Also note that UAM is not really a program - it is a bunch of nice udev rules with accompanying scripts. You can have a look at the rules and easily adapt them to your needs. –  rozcietrzewiacz Nov 16 '11 at 15:12
    
Thanks for the advice. One other thing: do you think that you could look at my output from udevadm and tell me which device is the device I should actually be targeting with my rule? The various examples I've seen online all seem to involve much shorter trees and each example seems to target a different level of device, with no explanation of which one should be targeted and why. –  jon Nov 16 '11 at 15:49
    
Just added an update above, any ideas? Thanks! –  jon Nov 16 '11 at 16:18

Sorry to answer my own question, and many thanks are due to rozcietrzewiacz for contributing, but I eventually managed to make some major progress using the following rule after hours of reading online:

SUBSYSTEMS=="scsi", KERNEL=="sd[a-h]1", SYMLINK+="removable", RUN+="/bin/mount /dev/removable /path/to/mount"

This will mount the first partition of any SCSI device. I guess the next question will be how to mount multiple partitions, but that's another issue for another day.

share|improve this answer
1  
It is not a good rule. This will match also the partitions of hard drives. there is a removable attribute you should test for, and rather block instead of scsi. –  rozcietrzewiacz Nov 18 '11 at 10:18

Here is how I recently did it, and I am quite happy with this approach now. This is for Ubuntu 12.04 + Gentoo, but I guess any distro, which allows to install udev and autofs should work.

Prerequisites: You have to have installed udev + autofs.

Step 1)

Create the following "/etc/udev/rules.d/90-usbsd-auto.rules" file (of course you might use any name as long as it ends with ".rules"). :

# Add symlink /dev/usbdisks/<label> to /dev/sd[a-z][1-9] 
# for automounter support

ACTION=="add", KERNEL=="sd*", ENV{DEVTYPE}=="partition", \
    ENV{ID_BUS}=="usb", \
    SYMLINK+="usbdisks/%k", MODE:="0660", \
    RUN+="/bin/rm /media/usb/%k", \
    RUN+="/bin/ln -sf /media/autousb/%k /media/usb/%k"

# Some FileSystems emit a "change" event when they are unmounted.
# UDEV seems to delete the device symlink in this case :-(
# So we need to re-create it here
ACTION=="change", KERNEL=="sd*", ENV{DEVTYPE}=="partition", \
    ENV{ID_BUS}=="usb", \
    SYMLINK+="usbdisks/%k", MODE:="0660"


# When device is removed, also remove /media/usb/<...>
ACTION=="remove", KERNEL=="sd*", ENV{DEVTYPE}=="partition", \
    ENV{ID_BUS}=="usb", \
    RUN+="/bin/rm /media/usb/%k"

What does this do: It creates two symlinks, one for the USB storage device partition under "/dev/usbdisks/<...>".

The second symlink will link from "/media/usb/<...>" to "/media/autousb/<...>" this is done for automounter support (see step 2).

To make sure udev reads these rules use

sudo udevadm control --reload-rules

Note: Same name for same usb stick: Possible but maybe dangerous: You might use for example "$env{ID_FS_LABEL_ENC}", instead of "%k" in the above UDEV rules. This will use the volume label to create /media/usb/<...>, but what happens if you plug in two USB sticks and both use the same volume label...

With this udev rules file everything is setup to automount the USB storage device partition. Note though that right now, the device will NOT be automounted (intentionally). It will be automounted once you use it with

Step 2)

Setup autofs to automount /media/autousb/<...> : I added the following line to my "/etc/auto.master" file (for Ubuntu 12.04):

/media/autousb /etc/auto.usb --timeout=60

This means that AutoFS will unmount the device after 60 seconds of inactivity. You might want to use less or more, dependent on your taste.

For Gentoo you have to modify "/etc/autofs/auto.master" so it makes sense to use

/media/autousb /etc/autofs/auto.usb --timeout=60

Now I created "auto.usb" with the following content:

#!/bin/bash

key=${1}
fstype=$(/sbin/blkid -o value -s TYPE /dev/usbdisks/${key})
if [ "${fstype}" = "vfat" ] ; then
  echo "-fstype=vfat,sync,uid=0,gid=plugdev,umask=007 :/dev/usbdisks/${key}"
  exit 0
fi
if [ "${fstype}" = "ntfs" ] ; then
  echo "-fstype=fuse.ntfs-3g,sync,uid=0,gid=plugdev,umask=007 :/dev/usbdisks/${key}"
  exit 0
fi
if [ "${fstype}" = "ext4" ] ; then
  echo "-fstype=ext4,sync,nocheck :/dev/usbdisks/${key}"
  exit 0
fi

exit 1

This auto.usb needs to be executable, so that autofs uses this as a (bash) script. So for example

sudo chmod 0755 /etc/auto.usb

What does this do: This script will tell AutoFS (/usr/sbin/automount) how to mount the usb storage device partition.

The script will first use "/sbin/blkid" to find out what kind of file system is on the partition.

The script will then provide the right mount options depending on the device partition.

Note: I included sample code for "vfat" (probably most common for usb sticks), "ntfs" and "xfs" file systems. Of course it is quite easy to extend this to support more file systems.

Step 3)

Optional... To "eject" == unmount your usb stick(s) (or partitions on your usb stick), create a script under /sbin/usbeject :

#!/bin/bash
killall -s SIGUSR1 /usr/sbin/automount

With this script you might use "sudo usbeject" to unmount all mounted USB device partitions (by telling automount to unmount them).

Of course you can simply make sure that the partition is not used anywhere; automounter will then unmount the partition after the 60 second timeout...

The real trick here is to use symlinks from "/media/usb" to "/media/autousb":

  • The "/media/usb" symlinks will be created by udev, giving a user a simple overview which usb storage device partitions are there
  • AutoFS will then automount the partition on demand if you use it via /media/usb
  • With the scripted "auto.usb" file you might support any kind of file system and additionally you also are able to support any kind of naming scheme.
  • This approach supports USB sticks with multiple partition, even if these partitions use different file system types.
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.