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.

path_to_executable stands for the path to the actual service executable/script.

Type=forking is used for daemons that make the fork system call. The default value here is 'simple' which doesn't fork the process.

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 se more options then our basic unit had.

PIDFile, stores the PID of your service in a file.

Enviroment, is if you want to set special eniviroment variables like $PATH and such.

ExecStartPre, names executable/script thats needs to be run before the main executable/script is started.

ExecStart, path to your executable/script

ExecStop, 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 /etc/systemd/system/test.service

[Unit]
Description = A systemboot log
After = mediacenter.service
[Service]
Type = single
ExecStart = /home/osmc/scripts/bootlog.sh
[Install]
WantedBy = multi-user.target

sudo chmod 664 /etc/systemd/system/test.service
sudo systemctl daemon-reload
sudo systemctl enable test.service
sudo systemctl start test

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