62

Is there a way to run a script when a particular USB device is mounted?

I keep my videos on a separate USB and would like to run a script that would mount the video folder on the USB device to the one in the home folder.

Braiam
  • 67,791
  • 32
  • 179
  • 269

6 Answers6

52

There's much nicer solution with systemd now. You create a service which depends and is wanted by you media e.g.: /etc/systemd/system/your.service

[Unit]
Description=My flashdrive script trigger
Requires=media-YourMediaLabel.mount
After=media-YourMediaLabel.mount

[Service]
ExecStart=/home/you/bin/triggerScript.sh

[Install]
WantedBy=media-YourMediaLabel.mount

Then you have to start/enable the service:

sudo systemctl start your.service
sudo systemctl enable your.service

After mount, systemd fires your trigger script. The advantage over udev rule is that the script really fires after mount, not after adding system device.

Use case: I have an encrypted partition which I want to backup automatically. After adding the device I have to type in the password. If I hooked the backup script to udev, the script attempts to run at the time when I'm typing password, which will fail.

Resource: Scripting with udev

Note: You can find your device unit with:

systemctl list-units -t mount
Pablo Bianchi
  • 15,657
sumid
  • 631
  • I hope april 2016 is coming soon. The next Ubuntu LTS will have systemd enabled. AFAIK the nice solution from above needs Ubuntu 15.04 or newer. – guettli Nov 04 '15 at 08:03
  • Oh, I thought systemd already is in ubuntu. I'm actually running debian stretch ;-) – sumid Nov 04 '15 at 09:00
  • @sumid If I want to put it under ~/.config/systemd , will it work? – Khurshid Alam Jul 01 '16 at 06:40
  • 5
    Great! Tested in Debian Jessie. Don't forget to enable your service systemctl enable your.service. The script file must be executable. – Powerriegel Jul 03 '16 at 13:13
  • I confirm this is the way to go with systemd enabled distro. Running nicely on Debian Stretch. – ripat Jul 29 '16 at 14:04
  • 1
    For me, this fails. When I try to start the service, it complains with "Unit media-bb.mount not found.". I called my thumb drive's (FAT32) FS "bb" to make sure there are no weird characters in it and it's not too long or anything like this. I tried the Requires=, After=, and WantedBy= lines both with media-bb.mount and media-BB.mount because Nautilus shows me the volume as "BB", not "bb". Same error message, except for capitalization. What's wrong? Do I somehow have to create that media-<something>.mount service? – UTF-8 Nov 17 '17 at 00:19
  • What is YourMediaLabel and how do I find that value? – Steven Jeffries Jul 03 '19 at 01:23
  • 1
    @StevenJeffries systemctl list-units -t mount gives you that label. Systemd automatically creates .mount units and as far as I can tell, it's a mount path, but with slashes (/) replaced by dashes (-). And one note: this unit also works as a user unit (systemctl --user). – Michał Góral Apr 22 '20 at 06:26
  • @KhurshidAlam for systemctl --user you need to write your service in ~/.config/systemd/user/your.service – Markus Weber Oct 22 '20 at 19:52
  • Am I wrong or the other advantage of using this solution over udev is that ExecStart scripts are run asynchronously? Thank You by the way. – kcpr Jan 08 '21 at 01:13
  • How to pass information on what device whas mounted (path to it) and how to handle multiple devices munted? – Dims Feb 11 '23 at 13:47
  • I know this is ancient, but please don't put your own service definitions in /etc/systemd/system/. That's what systemctl enable is for. – Auspex Jan 22 '24 at 21:47
31

Start by finding your device in lsusb. Note the ID (eg 0a81:0101)

Create a new udev rules file in /etc/udev/rules.d/ via sudoedit /etc/udev/rules.d/100-mount-videos.rulesand plonk a new rule in there like this:

ACTION=="add", ATTRS{idVendor}=="0a81", ATTRS{idProduct}=="0101", RUN+="/home/your_username/bin/mount_videos.sh"

Note how I used the ID from lsusb.

