Skip to content

systemd

Often it is desirable to have your embedded Linux computer run a script or application on startup. Examples include capturing camera video data on a quad when you turn power on to the onboard computer, setting up and running your ROS nodes on a fixed-wing, or setting up the ROS Whirlybird network on a Raspberry Pi.

There are a few ways of running startup scripts which makes the waters more muddy. This is mainly because of historical reasons between SysV Init, Upstart, and systemd. We will use systemd to run userland services.

Historical Background

UNIX System V ("System Five") was an early commercial OS developed at AT&T in 1983. They introduces a new style of system startup configuration that we now call SysV-style init. Nowadays, Linux still has support for SysV init for backward compatibility even though it was technically replaced in Ubuntu 6.10 by Upstart. Scripts for SysVinit are found in /etc/init.d and are run using those executable scripts directly (e.g., sudo /etc/init.d/apache2 start).

Upstart was the successor to SysVinit and was the default system configuration from Ubuntu 6.10 to 14.10. Upstart was made just to replace SysVinit -- i.e., it did nothing else other than manage processes that you wanted to be able to start and stop at boot or during the system uptime. Upstart introduced non-executable *.conf files found in /etc/init. These configuration files describe services that can be called with the start, stop, and status commands (e.g., sudo start apache2).

While Upstart was the default, a new command showed up on the block that aimed at providing inter-operability to Linux system administrators. This command is the service command. It's goal was to provide a common interface to both Upstart and SysVinit configurations and services. It runs as sudo service apache2 start and tells you whether it is using the /etc/init.d/ script or the /etc/init Upstart conf file.

With the release of Ubuntu 15.04, Ubuntu switched from upstart to systemd as the default configuration manager. systemd is a powerful tool that has caused a lot of debate in the Linux community. Not only does it deal with the starting and stopping of system services, but it takes care of mounting, networking, process management, login, etc. In short, it breaks the UNIX idea of doing one thing and doing it well. But, it does run services cleanly and is rather flexible. Systemd service files (called units) are found in multiple places, most importantly in /etc/systemd/system and are managed with the systemctl command (e.g., sudo systemctl start apache2). Also, here is a discussion on systemd vs upstart.

Why not use /etc/rc.local ?

This script is available and will run Bash scripts during boot, but processes are owned by root and it's really part of the old SysVinit system and isn't that clean.

Why not use cron?

I don't know. It will work and it can be owned by the appropriate user and set with @reboot, but it runs in a /bin/sh (shell) environment so you have to remember to call /bin/bash to get into the right environment. It just doesn't feel right.

systemd systemctl Commands

$ sudo systemctl start myrobot   # the .service extension is optional
$ sudo systemctl stop myrobot
$ sudo systemctl enable myrobot  # installs the service to be run at boot -- requires an [Install] stanza
$ sudo systemctl disable myrobot

Read more about managing your system with systemctl here.

Example systemctl Unit File

Here is the service unit file for the ROS Whirlybird setup used in ECEn 483

# /etc/systemd/system/whirlybird.service
[Unit]
Description="Whirlybird ROS Serial Bridge"
After=network-online.target

[Service]
Type=simple
User=louie
Group=louie
ExecStart=/home/louie/ros_start.sh

[Install]
WantedBy=default.target

And here is the ros_start.sh script that is run on startup as the louie user

#!/usr/bin/env bash
# Setup the ROS environment for this Whirlybird and start the serial node
#
# This file should be in ~/ros_start.sh and be marked as executable (chmod +x ros_start.sh)

export ROS_MASTER_URI=http://localhost:11311
export ROS_IP=`hostname -I`

source ~/catkin_ws/devel/setup.bash
roslaunch whirlybird_serial serial.launch

Before rebooting, you can test the service with

$ sudo systemctl start whirlybird

And you can see if it is running or failed with

$ sudo systemctl status whirlybird

or you can check the log output with

$ sudo journalctl -u whirlybird

Make sure to "install" the service with

$ sudo systemctl enable whirlybird

Reboot and it should start automagically!

More information about writing unit files can be found:

Gotchas

Sourcing ~/.bashrc Doesn't Work

In your equivalent ros_start.sh entry point, you may notice that if you try to source your ~/.bashrc it does not seem to work (i.e., your ROS network setup, aliases, etc). This is because it is being sourced from a non-interactive session and at the top of the ~/.bashrc you will see code that makes the script bail when that's the case. A solution is to use a secondary script like ~/.bash_profile to put all of your specific changes in and source that script in ~/.bashrc for normal use and in the ros_setup.sh for robot use. In my opinion, this is the proper way to do that anyways because then you can source control or share the ~/.bash_profile with other computers/robots.

For the alias problem it's because expanding aliases is not the default option in non-interactive mode. This can be changed by adding that option before you source a script:

$ shopt -s expand_aliases
$ source ~/.bash_profile

systemd Version 230 Breaks screen and tmux

Ubuntu 16.04 ships with systemd version 229 (systemd --version). Apparently in version 230, screen and tmux are broken by default which seems silly. Likely, Ubuntu 18.04 will be confusing for users (and us) if systemd keeps this as the default.

Read here for a long discussion of systemd and links about this issue and here for how to change this default behavior.