7

I am curious as to what this difference is between programs that are; started with systemd when enabled through systemctl, vs those started by means of /etc/rc.local or through the CLI.

For example, I was recently using shairport-sync for the raspberry pi. Initially, I set shairport-sync to start by means of sudo systemctl enabled shairport-sync.

Later down the road I used a functionality within shairport-sync to run scripts prior and post to devices connecting.

To my surprise, the scripts when executed by shairport-sync did not kill arecord or aplay

However, when I would run the script via terminal the script executed and killed arecord and aplay.

To further confuse myself, I killed shairport-sync and started it via terminal to see the output of what was happening. When I did so the scripts functioned as I expected when the device connected and killed arecord and aplay. So, as a fix I disabled shairport-sync in sysmtectl and set it to run in /etc/rc.local as a quick fix. After a reboot it functioned as I expected.

This leads me to believe that there is some difference between a program run as apart of systemd and a program that runs when started via /etc/rc.local or the CLI.

Why does this happen? Is this because of different run levels? Some dark magic?

The script that is run when a device connects to shairport-sync is as follows: shairportstart.sh

#!/bin/sh
/usr/bin/sudo /bin/pkill arecord
if [ $(date +%H) -ge "18" -o $(date +%H) -le "7" ]; then
        /usr/bin/amixer set Speaker 40%
else
        /usr/bin/amixer set Speaker 100%
fi
/home/pi/shScripts/shairportfade.sh&

exit 0

Here is the fade script: shairportfade.sh

#!/bin/sh
/usr/bin/amixer set Speaker 30-
for (( i=0; i<30; i++))
do  
    /usr/bin/amixer set Speaker 1+
done
exit 0

The script that is run when a device disconnects to shairport-sync is as follows: shairportend.sh

#!/bin/sh
/usr/bin/amixer set Speaker 70%
/usr/bin/arecord -D plughw:1 -f dat | /usr/bin/aplay -D plughw:1 -f dat&
exit 0

I found the following error in the /var/log/syslog only when shairport-sync was initially run as apart of systemd. When shairport-sync was run from the CLI or /etc/rc.local there were no errors present.

Jan 24 00:38:45 raspberrypi shairport-sync[617]: sudo: no tty present and no askpass program specified

Please note, that the only difference is how shairport-sync is initially started, when devices connect or disconnect shairport-sync continues to run.

  • 1
    That ps ... awk ... grep ... stuff might be replaced by a simpler pkill – thrig Jan 23 '17 at 22:03
  • @thrig originally the line was much simpler but since it didn't work or so I thought I tried using other methods to kill the instance which still didn't work. Killing the process wasn't the issue per se, as it worked but only when run from a user login – Brett Reinhard Jan 23 '17 at 22:50
  • can you show the listing of /home/pi/shScripts/shairportfade.sh ? – Michael D. Jan 24 '17 at 8:05
  • @MichaelD. i have added the fade script as well as the script that is execute when a device disconnects to shairport-sync – Brett Reinhard Jan 24 '17 at 14:32
  • @BrettReinhard what's the problem with running the script from rc.local – Michael D. Jan 24 '17 at 16:25
12

Variations of "Why do things behave differently under systemd?" are a frequently asked question.

Any time something runs from the CLI and not from systemd, there are a some broad categories of possibilities to account for differences.

  1. Different environment variables. systemd documents the environment variables it passes in man systemd.exec in the section Environment variables in spawned processes. If you want to inspect the difference yourself, you can use systemd-run /path/to/binary, it will run your app in a transient scope, as it would be run by a systemd service. You'll get output like: Running as unit: run-u160.service. You can then journalctl -u run-u160.service to review the output. Modify your app to dump out the environment variables it receives and compare the CLI run to the systemd run. If the app isn't conveniently modified, you can just use systemd-run env to see the environment variables that would be passed and review the resulting journal logging for it. If you are trying to start an X11 GUI app, the DISPLAY environment variable needs to be set. In that case, consider using your desktop environment's "autostart" feature instead of systemd.
  2. Resource restrictions. See man systemd.resource-control for configuration values which could restrict resource consumption. Use systemctl show your-unit-unit.service to check the full configuration values affecting the service you attempting to start.
  3. Non-interactive shell. Your bash CLI environment is an interactive login shell. It has sourced files like .bashrc that systemd has not. Besides setting environment variables, these scripts can do any number of other things, such as connecting an SSH agent so that SSH actions don't require a login. See also Difference between Login Shell and Non-Login Shell?
  4. No TTY. Your interactive session is connected to a TTY that some programs like sudo and ssh expect when prompting for passwords. See also sudo: no tty present and no askpass program specified
  5. Relative vs. Absolute Paths. Relative binary work in the shell, but as documented in man systemd.service, the first argument to ExecStart= must be an absolute path to a binary.
  6. Restricted command line syntax. Shell CLIs support many metacharacters, while systemd has a very restricted command line syntax. Depending on your needs, you may be able to replicate Shell syntax with systemd by explicitly running your command through a shell: ExecStart=/bin/bash -c '/my/bash $(syntax) >/goes-here.txt'

It's a feature that system runs your code in a consistent environment with resource controls. This helps with reproducible, stable results in the long run without overwhelming the hardware.

  • Also need to take into account MAC context (SELinux,...), capabilities, namespaces... – Bigon Jan 24 '17 at 8:26
  • 2
    @BrettReinhard Do not call sudo in a shell script better run sudo shairportstart.sh from terminal, since systemd is running the script as root, no need to sudo as root. – Michael D. Jan 24 '17 at 16:24
  • 1
    I solved my issue multiple ways in my attempt to understand what was happening. Ultimately, what I ended up doing was changing my kill command to /usr/bin/echo "mypassword" | /usr/bin/sudo /bin/pkill arecord. Later on today, I will try removing the sudo and echo commands to my kill command and see if that yields the same results. My guess is that will work, as it seems that the error was caused by no password being sent with the sudo command. Thank you for the help in understanding as to why there is a difference between systemd and the CLI – Brett Reinhard Jan 24 '17 at 16:37
  • 1
    One other difference, which may be obvious but which bit me today, is that systemd tries to track the status of a service and won't start it if it thinks it's already active, so it may not even launch an init.d script if it thinks the service is running. By contrast, init.d scripts are typically written to always check and try to start the service as appropriate. – Josh Kelley May 4 '18 at 17:11
  • 1
    @JoshKelley Thanks for the tip. That's not a difference between systemd and the CLI but between systemd and sysVinit init.d scripts. – Mark Stosberg May 4 '18 at 17:59

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.