The officially official Devuan Forum!

You are not logged in.

#1 2018-05-19 16:12:25

Geoff 42
Member
Registered: 2016-12-15
Posts: 462  

Integrating Runit with OpenRC (or not... ;-)

I suspect that you could use runit under OpenRC in the same way that it can run under SysVinit, starting it in inittab as described in :-

https://dev1galaxy.org/viewtopic.php?id=1748

Here I have tried to have it integrated with OpenRC, so that services appear as existing services.

The file set-up

OpenRC needs to know how to start Runit's runsvdir -
download runsvdir.in from

https://raw.githubusercontent.com/OpenR … unsvdir.in

Edit it to fix up the #! path to #!/sbin/openrc-run
and change :-
       checkpath -m 0755 -o root:root -d ${RC_SVCDIR}/sv
to :-
       install -m 0755 -o root -g root -d ${RC_SVCDIR}/sv

copy it to /etc/init.d/runsvdir

chmod a+x /etc/init.d/runsvdir

The following example is copied from :-
https://wiki.gentoo.org/wiki/Runit#Open … on_feature
and hacked to work on my machine. Do make sure that the file path names are correct for you, if you try and copy it.

Gentoo seems to have a service called localmount. In order to get things running I changed this to mountall.
They show the test-daemon being run under chpst with "-o 5". My /bin/sh test-daemon failed under this with
/bin/sh: 0: 3: Invalid argument
I therefore changed the argument to allow 20 files, i.e. "-o 20"

As an ordinary user create a test-daemon, which puts out a time stamp!

cd
mkdir -f test/svc-repo/test-service
cd test
cat << EOF > test-daemon
#!/bin/sh
while true
do
  echo "This is the test-daemon `date`";
  sleep 60;
done;
EOF
chmod a+x test-daemon

Then we create an executable "run" file for Runit.

cd svc-repo/test-service
cat << EOF2 > run
#!/bin/sh
exec \
chpst -o 20 \
chpst -u daemon \
/home/user1/test/test-daemon
EOF2
chmod a+x run

Then, as root, create the OpenRC init file.

cd /etc/init.d
cat << EOF3 > test-service
#!/sbin/openrc-run
description="A supervised test service"
supervisor=runit
runit_service=/home/user1/test/svc-repo/test-service

depend() {
   need mountall runsvdir
}
EOF3
chmod a+x test-service

Now see if it will run :-

# rc-service test-service start
 * Starting runsvdir ...                      [ ok ]
 * Starting test-service ...
 * Failed to start test-service               [ !! ]
 * ERROR: test-service failed to start

It is documented that this currently (0.23) produces a failure message. This is a timing problem and the service will be started at the next runsvdir scan (if no "down" file), or try again, but see the warning in :-
https://wiki.gentoo.org/wiki/Runit#Open … on_feature

# rc-service test-service start
 * Starting test-service ...                  [ ok ]
# rc-service test-service status
run: /run/openrc/sv/test-service: (pid 4248) 163s
# ps uaxf
...
root      4224  0.0  0.0   4216  1108 ?        S    14:31   0:00 /usr/bin/runsvdir -P /run/openrc/sv log: .................................................................................................
root      4247  0.0  0.0   4064   668 ?        Ss   14:31   0:00  \_ runsv test-service
daemon    4248  0.0  0.0   4292  1488 ?        S    14:31   0:00      \_ /bin/sh /home/user1/test/test-daemon
daemon    4338  0.0  0.0   5844   684 ?        S    14:34   0:00          \_ sleep 60

# rc-service test-service stop
 * Stopping test-service ...                 [ ok ]
# rc-service test-service status
fail: /run/openrc/sv/test-service: unable to change to service directory: file does not exist

As an old Tops 20 user, I have alias v='ls -alF' ;-)

