I'm trying to execute a shell script with systemd.
If I run my script from the bash everything works fine. But if I run the same script via systemd it never finishes. The command where it seems to hang is:
random="$(LC_ALL=C tr -cd '[:alnum:]' < /dev/urandom | fold -w128 | head -n1)"
If I'm replacing this line with random="1234"
it also runs with systemd. I guess the 'hanging' command is the tr
- its process never finishes.
And this is the systemd unit file I'm using:
[Unit]
Description=my script
[Service]
Type=forking
Restart=on-failure
ExecStart=/mypath/script.sh start
ExecStop=/bin/kill $MAINPID
ExecStopPost=/bin/rm -f /mypath/RUNNING_PID
[Install]
WantedBy=multi-user.target
Edit: Made the explanation clearer and added new information.
Short answer: Set IgnoreSIGPIPE=false
under [Service]
in the .service
file. From the systemd.exec
manual:
IgnoreSIGPIPE= Takes a boolean argument. If true, causes SIGPIPE to be ignored in the executed process. Defaults to true because SIGPIPE generally is useful only in shell pipelines.
Long explanation:
random="$(LC_ALL=C tr -cd '[:alnum:]' < /dev/urandom | fold -w128 | head -n1)"
When the head
command exits after the first newline received from fold
, it's open file descriptors are closed. When the fold
command later tries to write to the pipe, it will receive a SIGPIPE
signal. The default action for this signal is a termination of the process. This should normally lead to the termination of the fold
command, and likewise the subsequent termination of the tr
command.
However, when the pipeline is run under systemd
, systemd
sets the default action for SIGPIPE
to SIG_IGN
, which makes the processes in the pipeline ignore the signal. While the fold
command ignores the signal, it will still receive an EPIPE error when it writes to the broken pipe. But the fold
command does not check the return value of any of the fwrite
calls, at least not in coreutils-8.26
. This leads the fold
command to continue reading from std in and oblivious to the error, write to std out. In doing so, fold
keeps the pipe from tr
open. Since also tr
ignores the SIGPIPE
, and the pipe to fold
is open, it just continues reading from /dev/urandom
and writing filtered bytes to the pipe forever.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With