pup_event service management

Page updated February 28, 2018
In this context, "services" are processes that start and stop in the background. For example the 'cupsd' daemon for printing.

In Puppy and derivatives such as Quirky and Easy, most of these services are scripts found at folder /etc/init.d. Puppy runs /etc/rc.d/rc.sysinit at startup (refer to /etc/inittab which is read by Busybox 'init'), which in turn calls /etc/rc.d/rc.services.

rc.services executes the scripts in /etc/init.d, in alphabetical order (mostly -- in Quirky and Easy, there is a bit of juggling in rc.services to modify that order). Note that the simple Busybox init does not have runlevels.

The single big problem with this fixed order of execution is dependencies, or lack thereof. For example, it may only be appropriate to start /etc/init.d/rc.samba if the network is "up". Or to run the 'ntpd' daemon that accesses online Network Time Protocol servers (to sync the local time from the Internet).

There needs to be mechanism to start services, as dependencies are met, and stopped when not. Puppy and derivatives achieve this in a very haphazard manner, or not at all.

So, I researched "service managers", and reported to my blog:





...in summary, I was not satisfied with what is on offer.

As I have done many times in the past, if not satisfied with what is available, do it myself. To understand my implementation, firstly an introduction to 'pup_event'...


The pup_event scripts are to be found in /usr/local/pup_event. The main guy is 'pup_event_frontend_d', which is launched from /root/.xinitrc when X starts.
It is a binary file written in BaCon (a BASIC to C translator), that detects hotplug events and maintains the desktop drive icons.

Well, that is the main purpose, it also performs some housekeeping at regular intervals (see /usr/local/pup_event/frontend_timeout, that pup_event_frontend_d calls every second.

Or rather, that is how it works in Puppy. In Quirky and Easy, I have evolved pup_event_frontend_d to be more efficient, and now a server for the service-manager.

Before getting onto the service-manager though, I need to introduce the concept of pup_event IPC...

pup_event IPC

This is a peer-to-peer serverless technique for message-passing and synchronization between programs. Or, it can also be a server-client arrangement.

Interesting, I went through a similar process of evaluation, ending in disappointment, of unix domain sockets and named pipes. After some input from technosaurus, invented my own IPC, based on inotify. See this old blog post, mid-2013:


pup_event_frontend_d is a IPC server, exporting information such as drive hotplug events, network up/down (and which interface), 1-, 4- and 60-second timeouts, X up/down, and in future, probably up/down for audio.

Any client program can receive this information. How this is achieved is described in this document:


...have a gander at that, then getting onto the actual service-manager...

pup_event service-manager

As already mentioned, /etc/rc.d/rc.services runs the services in folder /etc/init.d

This script is now enhanced, evolved into the service-manager. There is a new variable in /etc/eventmanager:
#180222 simple ipc-based service manager
#ref: /etc/rc.d/rc.services, rc.services_ipc
#names of services in /etc/init.d that must only start when a condition is met...
#format of each space-delimited parameter: dep1[:dep2[...]]%service1[:service2[...]]
#180228 optional append "ONESHOT" to service name if no "stop)" option in script.
2018-02-28 Enhancement
In PE_SERVICE_MANAGER, append "ONESHOT" to a service name, for example "cups-net-fixONESHOT". This is for service scripts that just run once at computer startup, and do not have a daemon or anything that needs to be stopped. "ONESHOT" is optional, improves efficiency.
This enhancement is shown in the code on this page as dark-blue text. 

Keeping it simple for now, the variable PE_SERVICE_MANAGER specifies that sshd and rc.samba require the network to be up, before they start. Now look in rc.services, extracting just the relevant parts:
#180222 simple ipc-based service manager
#these must run before pup_event_frontend_d starts (launched from /root/.xinitrc)
echo -n '' > /tmp/pup_event_backend/service-manager-services
if "$PE_SERVICE_MANAGER" ];then #see /etc/eventmanager
   SM_PARAMS="${aPESM/%/ }" #ex: 'network%sshd:rc.samba' to 'network sshd:rc.samba'
   echo -e "${SM_SERVICES//:/\\n}" >> /tmp/pup_event_backend/service-manager-services
