Linux – Create device symlink with udev based on device response, not udev device info

linuxserial-portudevusbserial

I have three different serial devices connected to three usb-serial converters (FTDI USB-RS232). If I connect them, I get the generic device names /dev/ttyUSBx as expected. When I try to write some udev rules, udevadm shows me the same output for the three devices except in some device serial id attributes.

Those serial id's will change on every device so if I use a different usb-serial converter, my rules won't work anymore. So, I need a way to communicate with the specific device connected to the serial converters and identify it by its response.

"Writing udev rules" HOWTO, says the following about using PROGRAM functionality to call an external program to name devices:

PROGRAM is used for running programs which produce device names (and they shouldn't do anything other than that). When those programs are being executed, the device node has not yet been created, so acting upon the device in any way is not possible,

Rule example:
SUBSYSTEM=="usb", PROGRAM="/bin/device_namer %k", SYMLINK+="%c"

so I can't write to /dev/ttyUSBx from there to identify the device. Then, I have the RUN functionality, but it seems that it can't create a new SYMLINK as udev won't get RUN's output.

Rule example:
SUBSYSTEM=="usb", RUN="/bin/program"

Can I instruct udev from that RUN script to create the symlink? Or can I create that symlink by hand from there?

Thanks

Best Answer

Blindly chatting on a serial port automatically the moment it is connected to the computer is quite a scary thing to do. Are you sure you want to do this? First of all it will take some time, which will delay the appearance of the device node if udev has to wait for a result before creating it. If the device happens to be powered off or its serial port is disconnected then you won't be able to name it properly (and you will need to have a timeout to detect this). Finally, if another device besides one of the ones you expect is connected, you may be sending it garbage that has unintended consequences.

You might consider relying on the adaptors' serial numbers to tell them apart, and associate each adaptor to an external device in a consistent fashion. If your adaptors even have real serial numbers instead of placeholder strings like 00000000 then you are already lucky!

Nevertheless, this is how you would do it.

As you suspected, you can't use RUN, because that's too late, the device node has already been created. You have to use PROGRAM. In your program you are going to have to create the device node yourself using mknod because udev hasn't done it yet. You should create a temporary node in a temporary location and destroy it before your program exits.

### Create the temporary device node in /tmp
device="/tmp/udev_device_guesser.$$"
# Note: mknod does not appear to be vulnerable to a symlink attack
mknod "$device" c "$MAJOR" "$MINOR"

### Use this device node to query what's attached to the serial port
insert your code here

### Get rid of the temporary node
rm -f "$device"
exit 0
Related Topic