# v /run/openrc/
total 44
drwxrwxr-x 15 root root   340 May 19 14:31 ./
drwxr-xr-x 25 root root   940 May 19 14:31 ../
drwxr-xr-x  2 root root    40 May 19 13:53 daemons/
-rw-r--r--  1 root root 40021 May 19 13:53 deptree
drwxr-xr-x  2 root root    40 May 19 14:37 exclusive/
drwxr-xr-x  2 root root    40 May 19 13:53 failed/
drwxr-xr-x  2 root root    40 May 19 13:53 hotplugged/
drwxr-xr-x  2 root root    40 May 19 13:53 inactive/
drwxr-xr-x  3 root root    60 May 19 14:31 options/
drwxr-xr-x  2 root root    40 May 19 13:53 scheduled/
-rw-r--r--  1 root root     7 May 19 13:53 softlevel
drwxr-xr-x  2 root root  1280 May 19 14:37 started/
drwxr-xr-x  2 root root    40 May 19 14:32 starting/
drwxr-xr-x  2 root root    40 May 19 14:37 stopping/
drwxr-xr-x  2 root root    40 May 19 14:37 sv/
drwxr-xr-x  2 root root    40 May 19 13:53 tmp/
drwxr-xr-x  2 root root    40 May 19 13:53 wasinactive/
# v /run/openrc/sv/
total 0
drwxr-xr-x  2 root root  40 May 19 14:37 ./
drwxrwxr-x 15 root root 340 May 19 14:31 ../
# rc-service test-service start
 * Starting test-service ...
 * Failed to start test-service                                                                            [ !! ]
 * ERROR: test-service failed to start
# rc-service test-service status
run: /run/openrc/sv/test-service: (pid 4489) 4s
# v /run/openrc/sv/
total 0
drwxr-xr-x  2 root root  60 May 19 14:40 ./
drwxrwxr-x 15 root root 340 May 19 14:31 ../
lrwxrwxrwx  1 root root  39 May 19 14:40 test-service -> /home/user1/test/svc-repo/test-service/

So, it seems to be basically working!
This could presumably be modified to do logging, as described in the docs.

Geoff

Last edited by Geoff 42 (2018-05-28 14:03:26)

Offline

#2 2018-05-19 16:16:23

Geoff 42
Member
Registered: 2016-12-15
Posts: 462  

Re: Integrating Runit with OpenRC (or not... ;-)

Now, can this daemon start automatically in the default runlevel?

# rc-service test-service stop
 * WARNING: test-service is already stopped
# rc-update add test-service default
 * service test-service added to runlevel default
