3

When mounting a hard drive via UUID and another via device file, how can I make sure, that the first one is always /dev/sdaX and the second /dev/sdbX and not the other way round?

Some explanation of what I'm trying to do: I'm plugging together a raspberry pi zero, a USB hub, an external hard drive and a sd card (all powered by a power bank). Then when I power up the raspberry, it should automatically take a backup of the sd card on the external hard drive.
A simplified fstab would look like this:

...
uuid=123123   /mnt/exthd   ntfs   rw,... 0 0
/dev/sdb1     /mnt/sdcard  vfat   ro,... 0 0

I can't mount the sd card via UUID, because it will change when I format the card or of course use another card.

Question is, can I be sure, that the external drive is always mounted using /dev/sda1?

Or do I have to parse for example the output of lsblk, look which device is smaller in size, and use this device file?

Note, that I won't have any feedback from the raspberry or whatever. I have to make sure, this always works. And I think I can do the parsing myself, if necessary. The question is solely, if I have to deal with it or if there's an easier way.

  • You could reuse the same label for the filesystem whenever you format the drive and mount by label. – kba Jul 25 '16 at 11:55
  • There's the use case, that a friend comes by and says "cool dude, take a backup of mine, too". So I would rather not do this. – fancyPants Jul 25 '16 at 11:58
  • It is hard changing sda|sdb order. What you can do is look for the "place" in the hardware, see ls -l /dev/disk/by-path/. – meuh Jul 25 '16 at 12:04
  • Thanks for the hint, @meuh, but since I'm not familiar with this, I think it's easier for me to parse lsblk -b. – fancyPants Jul 25 '16 at 12:21
3

I noticed that the devpath attribute is constant for my USB ports. You could add a new udev rule and create specific symlinks based on the ports the devices are plugged in then. Just add a new file into your /etc/udev/rules.d directory, that looks like this:

#new symlink for my front USB port:
KERNELS=="2-1.8", SUBSYSTEMS=="usb", ATTRS{devpath}=="1.8", SYMLINK+="usb_port1"

and make sure it's name ends in .rules, e.g. port1.rules. From now on you can make the fstab entry using /dev/usb_port1 as any device plugged into that specific port will be listed under said symlink in /dev/ . Same for the SD card and you should be settled.

What is happening is that we check for unique properties of the specific port ( the == parts), and once these match add (+=) a new symlink to /dev/.

The information on attributes you want to match canbe retrieved via udevadm info -a /dev/sdb1 (for a device sdb1). Make sure you take attributes from only one parent device block, and that should be the one that have unique devpath and KERNELS entries - try with a few USB ports if available to see which ones change.

PS: udev will also allow to run a script when plugging in a device - might come in handy for your backup needs. However I do not know if booting your system will count as plugging in, so you'll have to check the behaviour.

  • I think I won't use devpath, but I found an awesome tutorial, that suggests using other attributes of the device to create a rule. Thanks for putting me on the right track, though. Plus, this way is much more elegant to start the script, when the device is plugged in and I can start a script when the device is plugged out, to shut the raspberry down cleanly. Do you happen to know, if and how I can write a rule, that starts a script when both devices are plugged in? – fancyPants Jul 26 '16 at 15:05
  • As for the script, the simplest option that comes into my mind is to have the script being executed upon plugging in any of the devices but have it check for both devices being present before running the backup. That way if you plug in A first, nothing happens, and once you plug in B, the backup is run (or the other way around). Maybe you could mention which attributes you are checking for in your udev rule, as they might be more unique than devpath. – Fiximan Jul 27 '16 at 13:54
1

I will most likely use Fiximan's answer, but for completeness sake, here's an example script I wrote, to mount the device which is smaller in size and is not yet mounted.

#!/bin/bash

output=$(lsblk -b -I 8 -i | grep "^[\`|]-sd.1" | awk '{print substr($1,3), $4, $7}')

cursize=999999999999999

while read dev size mountpath; do
        echo $dev :: $size :: $mountpath
        if [[ $size -lt $cursize && -z $mountpath ]]
        then
                cursize=$size;
                dev2mount=$dev;
        fi
done <<< "$output"

echo to mount: $dev2mount of $cursize size

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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