2

I have written a daemon that manages a number of communication protocols over one, or multiple RS232 devices (typically FT232R usb2serial). Once a /dev/ttyUSB* device appears, if certain attributes are detected, systemd is told to start that daemon via udev:

ENV{SYSTEMD_WANTS}="%s{manufacturer}.service" 

Once the daemon has started, it needs to be told which device to open, which I do via udev:

RUN="/usr/bin/sercomc open %E{sd_name} %E{sd_proto} %N" 

So the complete udev rule reads like:

ACTION=="add", SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{manufacturer}=="sercomd", ENV{SYSTEMD_WANTS}="%s{manufacturer}.service", ENV{sd_proto}="%s{product}", ENV{sd_name}="%s{serial}", RUN="/usr/bin/sercomc open %E{sd_name} %E{sd_proto} %N" 

Now the problem is that RUN is executed before the daemon is started so that this command obviously has no effect:

systemd-udevd[1638]: starting '/usr/bin/sercomc open ctl-vk1 ctserial /dev/ttyUSB0' systemd-udevd[1632]: '/usr/bin/sercomc open ctl-vk1 ctserial /dev/ttyUSB0'(err) 'Couldn't connect to server: Connect failed: Connection refused' [...] sercomctl[1639]: [2015-10-12 03:05:39:291634] Serial communication daemon ver. 0.5 starting up 

Is there a recommended way in resolving this, i.e. trigger running the command once that systemd has finished starting the service?

0

1 Answer 1

1

If you've stumbled upon a similar problem and read the question, don't let yourselves be confused by the name of my software in use. Let it be quickly said that "sercomd" is the name of the daemon that manages the serial connections and "sercomc" is a client program that tells sercomd to open that device using a certain protocol. Furthermore, I have manipulated the EEPROM of the FTDI usb2serial chip such that product, manufacturer and serial strings display user-defined values which I can use for "plug and play" autorecognition of serial adapters.

What I'm doing is now using an instanciated service with unit file /lib/systemd/system/[email protected] for every device that appears.

The udev rule now reads:

 SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{manufacturer}=="sercomd", ACTION=="add", SYMLINK="tty%s{serial}", PROGRAM="/bin/systemd-escape %s{serial}", ENV{SYSTEMD_WANTS}="sercomd@%c.service", ENV{sd_proto}="%s{product}", ENV{sd_dev}="%N" 

This rule sets a few environment variables sd_proto and sd_dev, and the third parameter sd_dev which can then be extracted from the [email protected] file:

 ExecStart=/bin/bash -c "eval $$( udevadm info --query=env --export /dev/tty%I ); sercomc open %I $$sd_proto $$sd_dev" ExecStop=/usr/bin/sercomc -l %I close 

Thus every time a device is added or removed from the USB hub, the appropriate client command is run from systemd. By adding

 Requires=sercomd.service After=sercomd.service 

to the unit file, it will also make sure my daemon that actually manages these interfaces is started before the client gets run.

Sign up to request clarification or add additional context in comments.

1 Comment

If you think your question is confusing, edit your question to explain.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.