User Tools

Site Tools


inbox:procd-init-scripts

This site is still under writing …

How to write a procd init script?

A procd init script is similiar to an old init script, but with a few differences:

  • procd expects services to run in the foreground
  • Different shebang line: #!/bin/sh /etc/rc.common
  • Explicitly use procd USE_PROCD=1

Example:

#!/bin/sh /etc/rc.common

USE_PROCD=1

To start a service we need the function 'start_service'. stop_service is only needed when you need special things to stop your service. stop_service() is called after procd killed the service. The service itself should run in the foreground. (Apparently

start_service() {
  procd_open_instance [instance_name]
  procd_set_param command /sbin/your_service_daemon -b -a --foo

  # respawn automatically if something died, be careful if you have an alternative process supervisor
  # if process dies sooner than respawn_threshold, it is considered crashed and after 5 retries the service is stopped
  procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}

  procd_set_param env SOME_VARIABLE=funtimes  # pass environment variables to your process
  procd_set_param limits core="unlimited"  # If you need to set ulimit for your process
  procd_set_param file /var/etc/your_service.conf # /etc/init.d/your_service reload will restart the daemon if these files have changed
  procd_set_param netdev dev # likewise, except if dev's ifindex changes.
  procd_set_param data name=value ... # likewise, except if this data changes.
  procd_set_param stdout 1 # forward stdout of the command to logd
  procd_set_param stderr 1 # same for stderr
  procd_set_param user nobody # run service as user nobody
  procd_set_param pidfile /var/run/somefile.pid # write a pid file on instance start and remote it on stop
  procd_close_instance
}

TODO: Table old openwrt initscript ↔ new procd

For as much information as is available, see the documentation at the top of procd.sh

Procd triggers on config file / network interface changes

In older versions of OpenWrt, a system called "ucitrack" attempted to track UCI config files, and the processes that depended on each of them, and would restart them all as needed. This too, is replaced with ubus/procd, and expanded to allow notifying services when network interfaces change. This is useful for services like dnsmasq, and proxy/routing software that cares about which network interfaces are in use, and with what configuration.

First, to simply make your service depend on a config file, add a "service_triggers()" clause to your init script

service_triggers()
{
        procd_add_reload_trigger "uci-file-name"
}

This will setup hooks such that issuing 'reload_config' will issue a call to '/etc/init.d/<yourinitscript> reload' when the md5sums of '/etc/config/uci-file-name' has changed. You can edit as many config files as you like, and then issue reload_config, procd will take care of reloading all of them. Note, no change in the config file, no reload. If you want to explicitly reload, you still need to issue '/etc/init.d/<yourservice> reload' manually.

By default, "reload" will cause a stop/start call, _only_ if the md5sum of the final computed command line has changed. (This is in addition to any reload triggers) If your application doesn't use args, but has a generated config file, or parses the uci config file directly, you should add that to procd via 'procd_set_param file /var/etc/your_service.conf' or 'procd_set_param file /etc/config/yourapp' If you don't have any files or args, but still need to explicitly restart when reload is called, you can hook reload_service as shown below.

reload_service()
{
        echo "Explicitly restarting service, are you sure you need this?"
        stop
        start
}

If you want/need your service to depend on changes to networking, simply modify your service_triggers section, like so..

service_triggers()
{
        procd_add_reload_trigger "uci-file-name" "second-uci-file"
        procd_add_network_trigger "lan"|"etho0" FIXME - this is still a work in process....
}
igmpproxy is (currently) the only service that makes use of this, but (hopefully) by the time you read this, dnsmasq will also have been updated, at least.

Signalling a service

Current versions (LEDE 17.01 and up) support sending signals to procd registered services. (OpenWrt-CC gained support for pidfile writing, which allowed third party monitoring services to send signals) This allows, for instance, reload_config and /etc/init.d/yourapp reload to issue a SIGHUP instead of stop/starting your process.

reload_service() {
         procd_send_signal service_name [instance_name] [signal]
}
The signal is SIGHUP by default, and must be specified by NAME. (You can get available signals from kill -l on the console)

The service_name is the basename of the init.d script, eg for /etc/init.d/yourappyourapp.

The instance_name if you wish to signal different instances of your service, comes from the optional parameter to procd_open_instance [instance_name]. If instance_name is unspecified, or '*' then the signal will be delivered to all instances of the service.

Note You can also send signals to named procd services from outside initscripts. Simply load the procd functions and send the signal as before.

#!/bin/sh
. /lib/functions/procd.sh
procd_send_signal service_name [instance_name] [signal]

How do these scripts work?

All arguments are packed into json and send over to procd via ubus

Debugging

Set PROCD_DEBUG=1 to see debugging information when starting or stopping a procd init script.

Examples

inbox/procd-init-scripts.txt · Last modified: 2017/07/11 14:04 by karlp