#...one service per line    /etc/rc.d/rc.services_ipc ${SM_PARAMS} &  done fi
sed -i -e 's%ONESHOT$%%' /tmp/pup_event_backend/service-manager-services #180228
for service_script in /etc/init.d/* /etc/init.d/.[a-z]* do  if -x $service_script ];then 
  #180222 exclude those already run above...   if -s /tmp/pup_event_backend/service-manager-services ];then    baseSC="$(basename $service_script)"    echo "$baseSC" grep -q -x -f /tmp/pup_event_backend/service-manager-services    $? -eq ] && continue   fi    echo $service_script   $service_script start  fi done
...in a nutshell, /etc/rc.d/rc.services_ipc is called, with names of services and their dependencies passed to it. For our example, that will be "network sshd:rc.samba". So, look at /etc/rc.d/rc.services_ipc...
DEPs="${1//:/ }" #replace all : with spaces
SERVICEs="${2//:/ }"

#180228 find any one-shot services. ref: /etc/eventmanager
case "$aSERVICE" in
*) mSERVICEs="${mSERVICEs}${aSERVICE} " ;;

###big loop### while true ]; do
 for aDEP in $DEPs  do   MSG1="$(/usr/local/pup_event/pup_event_ipc "${aDEP}:${$}")"   #...ex: network:12345 MSG=eth0 or MSG='' (empty, meaning i/f gone down)   [ ! "$MSG1" ] && continue 2  done
 #start the services...  for aSERVICE in $mSERVICEs $oSERVICEs  do   if -x /etc/init.d/${aSERVICE} ];then    echo "Starting /etc/init.d/${aSERVICE}"    /etc/init.d/${aSERVICE} start   fi  done
[ "$mSERVICEs" == "" ] && break

 for aDEP in $DEPs  do   MSG1="$(/usr/local/pup_event/pup_event_ipc "${aDEP}:${$}")"   if [ ! "$MSG1" ];then  
   #stop the services...    for aSERVICE in $mSERVICEs    do     if -x /etc/init.d/${aSERVICE} ];then      echo "Stopping /etc/init.d/${aSERVICE}"      /etc/init.d/${aSERVICE} stop     fi    done  
   continue 2   fi  done
done ###big loop###
...this script is very simple. It will start 'sshd' and 'rc.samba' when the network goes up, and stop them when the network goes down.

That's the essence of it, a very simple service-manager. Importantly, it is extremely efficient as it does not use polling. 'pup_event_ipc' is a binary executable (also written in BaCon) that uses inotify to wait on a file-change. That is much more efficient than polling.


A note for developers. The binaries 'pup_event_frontend_d' and 'pup_event_ipc' are written in BaCon, which is a BASIC-to-C translator. BaCon can be installed in any distro, but it must be version 3.0.2 or 3.7.2+.

The source code for these executables is found in 'pup-tools-*.tar.gz', here:


...you must have 'pup-tools-20180222.tar.gz' or later if available.

Advantages and disadvantages

Compared with other service managers

  1. Tiny: rc.services (3.4KB), rc.services_ipc (1.6KB), pup_event_frontend_d (27KB), pup_event_ipc (23KB)
  2. Efficient, hardly any resources, event-driven.
  3. Scripts in /etc/init.d unmodified.
  4. Does one thing and does it well: brings services up and down according to dependencies.
  1. rc.services_ipc must launch clients before pup_event_frontend_d (not really a disadvantage, just a requirement).
  2. Does not have monitoring and resource management of some other service managers (that is, not bloated).
  3. Probably only suitable for Puppy Linux and derivatives (though, not impossible, would be an interesting project to export to other distros -- note, definitely systemd-unfriendly).

Have fun!

Barry Kauler
February 22, 2018