Difference between systemd and terminal starting program

648

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.

Share:
648

Related videos on Youtube

digglemister
Author by

digglemister

Updated on September 18, 2022

Comments

  • digglemister
    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
      nils over 8 years
      What 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
      Jonathan Lonowski over 8 years
      No, 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
      digglemister over 8 years
      This 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
      thrig over 7 years
      That ps ... awk ... grep ... stuff might be replaced by a simpler pkill
    • Brett Reinhard
      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.
      Michael D. over 7 years
      can you show the listing of /home/pi/shScripts/shairportfade.sh ?
    • Brett Reinhard
      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.
      Michael D. over 7 years
      @BrettReinhard what's the problem with running the script from rc.local
    • Brett Reinhard
      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 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.
    • ajeh
      ajeh about 6 years
      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.
  • Bigon
    Bigon over 7 years
    Also need to take into account MAC context (SELinux,...), capabilities, namespaces...
  • Brett Reinhard
    Brett Reinhard over 7 years
    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
  • Mark Stosberg
    Mark Stosberg over 7 years
    systemd system units run as root by default, so sudo would not be needed.
  • Brett Reinhard
    Brett Reinhard over 7 years
    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?
  • Mark Stosberg
    Mark Stosberg over 7 years
    Correct. Any sub process would inherit the ownership and privileges of the parent.
  • Brett Reinhard
    Brett Reinhard over 7 years
    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.
  • Michael D.
    Michael D. over 7 years
    @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.
  • Mark Stosberg
    Mark Stosberg over 7 years
    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.
  • Brett Reinhard
    Brett Reinhard over 7 years
    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
  • Josh Kelley
    Josh Kelley about 6 years
    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.
  • Mark Stosberg
    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.