0

I'm trying to run a bash script at boot time from /etc/rc.local on a headless Raspberry Pi 4 (Raspbian buster lite - Debian based). I've done something similar on a Pi 3 with success so I'm confused about why the Pi 4 would misbehave - or behave differently. The script executed from /etc/rc.local fires but appears to just exit at seemingly random intervals with no indication as to why it's being terminated.

To test it, I dumbed down the script and just stuck the following into a test script called /home/pi/test.sh:

#!/bin/bash
while true
do
        echo 'Still alive'
        sleep 1
done

I then call it from /etc/rc.local just before the exit line:

#!/bin/sh -e
#
# rc.local - executed at the end of each multiuser runlevel
#
# Make sure that the script will "exit 0" on success or any other
# value on error.

openvt -c 1 -f -- /home/pi/test.sh
echo $? >/tmp/exiterr #output exit code to /tmp/exiterr

exit 0

The contents of /tmp/output:

Still alive
Still alive

and /tmp/exiterr shows

0

If I reduce the sleep period, /tmp/output is longer (over 6000 lines without the sleep). Any ideas why the script is exiting shortly after starting?

EDIT I notice the script runs fine from rc.local as well as crontab @reboot if I omit openvt. I have also tried creating a system.d service that calls the full command including openvt.

The .service file looks like this:

[Unit]
Description=Rpi Player
After=network.target

[Service]
ExecStart=/home/pi/testcaller.sh
WorkingDirectory=/home/pi
StandardOutput=inherit
StandardError=inherit
Restart=always

[Install]
WantedBy=multi-user.target

...and the testcaller.sh looks like this:

#!/bin/bash
/bin/openvt -c 1 -f -- /home/pi/test.sh

EDIT added for Inigo: After reboot, the output of sudo systemctl status player.service is:

● player.service - Rpi Player
   Loaded: loaded (/etc/systemd/system/player.service; enabled; vendor preset: enabled)
   Active: inactive (dead) since Sun 2019-12-29 10:02:54 GMT; 34s ago
  Process: 544 ExecStart=/bin/bash -c /bin/openvt -c 1 -f -- /home/pi/test.sh (code=exited, status=0/SUCCESS)
 Main PID: 544 (code=exited, status=0/SUCCESS)

Dec 29 10:02:54 raspberrypi systemd[1]: Started Rpi Player.
Dec 29 10:02:54 raspberrypi systemd[1]: player.service: Succeeded.

The output of sudo ps -aux | grep /home/pi shows that the service is no longer running (as expected per code=exited above). If I start the service manually from the shell using sudo systemctl start player.service, it does the same - it starts then exits. If I run the execstart command from the bash prompt, it runs and behaves as expected:

sudo /bin/bash -c '/bin/openvt -c 1 -f -- /home/pi/test.sh'

The output of journalctl --unit=player.service:

-- Logs begin at Sun 2019-12-29 10:13:18 GMT, end at Sun 2019-12-29 10:16:17 GMT. --
Dec 29 10:13:33 raspberrypi systemd[1]: Started Rpi Player.
Dec 29 10:13:33 raspberrypi systemd[1]: player.service: Succeeded.

Why can I not run this simple openvt command on a Raspberry Pi 4 as a service or cron job?

2
  • I care! FWIW this doesn't appear related to rc.local. I've tried this as a crontab @reboot and get the same results. If I omit openvt, the script launches fine from crontab and rc.local and keeps running. Also, if I create a service using system.d, it fails and exceeds the start-limit-hit. Running the script directly from bash after login works fine
    – wedwo
    Dec 24 '19 at 12:31
  • I think this has evolved into a new question... Why does the script exit when launched by openvt on a Pi 4? It runs fine when launched manually.
    – wedwo
    Dec 25 '19 at 6:43
2

Please note that using /etc/rc.local is deprecated since years. It has limitations due to Compatibility with SysV. We have seen many problems here on this site using it. Following the recommendation of the developers from systemd you should avoid using it. Failing functionallity of rc.local is as expected with upgrading to Raspbian Buster in respect to the last sentence of the Compatibility document:

Note that there are some areas where systemd currently provides a certain amount of compatibility where we expect this compatibility to be removed eventually.

You see, it's time to finally use a systemd Unit as you did. Because your script runs from the command line is should not be a big issue to make it running as a service. You have many options to give it the same environment than on the command line. correct your Unit like this:

[Unit]
Description=Rpi Player
After=network.target

[Service]
User=pi
WorkingDirectory=/home/pi
#Environment=ENV_VAR_NEEDED
#ExecStartPre=/bin/bash -c `/usr/bin/env`
ExecStart=/bin/bash -c '/bin/openvt -c 1 -f -- /home/pi/test.sh'

[Install]
WantedBy=multi-user.target

This gives the script the same login with user pi (I think you use it). It could be that it still does not meet the environment of the command line. Maybe you have to look for environment variables that /bin/openvt needs. You can set them as shown with the commented Environment= option. If you like to see the enviroment of the service at run time just uncomment the #ExecStartPre= line. You will find its output in the journal with:

rpi ~$ journalctl --unit=rpi-player.service

For all options to configure the needed environment look at man systemd.exec.

7
  • Unfortunately it's still not working. For whatever reason, openvt seems to be the common denominator - when it's included, the service does not run, when it's omitted, it runs fine. I'm trying to figure out why openvt is not able to fire the command. I can run the full command (including openvt) manually as root (I am running this as root as openvt requires root I believe). I omitted the User=pi line to ensure it's run as root. Running journalctl --unit=rpi-player.service indicates the service started without issue, but it hasn't run as no output is produced.
    – wedwo
    Dec 27 '19 at 8:06
  • I've moved this to raspberrypi.stackexchange.com/questions/106636/… as I believe it more accurately targets the issue which appears to be the openvt command on a Pi 4.
    – wedwo
    Dec 27 '19 at 8:35
  • @wedwo Do you want to show output from openvt? It isn't a silent service? If so, what output do you want? Text or graphical? You forgot to mention it in your question.
    – Ingo
    Dec 27 '19 at 10:54
  • A simple echo to the screen connected to the Raspberry Pi HDMI (tty01) will do fine.
    – wedwo
    Dec 27 '19 at 17:14
  • @wedwo What output does openvt use by default? Does it write to stdout? What does it output on the command line? In a comment you wrote: "the service does not run, when it's omitted, it runs fine.". What does it mean? can you please edit your question and add the output of this command to it: systemctl status rpi-player.service. Asking the same question a second time was not a good idea. Instead you should modify this question.
    – Ingo
    Dec 27 '19 at 18:52
0

Coming from the SysV init camp one could expect the rc.local script to be run as root at the end of the start up process just before it goes multi-user...

That is why any process that is started by it must EITHER: finish up quickly so that the boot process can continue; OR: spawn itself as a daemon like process (in the background with a & at the end of the line in rc.local that invokes it) that forks a copy that can continue to run while the originating parent terminates - again so that the boot process can continue.

I may be wide of the mark - but it does not look like you are invoking the test script in the back ground here...

9
  • Your expectation that the rc.local script to be run at the end of the start up process just before it goes multi-user is wrong. And no, a "blocked" rc.local script does not affect starting other services. There is no synchron running SysV init running anymore. All is only emulated by systemd and that is working asynchron, starting all services at the same time if no dependencies defined.
    – Ingo
    Dec 26 '19 at 2:13
  • I SAID I was referring to the SysV init case - and that is what I use - admittedly it seems to be a minority position nowadays but it is still possible even in Debian/Raspbian Buster...
    – SlySven
    Dec 28 '19 at 18:21
  • @Ingo The page about rc.local seems to state the opposite: "the script will not end and the Pi will not boot", see here: raspberrypi.org/documentation/linux/usage/rc-local.md The page even contains an explicit warning that long running programs in rc.local should fork.
    – Daniel K.
    Aug 12 '20 at 9:51
  • @DanielK. Please read the page you have linked carefully. They also know that there is no SysV anymore and /etc/rc.local isn't working unfailing, quote: "NOTE: on Jessie, Stretch and Buster (which use systemd), rc.local has drawbacks: not all programs will run reliably, because not all services may be available when rc.local runs."". Also take note of Compatibility with SysV. We have seen many problems here on this site using it.
    – Ingo
    Aug 12 '20 at 16:33
  • @Ingo I think we are talking about different points here. You commented that " a blocked rc.local script does not affect starting other services." when using systemd. I wrote that this assertion is not supported by the page I linked. The page I linked indicates that rc.local (even when operated by systemd) should not block otherwise "the script will not end and the Pi will not boot". Thanks.
    – Daniel K.
    Aug 13 '20 at 7:31
0

OK, it seems the answer was in the parameters for the openvt command. For whatever reason, the original parameters of -c 1 -f -- are causing the script to exit early on the Pi 4 while -s -w is working:

old:

openvt -c 1 -f -- /home/pi/test.sh

According to the manual here: http://man7.org/linux/man-pages/man1/openvt.1.html, the options are as follows:

-c, --console=VTNUMBER
              Use the given VT number and not the first available. Note you
              must have write access to the supplied VT for this to work;
-f, --force
              Force opening a VT without checking whether it is already in
              use;
--     end of options to openvt. If openvt is compiled with a getopt_long() and you wish to set
       options to the command to be run, then you must supply the end of
       options -- flag before the command.

new:

openvt -s -w /path/to/install_script

The switches for the new command are:

-s, --switch
              Switch to the new VT when starting the command. The VT of the
              new command will be made the new current VT;
-w, --wait
              wait for command to complete. If -w and -s are used together
              then openvt will switch back to the controlling terminal when
              the command completes;

I suspect -w is the key and I suspect the first command will work with -w appended before --. I guess -- is not required in the binary that comes with Raspbian.

I have tested this in rc.local and will test it as a service next as well as try the original command with -w appended and update my post.

EDIT So it runs fine in rc.local with

openvt -c 1 -f -- /home/pi/test.sh

But will only work with:

openvt -w -s /home/pi/test.sh

...when running as a service.

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.