Then you just need to write the script to do the work. A simple mount command should work. You might need a sleep 5 command in there to wait for the filesystem to initialize (if you leave gnome to do the main mounting -- but you're free to mount it first and then you might not need the sleep).

Addition from Allan: Long running scripts might block "all further events for this or a dependent device". My Mint man page further states "Long running tasks need to be immediately detached from the event process itself." No tip is given on where to gain the skill to do this.

Reply from Oli: Wrap it like so: https://askubuntu.com/a/106359/449

Oli
  • 293,335
  • 4
    I might suggest prefixing the "RUN" command with "su your_user -c" so that the script is not running with root privileges. – Kees Cook Feb 07 '11 at 06:29
  • 3
    @Kees As the aim here is mounting, keeping root privs might be a good idea though. Perhaps instead of keeping the script in the user's home, you keep it in /root/ or somewhere where only root can edit it. – Oli Feb 07 '11 at 11:11
  • 2
    This doesn't answer the question. The question asks how to run a script when a USB drive is mounted. This answer says how to do run a script that does mounts a USB drive when it is inserted. The difference matters to me because I have such a script (for a digital camera); without the script, the drive may or may be mounted on insertion (depending on user settings) and it's only when the drive is mounted that I want to do something (copy the images). So my script (which runs when the drive is added) often runs at the wrong time. – Reinier Post Sep 15 '13 at 20:30
  • PS see http://ubuntuforums.org/showthread.php?t=1551835 – Reinier Post Sep 15 '13 at 20:39
  • this is an incredibly specific (brittle) way to achieve. @sumid answer more applicable to modern distro's using *systemd* – MrMesees Oct 02 '16 at 03:53
  • This doesn't do anything when I try it. I triple-checked the vendor ID and product ID of my thumb drive and chose a very simple path with no weird characters to my script (there is not much you can get wrong with /t/t.sh). The script definitely works both when I run it as my normal user and as root. Is there something you have to do to get the automation going? – UTF-8 Nov 17 '17 at 00:21
  • How to pass information on what device whas mounted (path to it) and how to handle multiple devices munted? – Dims Feb 11 '23 at 13:47
8

Another way to get the values for ATTRS{idVendor} and ATTRS{idProduct} (tested in Ubuntu 12.04) is:

  1. Find where your usb is mounted:

    $ mount | grep /dev/sd*
    

    this shows something like the following:

    /dev/sdb on /media/SOMEDIR type vfat ...
    
  2. Use udevadm to get that device info:

    udevadm info -q all -n /dev/sdb | grep -E -i -w '.*VENDOR_ID.*|.*MODEL_ID.*'
    

    the output should be something like:

    E: ID_MODEL_ID=001a
    E: ID_VENDOR_ID=002b
    
  3. Now use the model id for ATTRS{idProduct} and vendor id for ATTRS{idVendor}

    ACTION=="add", ATTRS{idVendor}=="002b", ATTRS{idProduct}=="001a" ...
    
emont01
  • 191
3

In Nautilus under Edit>Preferences>Media you can choose "other action" and than "custom command" for different kinds of scripts/commands to be executed. By that time the usb drive is already mounted, but I suppose you could still link it (with a custom command) to the folder you want the drive to appear in. I couldn't tell whether this is easier or better than using udev.

talonx
  • 105
  • 5
bacon
  • 158
1

If you don't want to interfere with your filemanager (nautilus, konquerer, gnome, etc) 's control over mounting and unmounting your device, I suggest not going the udev route.

Instead, use udisks-glue if your system uses udisks (almost all do).

After installing, just create a config file ~/.udisks-glue.conf in your home directory like this.

My following example updates GPS-Assist data on my camera everytime I plug in the SD-card.

filter BT16EXTREME {
  optical = false
  partition_table = false
  usage = filesystem
  label = BT16EXTREME
}
match BT16EXTREME {
  post_mount_command = "/home/bernhard/update-gps-assist-data.pl %mount_point"
}

Afterward just make sure udisks-glue starts when you boot or log-in. I.e. via gnome's startup applications

xro
  • 61
1

@sumid's answer has a problem. You should not start the service. You just need to enable it.

file: /etc/systemd/system/your.service

[Unit]
Description=My flashdrive script trigger
Requires=media-YourMediaLabel.mount
After=media-YourMediaLabel.mount

[Service]
ExecStart=/any_path_even_inside_the_mount_point/script.sh

[Install]
WantedBy=media-YourMediaLabel.mount

Then enable the service:

sudo systemctl enable your.service

That's all.

Note: You can find your medial label with: sudo systemctl list-units -t mount

Note2: If the service is failed somehow (for example, the script is not executable), your mount point will change to <old_mount_point_name>1 next time you mount the usb device. To fix this issue, you just need to execute sudo systemctl reset-failed

sgon00
  • 111
  • 'Failed to enable unit: Unit file your.service does not exist` – Michael Jun 11 '20 at 21:23
  • Since the question was related to disk mounting: I had a problem trying to execute udisks or gnome-disk-image-mounter because (as far as I can make out) it only works properly in a logged-in shell. The solution was to create a user service: that means (a) make the file in ~/.config/systemd/user instead of /etc/systemd/system, and use systemctl --user enable your.service instead of sudo systemctl enable your.service. Also cleaner because you don't need root access! – Hippo Sep 27 '23 at 12:05