Embedded linux application start script works better from command line - embedded-linux

I'm running embedded linux on an Altera FPGA. It uses SystemD to run startup, and I have a script in the "multi-user.target.wants" section that runs my application.
When it runs from startup my code runs slower than when I run the identical script from an ssh shell.
I have checked that paths are the same, that permissions are correct on the scripts, that full paths are used in the scripts. Using 'top' I can see that priorities are set the same for the various threads started, yet somehow performance is completely different between the two ways of starting.
The script in full is:
#!/bin/sh
sleep 5s
mount /dev/mmcblk0p5 /home/root/linux
cd /home/root/linux/mem_driver
./memdev_load
cd /home/root/linux/gpio_driver
insmod ./gpiodev.ko
mknod /dev/gpiodev c 249 0
sleep 5s
cd /home/root/src/control
mysqld_safe &
up=0
while [ $up -ne 2 ]
do
up=$(pgrep mysql | wc -l);
echo $up
done
sleep 3s
cd /home/root/studio_web/myapp
npm start &
sleep 1s
cd /home/root/src/control
#sleep 1s
./control > /home/root/linux/output.log
various sleep commands have been inserted to try and make sure things start up in the right order.
Any help in diagnosing why this behaves differently would be greatly appreciated.

Is that the only shell script you are using? or do you have a systemd service file that executes that single shell script?
Using sleep is ineffective here. You should separate them into separate shell scripts and then use systemd to ensure that the shell scripts are run in order.
For example, we want to mount the directory first, because if this fails then nothing following will be successful. So we create a systemd mount service:
# home-root-linux.mount
[Unit]
Description=Mount /home/root/linux
Before=gpiodev.service
[Mount]
What=/dev/mmcblk0p5
Where=/home/root/linux
Options=defaults
[Install]
WantedBy=multi-user.target
Then we can create another systemd service which depends on the mount above before executing the three parts of the shell script which were previously separated by sleep to ensure that they were run in order.
# gpiodev.service
[Unit]
Description=Handle gpiodev kernel module
After=home-root-linux.mount
Before=mysqlsafe.service
[Service]
Type=oneshot
ExecStartPre=/home/root/linux/mem_driver/memdev_load
ExecStart=/sbin/insmod gpiodev.ko; /bin/mknod /dev/gpiodev c 249 0
WorkingDirectory=/home/root/linux/gpio_driver
RemainAfterExit=yes
StandardOutput=journal
[Install]
WantedBy=multi-user.target
Second part of the systemd service (following the sleep). We have a separate shellscript which is placed in /sbin/ in this example as it contains a while loop so it would be best to separate this:
# mysqlsafe.service
[Unit]
Description=MySQL safe
After=gpiodev.service
Before=npmoutput.service
[Service]
Type=oneshot
ExecStart=/sbin/mysqlsafe.sh
WorkingDirectory=/home/root/src/control
RemainAfterExit=yes
StandardOutput=journal
[Install]
WantedBy=multi-user.target
Second part of the shell script which is executed in the systemd service above (separated to a separate file due to the complexity):
# /sbin/mysqlsafe.sh
#!/bin/sh
mysqld_safe &
up=0
while [ $up -ne 2 ]
do
up=$(pgrep mysql | wc -l);
echo $up
done
Third part of the systemd service (the third section of the original shell script which was separated by sleep):
# mpmoutput.service
[Unit]
Description=npm and output to log
After=mysqlsafe.service
[Service]
Type=oneshot
ExecStartPre=/usr/bin/npm &
ExecStart=/home/root/src/control > /home/root/linux/output.log
WorkingDirectory=/home/root/studio_web/myapp
RemainAfterExit=yes
StandardOutput=journal
[Install]
WantedBy=multi-user.target
The idea behind this approach is that systemd recognises the importance of each service and the reliance upon the following service i.e. if one service fails the following services in queue will not execute. You can then check this using systemctl and see logging in journalctl.
Just a quick copy, paste and edit. Could contain errors as it was not tested or checked.
More reading can be found here regarding systemd service files: https://www.freedesktop.org/software/systemd/man/systemd.service.html

Related

Bash script works in while but not in until?

This is very simple. I run this as a systemctl.
#!/bin/bash
until ping -c1 $1 www.google.com &>/dev/null
do protonvpn c -f
done
my systemctl is:
### BEGIN INIT INFO
# Provides: protonvpn
# Required-Start: $all
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop:
# Short-Description: autostartvpn
### END INIT INFO
[Unit]
After=remote-fs.target
[Service]
ExecStart=/dir/startupscript
[Install]
WantedBy=default.target
It does not work (the upper script) when i execute it as systemctl, and it stops working generally after reboot for unknown reason.
I want to run this command protonvpn c -f on boot as soon as i get internet connection and i want it to loop until a connection is found (then kill-switch controls the app, and all works indefinitely).
Can you help me make it work?
If you want to run a service after having an active network connection, you can use this on your Systemd service file:
After=network-online.target
I think that would kill two birds with one stone, because that behaviour implies that you no longer should need to add any kind of check in your script to make sure it runs after network connection is established.
#hads0m has the right idea, but the loop pattern is also wrong.
until command1
do
command2
done
does not do what you think. If command1 succeeds the first time then it never runs command2. If command1 does not succeed it'll run command2, and if that command runs in the background or exits it'll run command1 again. What you want instead is
until command1
do
sleep 1
done
command2
to not run a busy loop and to only run command2 when the prerequisite is met.

ExecStartPost script an infinite loop script - Is it possible to do?

