Running scripts on startup and shutdown
Overview
As you come to customise OSMC and tweak it to your liking, you may start writing your own scripts or installing additional software. You may wish to run a script or start a program when OSMC starts, and run a script just before OSMC shuts down.
This article expects you to be familiar with accessing the command line in OSMC. If you’re not sure how to do this, you can learn more here.
Running a script on startup
The rc.local approach
Most Linux distributions have a file called rc.local
. This is a shell script that is run when the system is started up, and can be used to run scripts or programs.
There are some reasons when a quick addition to /etc/rc.local
is appropriate:
- When you want to run a command quickly
- When the command executes quickly and does not wait in the background.
There are also some disadvantages to this approach however:
- Not appropriate for services. Services are meant to run in the background. Adding something to
rc.local
will halt the boot process until the tasks finish executing - No guarantee of process survival. If you try and run a service via
rc.local
and it crashes, nothing will attempt to respawn the process and keep it alive.
When using the rc.local
approach you should always ensure:
- You use the full path to any scripts or executables
- You set the execute bit (chmod +x) on any scripts you wish to run
Note: applications are run as the root user when they are called from rc.local
. We recommend you use ‘su osmc -c /path/to/your/program’ to run the application as the default OSMC user.
The service approach
A better approach is to use OSMC’s init system, called systemd and let it run startup scripts and services for you. Documentation on how to use systemd can be found on the Internet, so the examples given here will be brief and are meant to be an overview.
Here is a raw breakdown of how a unit is build. We will try to explain what each line does then later show some examples with more options.
[Unit]
Description=service_description
After=network.target
[Service]
ExecStart=path_to_executable
Type=forking
[Install]
WantedBy=default.target
service_description is an informative description that is displayed in journal log files and in the output of the systemctl status command.
After setting ensures that the service is started only after the network is running. Add a space-separated list of other relevant services or targets.
Type=forking is used for daemons that make the fork system call. If omitted, will default to Type=simple, which doesn’t fork the process.
ExecStart, complete path to your executable/script
WantedBy states the target or targets that the service should be started under. Think of these targets as of a replacement of the older concept of runlevels.
These are the basics of units, now to a a few real world examples, like Postfix and Minecraft.
Postfix here:
[Unit]
Description=Postfix Mail Transport Agent
After=syslog.target network.target
Conflicts=sendmail.service exim.service
[Service]
Type=forking
PIDFile=/var/spool/postfix/pid/master.pid
EnvironmentFile =-/etc/sysconfig/network
ExecStartPre=-/usr/libexec/postfix/aliasesdb
ExecStartPre=-/usr/libexec/postfix/chroot-update
ExecStart=/usr/sbin/postfix start
ExecStop=/usr/sbin/postfix stop
[Install]
WantedBy=multi-user.target
Here you see more options then our basic unit had.
Conflicts, list other services that conflict with the current one.
PIDFile, stores the PID of your service in a file.
EnvironmentFile, is used when you got many environment variables that you want set for the service. Or use Environment, if you want to set a few environment variables like $PATH and such.
ExecStartPre, names executable/script that needs to be run before the main executable/script is started.
ExecStop, complete path to executable/script to run when service is stopped
And here is one that I wrote myself for my minecraftserver
[Unit]
Description = Minecraftserver
After = remote-fs.target network-online.target mediacenter.service
[Service]
Type=oneshot
RemainAfterExit=yes
User=osmc
ExecStart = /opt/scripts/minecraftstarter.sh
ExecStop = /opt/scripts/minecraftstopper.sh
TimeoutStopSec=20
[Install]
WantedBy = multi-user.target
As you see there is a few more options under service, but it’s built the same way so
for more information and a deeper understanding check out this man pages:
http://0pointer.de/public/systemd-man/systemd.unit.html
http://0pointer.de/public/systemd-man/systemd.service.html
Now we are gonna make our own service step by step. First we need the script we wanna execute on every bootup, in our case it’s a simple script that writes down in a log the time the device was started:
cd /home/osmc
mkdir scripts
cd scripts
touch bootlog.log
nano bootlog.sh
chmod +x bootlog.sh
#!/bin/bash
now=$(date +"%Y %b %d %H:%M:%S")
echo ”Booted: $now” >> /home/osmc/scripts/bootlog.log
exit
sudo nano /lib/systemd/system/test.service
[Unit]
Description = A systemboot log
After = mediacenter.service
[Service]
Type = simple
ExecStart = /home/osmc/scripts/bootlog.sh
[Install]
WantedBy = multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable test.service
sudo systemctl start test.service
WARNING
Always run the systemctl daemon-reload command after creating new unit files or modifying existing unit files.
Waiting for a network connection
Running scripts on shutdown
TBC