# v /etc/runlevels/default/
total 8
drwxr-xr-x 2 root root 4096 May 19 15:57 ./
drwxr-xr-x 9 root root 4096 May 15 15:54 ../
lrwxrwxrwx 1 root root   19 May 15 15:54 anacron -> /etc/init.d/anacron*
lrwxrwxrwx 1 root root   18 May 15 15:54 autofs -> /etc/init.d/autofs*
lrwxrwxrwx 1 root root   26 May 15 15:54 binfmt-support -> /etc/init.d/binfmt-support*
lrwxrwxrwx 1 root root   21 May 15 15:54 bluetooth -> /etc/init.d/bluetooth*
lrwxrwxrwx 1 root root   20 May 15 15:54 bootlogs -> /etc/init.d/bootlogs*
lrwxrwxrwx 1 root root   21 May 15 15:54 cgmanager -> /etc/init.d/cgmanager*
lrwxrwxrwx 1 root root   19 May 15 15:54 cgproxy -> /etc/init.d/cgproxy*
lrwxrwxrwx 1 root root   28 May 15 15:54 console-setup.sh -> /etc/init.d/console-setup.sh*
lrwxrwxrwx 1 root root   16 May 15 15:54 cron -> /etc/init.d/cron*
lrwxrwxrwx 1 root root   16 May 15 15:54 dbus -> /etc/init.d/dbus*
lrwxrwxrwx 1 root root   19 May 15 15:54 elogind -> /etc/init.d/elogind*
lrwxrwxrwx 1 root root   17 May 15 15:54 exim4 -> /etc/init.d/exim4*
lrwxrwxrwx 1 root root   19 May 15 15:54 hddtemp -> /etc/init.d/hddtemp*
lrwxrwxrwx 1 root root   22 May 15 15:54 irqbalance -> /etc/init.d/irqbalance*
lrwxrwxrwx 1 root root   24 May 15 15:54 lvm2-lvmetad -> /etc/init.d/lvm2-lvmetad*
lrwxrwxrwx 1 root root   25 May 15 15:54 lvm2-lvmpolld -> /etc/init.d/lvm2-lvmpolld*
lrwxrwxrwx 1 root root   16 May 15 15:54 lxdm -> /etc/init.d/lxdm*
lrwxrwxrwx 1 root root   16 May 15 15:54 motd -> /etc/init.d/motd*
lrwxrwxrwx 1 root root   16 May 15 15:54 nmbd -> /etc/init.d/nmbd*
lrwxrwxrwx 1 root root   15 May 15 15:54 ntp -> /etc/init.d/ntp*
lrwxrwxrwx 1 root root   20 May 15 15:54 rc.local -> /etc/init.d/rc.local*
lrwxrwxrwx 1 root root   21 May 15 15:54 rmnologin -> /etc/init.d/rmnologin*
lrwxrwxrwx 1 root root   17 May 15 15:54 rsync -> /etc/init.d/rsync*
lrwxrwxrwx 1 root root   19 May 15 15:54 rsyslog -> /etc/init.d/rsyslog*
lrwxrwxrwx 1 root root   23 May 15 15:54 samba-ad-dc -> /etc/init.d/samba-ad-dc*
lrwxrwxrwx 1 root root   16 May 15 15:54 smbd -> /etc/init.d/smbd*
lrwxrwxrwx 1 root root   15 May 15 15:54 ssh -> /etc/init.d/ssh*
lrwxrwxrwx 1 root root   22 May 15 15:54 sysfsutils -> /etc/init.d/sysfsutils*
lrwxrwxrwx 1 root root   24 May 19 15:57 test-service -> /etc/init.d/test-service*
lrwxrwxrwx 1 root root   16 May 15 15:54 wicd -> /etc/init.d/wicd*
lrwxrwxrwx 1 root root   15 May 15 15:54 xen -> /etc/init.d/xen*
lrwxrwxrwx 1 root root   22 May 15 15:54 xendomains -> /etc/init.d/xendomains*

Now reboot and when it comes up, check /var/log/rc.log :-

rc default logging started at Sat May 19 16:02:04 2018