I am tweaking snmpd systemd service and I want to execute a script in ExecStartPost. This will be an infinite loop script.
This script is an implementation of agentx ..
I have tried running in a normal manner with and without & , but after sometime the systemd service is timing out..
it is timing out expecting a exit status from the script is what is believe.
Is there any way to run the script in background without the systemd snmp service timing out ?
[Unit]
Description=Simple Network Management Protocol (SNMP) Daemon.
After=syslog.target network.target
[Service]
Type=notify
Environment=OPTIONS="-LS0-6d"
EnvironmentFile=-/etc/sysconfig/snmpd
ExecStart=/usr/sbin/snmpd $OPTIONS -f
ExecStartPost=/usr/bin/python /usr/local/bin/pyagent.py
ExecReload=/bin/kill -HUP $MAINPID
[Install]
WantedBy=multi-user.target
From reading the documentation, I believe you want to keep your & but add - prefix to skip result checking:
ExecStartPost=-/usr/bin/python /usr/local/bin/pyagent.py &

Custom systemd service that runs shell script at startup is inactive (dead)

I made a systemd service that should run a script on startup. The script contains a couple echoes for power saving and a command to disable my bluetooth. It has executable rights.
When I start the service it has an inactive (dead) status.
Here you can see my systemd service and the script that i am trying to run.
I already tried a crontab : #reboot ( sleep 90 ; sh /home/maxim/bin/power.sh )
Still didn't have the required results.
[Unit]
Description=Example systemd service.
[Service]
Type=simple
ExecStart=/usr/bin/sudo /bin/sh /home/maxim/bin/power.sh
[Install]
WantedBy=default.target
The power.sh script:
#!/bin/bash
echo 'min_power' > '/sys/class/scsi_host/host2
/link_power_management_policy'
echo 'min_power' > '/sys/class/scsi_host/host3
/link_power_management_policy'
echo 'min_power' > '/sys/class/scsi_host/host0
/link_power_management_policy'
echo 'min_power' > '/sys/class/scsi_host/host1
/link_power_management_policy'
echo '1500' > '/proc/sys/vm/dirty_writeback_centisecs'
rfkill block bluetooth

How to run multiple command systemd

i want to multiple command in myapp.service file in systemd
[Unit]
Description=to serve myapp
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/myapp
ExecStart=/home/ubuntu/.local/bin/pserve production.ini http_port=5000
ExecStart=/home/ubuntu/.local/bin/pserve production.ini http_port=5001
Restart=always
[Install]
WantedBy=multi-user.target
it throws error saying invalid argument.
i want to run two commands
pserve production.ini http_port=5000
pserve production.ini http_port=5001
How do i do that??
You can start multiple background processes from one systemd unit, but systemd will not be able to track them for you and do all the nice things that it does to support a daemon, such as send signals to it on various system events or auto-restart it when needed.
If you must have it as a single unit, then you can do one of the following (in my order of preference):
make the two servers separate units (note you may be able to use the same config file for both, so they are two 'instances' of the same service - which makes sense, they run the same server). You will have two entries in the list of running services when you run 'systemctl'.
make that unit a one-shot (runs a program that exits and is not monitored and restarted). Make the one-shot command start both servers in background, e.g.,
sh -c " { pserve production.ini http_port=5000 & pserve production.ini http_port=5001 & } </dev/null >/dev/null >&1"
make a script that launches both daemons and watches for them, restarting them if needed and kills them when it is killed itself. Then you make that script the 'daemon' that systemd runs. Not really worth it, IMO - because you're doing much of the work that systemd itself is best suited to do. Of course you can spin a new copy of systemd that is configured to run just those two servers (and make that systemd as your 'one-service-for-two-commands' unit), but that seems an overkill.

systemd timer to start .sh script daily at 2 different hours

I have a bourne shell script (at my NAS) that handles the ffmpeg recording of all my ipcams. For switching the record time (etc) of some cams, that sh script should be restarted daily at 2 different hours (07:00am and 10:00pm), which is configured in the bash script and works well.
To start the sh script, I make use of systemd with the following .service file:
[Unit]
Description=record ipcams
After=tmp.mount network.target
Requires=network.target
RequiresMountsFor=/media/USB2
[Service]
Type=forking
PIDFile=/var/run/cams_record.pid
ExecStart=/bin/bash -c '/media/USB2/movie/cams/cams_record.sh'
TimeoutStopSec=1
Restart=always
[Install]
WantedBy=multi-user.target
So far so good. Now what I actually want, is to restart that script file daily at 07:00am and 10:00pm (or restart the previous mentioned .service at those two times) thus I thought to make use of a systemd timer. I created such a timer for 07:00 am (with the option: OnCalender=07:00)
Question is: having a (permanently running) service, how do I restart that service (and thus the script file) at 07:00am and 22:00pm. I can of course make use of 2 systemd timers (1 for 07:00am and 1 for 10:00pm), but is there a possibility to combine these; i.e. using 1 systemd timer for both times.
With a templates timers, you can do something like this
cat test#.timer
[Unit]
Description=test
[Timer]
OnCalendar=%i:00
Unit=test.service
[Install]
WantedBy=timers.target
Then :
systemctl daemon-reload
and
systemctl start test#07.service
systemctl start test#22.service
Source : https://fedoramagazine.org/systemd-template-unit-files/ and https://jason.the-graham.com/2013/03/06/how-to-use-systemd-timers/
You can use several OnCalendar in one timer, see documentation https://www.freedesktop.org/software/systemd/man/systemd.timer.html#OnCalendar=
[Unit]
Description=test
[Timer]
OnCalendar=07:00
OnCalendar=10:00
Unit=test.service
[Install]
WantedBy=timers.target

Resources