8

I made a systemd service that launches a simple .sh to read data from a serial connection. If I run the service manually after booting it works fine, but when I try to run it automatically at boot it fails because the .sh can't yet read from ttyUSB0 (awk: fatal: cannot open file /dev/ttyUSB0' for reading (No such file or directory).

Is there any way to make the service wait for ttyUSB0 and then run the .sh? I tried something like after=ttyUSB0 but that doesn't work.

[Unit] 
Description=Serial logger

[Service] 
ExecStart=/serial_script.sh

[Install] 
WantedBy=default.target
sjaak
  • 584

2 Answers2

12

Consider using an udev rule instead of a systemd service to start your script. Never mind, since starting long-running processes from udev is not recommended, and newer udev versions may actively try and prevent it by having a strict time limit for udev transactions and processes spawned by them.

But if you need to do it in udev (e.g. in an old system that has an old version of systemd), something like this in /etc/udev/rules.d/99-serial-logger.rules should work:

SUBSYSTEM=="tty", ACTION=="add", KERNEL=="ttyUSB0", RUN+="/serial_script.sh"

When implementing this as a systemd service (the current recommended way), remove the WantedBy=default.target line from your service and make your udev rule like this:

SUBSYSTEM=="tty", KERNEL=="ttyUSB0", TAG+="systemd", ENV{SYSTEMD_WANTS}+="your-serial-logger.service"

As a result, udev should tell systemd to start your service when the device appears, and to stop it if/when the device is removed.

telcoM
  • 96,466
  • 3
    The systemd route is probably better, since starting long-running processes from udev is not recommended. See also https://unix.stackexchange.com/a/249630/233460 – Matthijs Kooijman Jun 04 '19 at 13:26
0

Rules like this in UDEV dont work

SUBSYSTEM=="tty", ACTION=="add", KERNEL=="ttyUSB0", RUN+="/serial_script.sh"

Use serial_script.sh | at now to run the job detached from udev process. UDEV prevents you from starting long-lived background processes in RUN or PROGRAM scripts. But, the "right way" to do this is with systemd. I recommend reading Instantiated Services with systemd and Proper way to start long-running systemd service on udev event and Starting systemd service instance for device from udev

Glorfindel
  • 815
  • 2
  • 10
  • 19
Gustavo
  • 61