site  contact  subhomenews

Experimenting with Busybox Runit

February 14, 2018 — BarryK

Refer to these posts yesterday:

I have been wondering more about why I find daemontools and derivatives to be unsatisfactory. I think that the developers are system adminstrators, and have a particular mindset. They are developing for systems that have fairly fixed software and interfaces, not for generic desktop systems.

Also, I have struggled with the documentation. Regarding Runit, one person commented:

"Runits documentation is so bad that I had to learn it by experimentation, even though I know its ancestor daemontools inside and out."

I was also hampered by the documentation of the Busybox implementation of Runit. "sv --help" showed the commandline options, which lead me to believe it was only a subset of the full 'sv' utility. Options such as "check" and "start" were missing. Until I looked at the Busybox 'sv.c' source, and saw that those options are supported.

Anyway, my simple requirement for some services to be dependent on a network up. It was not explained in the official docs, found some info after much hunting...

I created a service named "network", by creating a folder '/etc/sv/network'.
Inside, created two scripts, 'run' and 'check'. Contents of 'run':

#sleep forever...
sleep 9999d

Contents of 'check':

exec 2>&1
#exit with 0 if network is up (exclude 'lo')...
UP_IFS="$(grep -l '^0$' /sys/class/net/[^l]*/dormant | cut -f 5 -d '/')"
#...ex: /sys/class/net/eth0/dormant, cut 'eth0'
if [ "$UP_IFS" ];then
 exit 0
 exit 1

Now, if another service specifies "network" as a dependency, the 'network/check' script will be run, and if returns "0" then yep it is running.

So, I created '/etc/sv/test_net', with script 'run':

exec 2>&1
sv -w10 check network
if [ $? -eq 0 ];then
 echo 'up' >> /tmp/zz-net
 sleep 99999d
 echo 'down' >> /tmp/zz-net
 exit 1

...this is just a dummy script. A real service might be to start a daemon instead of that "sleep 99999d".

The key line in that script is "sv -w10 check network". This will run the 'network/check' script. If 'check' returns non-0, the above 'run' will exit with non-0. The Runit supervising utility 'runsvdir' will wait one second, then try again, that is, rerun 'test_net/run', and will keep at it until the network is up.

This is the official way to do it, and at this stage I was thinking "Oh my goodness gracious me, surely not!" (or words to that effect). But yep, that's it, a polling loop. Furthermore, if several services have the same "network" dependency, they will all independently be calling 'network/check'.

Then I recalled something that I had read in the 's6' docs, at

"Neither System V init, daemontools, runit or perp provides any hooks to wait for a service to go up or down. runit provides a waiting mechanism, but it's based on polling, and the ./check script has to be manually written for every service."

It is a pity that I am not happy with Runit, as the Busybox implementation is tiny. I reported yesterday that I recompiled Busybox statically, adding the Runit applets and three extra network applets. The size of the stripped binary grew from 933KB to only 965KB.

Tags: easy, quirky