Difference between systemd and terminal starting program
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.
-
Different environment variables.
systemd
documents the environment variables it passes inman systemd.exec
in the section Environment variables in spawned processes. If you want to inspect the difference yourself, you can usesystemd-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 thenjournalctl -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 usesystemd-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, theDISPLAY
environment variable needs to be set. In that case, consider using your desktop environment's "autostart" feature instead ofsystemd
. -
Resource restrictions. See
man systemd.resource-control
for configuration values which could restrict resource consumption. Usesystemctl show your-unit-unit.service
to check the full configuration values affecting the service you attempting to start. -
Non-interactive shell. Your
bash
CLI environment is an interactive login shell. It has sourced files like.bashrc
thatsystemd
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? -
No TTY. Your interactive session is connected to a TTY that some programs like
sudo
andssh
expect when prompting for passwords. See also sudo: no tty present and no askpass program specified -
Relative vs. Absolute Paths. Relative binary work in the shell, but as documented in
man systemd.service
, the first argument toExecStart=
must be an absolute path to a binary. -
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 withsystemd
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.
Related videos on Youtube
digglemister
Updated on September 18, 2022Comments
-
digglemister over 1 year
I'm trying to run a while loop that contains an animation. What I'd like to happen is for the while loop to pause, let the animation finish, then resume.
This is not my actual code, but it gets to the issue, I believe:
var counter = 0; while (counter < 2) { $(".one").animate({"left":"+=50px"}, "slow", function() { counter++; }); };
This crashes my browser because it doesn't wait for the animation to finish (and consequently it doesn't wait for the counter to increase) before it continues through the while loop. Thanks in advance!
https://jsfiddle.net/uhmctey6/
EDIT
Thanks everyone for explaining why this is impossible. I'm still unsure how to do what I need, however, and since I didn't use my actual code for the example, I'm not sure if the suggested solutions could help.
Here is what I'm actually trying to do: I'm making a turing machine with a reader and a array of cells that it reads. Upon running this function, I'd like to search through a list of turing code lines to see if one matches the readers current state and the content of the current cell that the reader is scanning. If there's a match, I'd like for the reader to make a series of changes specified by the relevant turing code line, then visually move over to the next cell, and only after this animation has completed start the process over again by searching through the list of turing code lines to see if there is a match for the reader's new state, etc.
I understand that this can't be achieved as I have it, using a while loop, but is there a way to do something like this another way? Thanks a lot!
var run_program = function() { while (true) { for (var j=0; j< program.length; j++) { //loops through the different lines of turingcode if (reader.state === program[j].state && reader.scanning === program[j].scanning) { //if there is a line of turingcode for the readers current state and scanning values. cellArray[reader.location].content = program[j].print; //change the content of the current cell to the new value reader.location += 1; //increase the value of the reader's location $(".reader").animate({"left":"+=50px"}, "slow"); //move the div to the right so it appears to be under the next cell reader.scanning = cellArray[reader.location].content; //update the readers scanning value to be the value of the new cell reader.state = program[j].next_state; // update the state of the reader to that specified by the line of turingcode break; } else if (j === $scope.program.length-1) { //if there is no line of turingcode for the readers current state and scanning values, and j has looped through the entire list of turingcode lines return; //halt the function } } } }
-
nils over 8 yearsWhat is it exactly that you are trying to do? Are you trying to update the counter value with every animation-step? Or do you want to run the same animation multiple times?
-
Jonathan Lonowski over 8 yearsNo, it's not. The evaluation of JavaScript is bound to a single thread. The
while
loop will keep the thread busy indefinitely, preventing any other events from executing, including the.animate()
callback. -
digglemister over 8 yearsThis is not my actual code, it's just a simplified example. But I suppose in this example, what I'd like to happen is for the animation to run twice, increasing the counter after each time the animation is completed.
-
thrig over 7 yearsThat
ps ... awk ... grep ...
stuff might be replaced by a simplerpkill
-
Brett Reinhard over 7 years@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
-
Michael D. over 7 yearscan you show the listing of
/home/pi/shScripts/shairportfade.sh
? -
Brett Reinhard over 7 years@MichaelD. i have added the fade script as well as the script that is execute when a device disconnects to shairport-sync
-
Michael D. over 7 years@BrettReinhard what's the problem with running the script from
rc.local
-
Brett Reinhard over 7 years@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 enableshairport-sync
by means ofsudo 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. -
ajeh about 6 yearsIn 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.
-
-
Bigon over 7 yearsAlso need to take into account MAC context (SELinux,...), capabilities, namespaces...
-
Brett Reinhard over 7 yearsI 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 asshairport-sync
sudo rules have not been loaded. Given that you suggested that system runs in a consistent environment andshairport-sync
was run in that environment, it will require a password for usingsudo
. Where if it were run in/etc/rc.local
sudoers would be loaded and not need the password -
Mark Stosberg over 7 yearssystemd system units run as root by default, so
sudo
would not be needed. -
Brett Reinhard over 7 yearsgiven that
shairport-sync
is a system unit. Say for exampleshairport-sync
were to run some script nameddeviceconnectionhandler
which would be in control of running the scripts that are executed when a device connects or disconnects. Would the scripts run bydeviceconnectionhandler
also have the root privilege and not need sudo? -
Mark Stosberg over 7 yearsCorrect. Any sub process would inherit the ownership and privileges of the parent.
-
Brett Reinhard over 7 yearsSo 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 usessudo
will it require a password input? Or is this error more specifically due tono tty present
? Thank you for your patience in answering my questions. -
Michael D. over 7 years@BrettReinhard Do not call
sudo
in a shell script better runsudo shairportstart.sh
from terminal, since systemd is running the script as root, no need to sudo as root. -
Mark Stosberg over 7 yearsNormally using
sudo
with theroot
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. Bothsudo
andssh
have pseudo-tty options. -
Brett Reinhard over 7 yearsI 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 thesudo
andecho
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 thesudo
command. Thank you for the help in understanding as to why there is a difference betweensystemd
and the CLI -
Josh Kelley about 6 yearsOne 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.
-
Mark Stosberg about 6 years@JoshKelley Thanks for the tip. That's not a difference between systemd and the CLI but between systemd and sysVinit init.d scripts.