[....] Starting enhanced syslogd: rsyslogd[ ok .
[....] Starting anac(h)ronistic cron: anacron[ ok .
[....] Starting automount...[ ok .
[....] Enabling additional executable binary formats: binfmt-support[ ok .
[....] Starting system message bus: dbus[ ok .
[....] Starting bluetooth: bluetoothd[ ok .
[....] Setting up console font and keymap...[ ok done.
[....] Starting periodic command scheduler: cron[ ok .
[....] Starting session management daemon: elogind[ ok .
[....] Starting MTA: exim4[ ok .
ALERT: exim paniclog /var/log/exim4/paniclog has non-zero size, mail system possibly broken
[....] Starting SMP IRQ Balancer: irqbalance[ ok .
[....] Starting LVM2 metadata daemon: lvmetad[ ok .
[....] Starting LVM2 poll daemon: lvmpolld[ ok .
[....] Starting X display manager: lxdm[ ok .
[....] Starting NTP server: ntpd[ ok .
[....] Starting OpenBSD Secure Shell server: sshd[ ok .
[....] Setting sysfs variables...[ ok .
[....] Starting Network connection manager: wicd[ ok .
[....] Not running within Xen or no compatible utils ...[warn (warning).
* Starting runsvdir ...
[ ok ]
* Starting test-service ...
* Failed to start test-service
[ !! ]
* ERROR: test-service failed to start

rc default logging stopped at Sat May 19 16:02:06 2018

Although it is actually running :-

root      3132  0.0  0.0   4216   996 ?        S    16:02   0:00 /usr/bin/runsvdir -P /run/openrc/sv log: ........................................................................
root      3165  0.0  0.0   4064   660 ?        Ss   16:02   0:00  \_ runsv test-service
daemon    3166  0.0  0.0   4292   704 ?        S    16:02   0:00      \_ /bin/sh /home/user1/test/test-daemon
daemon    3168  0.0  0.0   4200   672 ?        S    16:02   0:00          \_ sleep 60

rc-status reports that test-service is stopped.

# rc-service test-service status
run: /run/openrc/sv/test-service: (pid 3166) 499s
# rc-service test-service start
 * Starting test-service ...                   [ ok ]

rc-status now also reports that test-service is started.

Maybe I should try a real service.

Geoff

Offline

#3 2018-05-21 13:15:32

Geoff 42
Member
Registered: 2016-12-15
Posts: 462  

Re: Integrating Runit with OpenRC (or not... ;-)

A real service

I decided to use bluetoothd as my first real test because breaking it would not stop my system from working!

With Runit under SysVinit

https://dev1galaxy.org/viewtopic.php?id=1748

The directory associated with a service would typically be e.g. /etc/sv/bluetoothd

# v /etc/sv/bluetoothd/
total 20
drwxr-xr-x 4 root root 4096 Dec  8 16:43 ./
drwxr-xr-x 7 root root 4096 Dec 20 16:00 ../
drwxr-xr-x 3 root root 4096 Dec  8 16:43 log/
-rwxr-xr-x 1 root root   57 Dec  8 16:37 run*
drwx------ 2 root root 4096 May 15 14:56 supervise/

where I set up run and log/ while supervise is set up and used by runit.

The contents of /etc/sv/bluetoothd look like this :-

mkdir -p /etc/sv/bluetoothd/log
cd /etc/sv/bluetoothd
cat << EOF2 > run
#!/bin/sh
exec 2>&1
exec /usr/sbin/bluetoothd --nodetach
EOF2

cat << EOF3 > /log/run
#!/bin/sh
exec chpst -ulog svlogd -tt /var/svlogd/bluetoothd
EOF
chmod a+x run log/run

In order to activate it a link would be added to /etc/service, although in ASCII this is typically a link to /etc/runit/runsvdir/default/. runsvdir will be scanning this directory and start services in there. This is the scan directory.

With Runit integrated under OpenRC it uses a separate scan directory /run/openrc/sv which is a tmpfs. OpenRC looks after putting links into this scan directory, using its own directory /etc/runlevels to keep track of what should be run. /etc/runlevels/default is perhaps the equivalent of /etc/rc2.d under SysVinit.

Whether OpenRC uses Runit or not is controlled by the start-up files in /etc/init.d

I suspect that it is best to leave distributed init.d files alone and create our own version, so that it won't be over-written during an upgrade. I will create my-bluetooth in init.d using the bluetoothd set-up I had created earlier. I based the dependencies on /etc/init.d/bluetooth.

as root:-

cat << EOF > /etc/init.d/my-bluetooth
#!/sbin/openrc-run
description="A bluetooth daemon"
supervisor=runit
runit_service=/etc/sv/bluetoothd

depend() {
   need mountall rsyslog dbus runsvdir
}
EOF
chmod a+x /etc/init.d/my-bluetooth

Turn off bluetoothd directly under OpenRC

# rc-update delete bluetooth default
 * service bluetooth removed from runlevel default

# rc-service bluetooth status
[ ok ] bluetooth is running.
# rc-service bluetooth stop
[ ok ] Stopping bluetooth: /usr/sbin/bluetoothd.
# rc-service bluetooth status
[FAIL] bluetooth is not running ... failed!

Now try my-bluetooth

# rc-service my-bluetooth start
 * Caching service dependencies ...
 * Found a solvable dependency loop: cryptdisks a> umountfs u> hwclock.sh a> checkroot n> cryptdisks-early a> lvm2 u> cryptdisks.
 * Found a solvable dependency loop: cryptdisks a> umountfs u> hwclock.sh a> checkroot n> cryptdisks.
 * Found a solvable dependency loop: cryptdisks a> umountfs u> hwclock.sh a> checkroot n> cryptdisks-early n> cryptdisks.
 * Solving the loop by breaking umountfs u> hwclock.sh.
 * Solving the loop by breaking lvm2 u> cryptdisks.            [ ok ]
 * Starting my-bluetooth ...
 * Failed to start my-bluetooth                                [ !! ]
 * ERROR: my-bluetooth failed to start
# rc-service my-bluetooth status
run: /run/openrc/sv/bluetoothd: (pid 5468) 87s; run: log: (pid 5467) 87s
#ps uaxf
...
root      3140  0.0  0.0   4216  1072 ?        S    13:52   0:00 /usr/bin/runsvdir -P /run/openrc/sv log: .....................
root      3173  0.0  0.0   4064   648 ?        Ss   13:52   0:00  \_ runsv test-service
daemon    3174  0.0  0.0   4292  1568 ?        S    13:52   0:00  |   \_ /bin/sh /home/user1/test/test-daemon
daemon    5543  0.0  0.0   4200   636 ?        S    15:14   0:00  |       \_ sleep 60
root      5466  0.0  0.0   4064   664 ?        Ss   15:10   0:00  \_ runsv bluetoothd
log       5467  0.0  0.0   4208   680 ?        S    15:10   0:00      \_ svlogd -tt /var/svlogd/bluetoothd
root      5468  0.0  0.0  28228  3928 ?        S    15:10   0:00      \_ /usr/sbin/bluetoothd --nodetach

/var/svlog/bluetoothd/current reports :-

2018-05-20_14:10:24.52202 bluetoothd[5468]: Bluetooth daemon 5.43
2018-05-20_14:10:24.52232 bluetoothd[5468]: Starting SDP server
2018-05-20_14:10:24.52431 bluetoothd[5468]: Bluetooth management interface 1.14 initialized
2018-05-20_14:10:24.52443 bluetoothd[5468]: Failed to obtain handles for "Service Changed" characteristic
2018-05-20_14:10:24.52462 bluetoothd[5468]: Sap driver initialization failed.
2018-05-20_14:10:24.52464 bluetoothd[5468]: sap-server: Operation not permitted (1)

I can also see it from my phone.

The next thing is to set it to be part of runlevel default.
It seems to be a bit problematical to stop this manually started instance as is thinks it is not running, so ...

# rc-service my-bluetooth start
 * Starting my-bluetooth ...                               [ ok ]
# rc-service my-bluetooth status
run: /run/openrc/sv/bluetoothd: (pid 5468) 1334s; run: log: (pid 5467) 1334s
# rc-service my-bluetooth stop
 * Stopping my-bluetooth ...                               [ ok ]

Now add it to default and give it a prod!

# rc-update add my-bluetooth default
 * service my-bluetooth added to runlevel default
# openrc
[ ok ] Stopping bluetooth: /usr/sbin/bluetoothd.
 * Starting my-bluetooth ...
 * Failed to start my-bluetooth                           [ !! ]
 * ERROR: my-bluetooth failed to start
 * Starting test-service ...                              [ ok ]

Both of these services are running. As bluetooth started first and test-service, which was second has reported that it started, it might be worth making bluetooth depend on test-service! Unfortunately this does not work. I tried several methods to run openrc a bit later, but none worked until I hit on running it from rc.local after a sleep, while backgrounding it, so that it would not delay the boot.

Edit /etc/rc.local and add a line before the end so that it reads :-

(sleep 5 ; /sbin/openrc)&
exit 0

I haven't tried adjusting the sleep time from 5 seconds as it just worked, but maybe it could be less or on a slow machine it may need to be longer.

# tail -25 /var/log/rc.log 
[....] Starting LVM2 metadata daemon: lvmetad[ ok .
[....] Starting LVM2 poll daemon: lvmpolld[ ok .
[....] Starting X display manager: lxdm[ ok .
 * Starting runsvdir ...
 [ ok ]
 * Starting my-bluetooth ...
 * Failed to start my-bluetooth
 [ !! ]
 * ERROR: my-bluetooth failed to start
[....] Starting NTP server: ntpd[ ok .
[....] Starting OpenBSD Secure Shell server: sshd[ ok .
[....] Setting sysfs variables...[ ok .
[....] Starting Network connection manager: wicd[ ok .
[....] Not running within Xen or no compatible utils ...[warn (warning).

rc default logging stopped at Mon May 21 11:22:27 2018

rc default logging started at Mon May 21 11:22:32 2018

 * Starting my-bluetooth ...
 [ ok ]

rc default logging stopped at Mon May 21 11:22:32 2018

Although this is a crude hack to work around the start-up bug, it this seems to work ok. The service does start from the initial attempt, but it does not seem to be recorded correctly. The calling of openrc gets it to try and start it again, which tidies up the housekeeping IIUC.

Geoff

Offline

#4 2018-05-28 14:07:11

Geoff 42
Member
Registered: 2016-12-15
Posts: 462  

Re: Integrating Runit with OpenRC (or not... ;-)

What does the OpenRC supervise-daemon look like?

There are references in some of the OpenRC documentation about its own supervise-daemon.
https://github.com/OpenRC/openrc/blob/m … n-guide.md
This would appear to be an alternative to using Runit. I thought that I would have a look to see how it compares.

All that was required to be set up was the init.d file. It is necessary to remove the dependency on runsvdir and the supervisor becomes supervise-daemon. It is also necessary to set up a pid filename as well as the command. Any arguments necessary to make the daemon remain in the foreground are also required. There is more detail in what can appear in the init.d file described in man openrc-run.

# cat << EOF > /etc/init.d/my-bluetooth-2
#!/sbin/openrc-run
name="Bluetooth Daemon"
description="A bluetooth daemon"
supervisor=supervise-daemon
command=/usr/sbin/bluetoothd
command_args_foreground=--nodetach
pidfile=/run/bluetoothd.pid

depend() {
   need mountall rsyslog dbus
}
EOF

To move to this set-up, remove the reference to openrc in /etc/rc.local and then tell OpenRC about the new set-up.

# rc-service my-bluetooth stop
# rc-update delete my-bluetooth default
# rc-update add my-bluetooth-2 default

Now kick it into action :-

# openrc
 * Starting Bluetooth Daemon ...
bluetoothd[5975]: Bluetooth daemon 5.43                     [ ok ]
bluetoothd[5975]: Starting SDP server
bluetoothd[5975]: Bluetooth management interface 1.14 initialized

ps uaxf reports :-

root      5974  0.0  0.0  36292   252 pts/2    S    20:46   0:00 supervise-daemon --start --pidfile /run/bluetoothd.pid /usr/sbin/bluetoothd -- --nodetach
root      5975  0.0  0.0  28228  3956 ?        Ss   20:46   0:00  \_ /usr/sbin/bluetoothd --nodetach
$ cat /run/bluetoothd.pid 
5974

The recorded pid is that of the supervise-daemon rather than the bluetooth daemon.

This requires less setting-up than with runit, as it only requires the file in /etc/init.d, whereas runit also requires the run file in /etc/sv.

I did try killing off the daemon under both Runit and OpenRC supervise-daemon with kill -9 and in both cases the daemon was restarted.

Geoff

Offline

Board footer