Write the name of a newly connected USB device to the console in Linux

In theory it is easy to detect when the user plugs in a USB device to a Linux computer and notify him what was detected. In practice it’s still easy as long as you know how to do it.

First thing to do is add a file to

/etc/udev/rules.d

The file name should follow the convention of NN-SomeDescriptiveName.rules, where NN is a two digit number. In our case it should be one of the last scripts to execute since by then all of the initialization by other scripts should be done and also printing the name to the console is not the most important part of the initialization. So let’s go with

99-notify_user_of_usb-drive.rules

That file defines what kind of events we are interested in. In this case, we are interested in the connection of a USB hard drive, so it looks like this:

ACTION=="add", SUBSYSTEM=="block", SUBSYSTEMS=="usb", KERNEL=="sd?1" RUN+="/usr/local/bin/usb-device-added.sh"

Note that the first 4 entries are conditions which are using C syntax, so there must be a double equal sign (Took me nearly an hour to find out that I missed one, debugging these events is not easy.).

  • ACTION==”add”: We want to know when a new device is being added
  • SUBSYSTEM==”block”: The device must be a block device (e.g. hard disk)
  • SUBSYSTEMS==”usb”: And it must be connected via USB
  • KERNEL=”sd?1″: And the device name must match /dev/sd?1, which means it must be a partition on a disk that is accessed as SCSI (basically everything nowadays)

If these conditions are met the last directive will be executed. It’s also C like, it appends something to the RUN variable, in our case we want to call the script

/usr/local/bin/usb-device-added.sh

Once you have created this file, make sure to let udev know that you did that.

sudo /etc/init.d/udev restart

should work on most Linux distributions.

The first script should be simple to check whether it is actually being called.

#!/bin/bash
exit 15

All it does is exiting with an exit code 15. This will show up in /var/log/syslog so we can check whether our script has been executed at all. Don’t forget to make it executable with

sudo chmod u+x /usr/local/bin/usb-device-added.sh

Once we are sure it does, we change it to do the real work:

#!/bin/bash

temp=${DEVLINKS#*/dev/disk/by-label/}
DevLabel=${temp%% *}
temp="${DEVNAME} (${DevLabel}) connected"
echo $temp | wall
echo $temp > /dev/console
exit 0

udev passes information about the device using many environment parameters. In our case we only want to know the device name and the partition label.

The device name is easy, it’s being passed in $DEVNAME. The device label is trickier. I only found it in $DEVLINKS which contains a list of /dev/* entries that link to the device, one of them being /dev/disk/by-label/[partition-label] which is the label of the partition of the device (and our device is the first partition, see the KERNEL filter above).

So first, we use a bit of bash magic got extract the label from $DEVLINKS, then we create the string $temp we want to write and last we send it to all logged on users using the wall command and for good measure to the local console.

Finally, we exit the script with exit code 0.

That’s it. Easy, when you know how to do it. Hard, if you have to find out about all the parts using Google (which was unhelpful as always and “found” lots of unrelated stuff even when I put the words I wanted it to look for in quotation marks. 🙁 )

Some caveats:

  • Scripts called by udev are restricted in what they are allowed to do. E.g. they usually cannot write to /tmp. It took me a while to figure that out, this answer on unix.stackexchange.com helped.
  • Also, sending an email didn’t work for me. Probably another restriction.
  • Writing to the system console is done by writing to /dev/console. (Google was only moderately helpful here again.)