15

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 08: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
  • @MichaelD. I am unsure if that is a proper way to handle such programs as I am still pretty new to linux and unsure of proper standards. Regardless, the way that shairport-sync is implemented most users enable shairport-sync by means of sudo systemctl enable shairport-sync. Since, I also raised an issue on the github page I felt it was my due diligence to find a fix for the issue with how it is installed by most users. – Brett Reinhard Jan 24 '17 at 16:42
  • In my simplistic view of this world, if anything cannot kill a process, then it does not have rights to do so. As in you need sudo to kill someone else's process. – ajeh Apr 20 '18 at 14:14

1 Answers1

30

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 08:26
  • I believe the error that I seemed to encountered is somehow related to when /etc/sudoers gets loaded to the system. It is my understanding that when systemd starts a given program, such as shairport-sync sudo rules have not been loaded. Given that you suggested that system runs in a consistent environment and shairport-sync was run in that environment, it will require a password for using sudo. Where if it were run in /etc/rc.local sudoers would be loaded and not need the password – Brett Reinhard Jan 24 '17 at 14:39
  • systemd system units run as root by default, so sudo would not be needed. – Mark Stosberg Jan 24 '17 at 15:07
  • given that shairport-sync is a system unit. Say for example shairport-sync were to run some script named deviceconnectionhandler which would be in control of running the scripts that are executed when a device connects or disconnects. Would the scripts run by deviceconnectionhandler also have the root privilege and not need sudo? – Brett Reinhard Jan 24 '17 at 15:39
  • Correct. Any sub process would inherit the ownership and privileges of the parent. – Mark Stosberg Jan 24 '17 at 15:56
  • So the error that is happening is : sudo: no tty present and no askpass program specified. Which to me begs the question when a script run as root uses sudo will it require a password input? Or is this error more specifically due to no tty present? Thank you for your patience in answering my questions. – Brett Reinhard Jan 24 '17 at 16:14
  • 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
  • Normally using sudo with the root user doesn't prompt for a password, but something is clearly attempting to use a TTY and there is no TTY in the systemd context. Figure out what's trying to use a TTY and make it stop, or see if there's an option force a pseudo-tty allocation that you can script passing something to. Both sudo and ssh have pseudo-tty options. – Mark Stosberg Jan 24 '17 at 16:26
  • 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 04 '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 04 '18 at 17:59