Procd reference

From PRPL
Jump to: navigation, search

This document is licensed under the GPLv2, at least for now. Based off the documentation in https://dev.openwrt.org/browser/trunk/package/system/procd/files/procd.sh which may require this document be under the GPLv2.

procd is a service manager for OpenWrt. It expands upon the basic functionality of etc/rc.common by providing functionality for triggers, validation and simpler service lifecycle control.

Structure[edit]

procd consists of two main parts: procd.sh script and the procd binary. The procd.sh script is the main software that package creators will be interested in using. Additionally, there is some code inside rc.common used for management of the procd system.

Your procd init script will use the functions in procd.sh to build a JSON message which procd will read, handle and respond to, in the process likely starting your service instances, adding triggers, validations, etc.

Messages sent to procd from the functions in procd.sh are sent via ubus as a JSON message. procd.sh functions build a JSON message which dictates certain function design and usage. For example, procd_open_trigger creates a trigger array. After adding all the triggers, a corresponding procd_close_trigger must be called to close the trigger array.

API for procd scripts[edit]

start_service()[edit]

Initializing your procd service. Create service instances in this function.

stop_service()[edit]

Shutdown for your service. If there's some cleanup your service needs to do, it should happen here.

reload_service()[edit]

optional

Called on service reload requests. If there's something that has to happen on a reload, it will happen there. Otherwise, the service will simply be restarted.

service_running()[edit]

optional

Called when a service running check occurs. WIP

Functions[edit]

procd_open_service(name, [script])[edit]

Used only inside rc.common

Initialize a new procd command message containing a service with one or more instances.

TODO: How is the name of the service set?

procd_close_service()[edit]

Used only inside rc.common

End the command message and send it to procd.

procd_open_instance([name])[edit]

Add an instance to the service described by the previous procd_open_service call. An instance of a service encompasses its command and arguments, other configuration, triggers and validations. It's possible have multiple instances running in a single call of the procd service, each running with different commands and functionality.

Provide example

procd_set_param(type, [value...])[edit]

Sets a parameter on an service instance. The contents of value is dependent upon the parameter type. The types are as follows:

  • command: command line for starting the service, including arguments, an array.
  • respawn: array of 3 values for handling respawning. First, the timeout in seconds for restarting a service after it closes. Second, a maximum time to wait for a process respawn to complete.(?) Last, a maximum number of times to attempt respawning for before giving up (0 means never stop trying to respawn). (What happens if nothing is passed in?)
  • env: an environment variable and value passed to the service process, e.g. proc_set_param env NO_DAEMONIZE=1
  • data: arbitrary name/value pairs for detecting config changes (table) (I can't find an example of this being used)
  • file: an array of config file paths. If any of these files changes, the instance is respawned.
  • netdev: array of names of a bound network device (detects ifindex changes). If any of the network devices is changed (ifindex changes), the instance is respawned.
  • limits: an array of resource limits. (passed to the process)? The array of values is written in name=value format. A value of unlimited corresponds to an rlimit of infinity. Each rlimit name is in the following array from service/instance.c which corresponds to rlimit definitions in the Linux kernel:
static const struct rlimit_name rlimit_names[] = {
	{ "as", RLIMIT_AS },
	{ "core", RLIMIT_CORE },
	{ "cpu", RLIMIT_CPU },
	{ "data", RLIMIT_DATA },
	{ "fsize", RLIMIT_FSIZE },
	{ "memlock", RLIMIT_MEMLOCK },
	{ "msgqueue", RLIMIT_MSGQUEUE },
	{ "nice", RLIMIT_NICE },
	{ "nofile", RLIMIT_NOFILE },
	{ "nproc", RLIMIT_NPROC },
	{ "rss", RLIMIT_RSS },
	{ "rtprio", RLIMIT_RTPRIO },
	{ "sigpending", RLIMIT_SIGPENDING },
	{ "stack", RLIMIT_STACK },
	{ NULL, 0 }
};
  • user: username of the user the service will run under
  • watch: array of uci config categories to watch for changes. If a change occurs, the service is respawned. As an example, procd_set_param watch network.interface restarts the service if the network interfaces change.
  • nice: sets the priority of the service process
  • stdout: A boolean value of 1 redirects the service stdout to the main stdout.
  • stderr: A boolean value of 1 redirects the service stderr to the main stderr.
  • seccomp: path to seccomp JSON file for the service listing the system calls that the instance is allowed to call.

No space separation is done for arrays/tables - use one function argument per command line argument

procd_append_param(type, [values])[edit]

Appends to a previously provided parameter. One example is for adding additional arguments to the command parameter for a service instance. Uses the same arguments as procd_set_param.

procd_close_instance()[edit]

Complete the instance being prepared

procd_kill(service, [instance])[edit]

Kill a service instance (or all instances). service is the name of the service and instance is the name of the instance in the service to kill. If no instance is provided, all of the instances will be shut down.

procd_open_trigger()[edit]

Adds triggers to the service. Opens trigger array in the ubus JSON message. Must be closed once you've added all triggers with a corresponding procd_close_trigger.

procd_add_raw_trigger(event, timeout, [script])[edit]

Add a trigger which runs every time a particular event happens. Timeout is the length of time to wait after the event for this trigger to be called?

procd_add_config_trigger(event, package, [script])[edit]

Add a trigger which runs every time an event occurs on a particular package's configuration. Calls the script command.

procd_add_interface_trigger(interface_path, interface_name, [script])[edit]

Add a trigger which runs every time a particular interface is modified. Runs the script when the trigger is fired.

Don't know what interface_path you can have other than interface.*?

procd_add_reload_trigger([config_files])[edit]

Every time any of the config files are changed (and reloaded), the current instance is restarted.

procd_add_reload_interface_trigger([names])[edit]

Any time any of the given interface names are changed, the instance is restarted.

procd_close_trigger()[edit]

Completes your addition of triggers to the service.

procd_add_instance([script])[edit]

Opens a new instance, setting the script to run and closing the instance. Shorthand for:

procd_open_instance
procd_set_param command [script and args]
procd_close_instance

procd_open_validate()[edit]

Opens an array of validations. Must be closed with a corresponding procd_close_validate.

uci_validate_section(package, type, name, [values])[edit]

Adds validations for the given UCI package, type and name. UCI uses the validations to know whether information has been properly provided. The validations are passed to UCI via the ubus system.

The format of values is 'name:type:default', for a list it is 'name:list(element_type)'. For example, to evaluate the ntp section of /etc/config/system, the init script does this:

uci_validate_section system timeserver 'ntp' 'server:list(host)' 'enabled:bool:1' 'enable_server:bool:0'

It is helpful to note that this function runs an eval on the results of the ubox utility /sbin/validate_data. This means that during the above call, the following statement is executed:

server='0.openwrt.pool.ntp.org'\ '1.openwrt.pool.ntp.org'\ '2.openwrt.pool.ntp.org'\ '3.openwrt.pool.ntp.org'; enabled=0; enable_server=0;

This characteristic makes this a very useful function for loading uci contexts into shell variables. eg:

#when the service starts, we need to perform a single successful ntp poll to get the sytem time set up correctly.
local server

#only do ntp poll if the config timerserver section is valid, and contains at least 1 server.
if uci_validate_section system timeserver 'ntp' 'server:list(host)' && [ -n server ] 
then
    echo "Attempting NTP Sync."
    local command_line
    command_line="/usr/sbin/ntpd -q -n"
    for element in $server
    do
        command_line=$command_line" -p "$element
    done
    local result=false
    while true
    do
        if $command_line
        then
            echo "NTP Success!"
            break
        fi
        echo "NTP sync failed, sleeping for retry in 5 seconds."
        sleep 5
    done

fi

procd_close_validate()[edit]

Closes the array of validations. Called when all the validations have been added.

procd_add_validation([validations])[edit]

Opens a validation section, adds a validation and closes the validation section. Shorthand for:

procd_open_validate
[an array of validations]
procd_close_validate

procd_add_jail(name,[jail_options])[edit]

Creates and adds a jail with the given name. The options correspond to whether certain features are available inside the OpenWrt jail created. The types are:

  • log - add access to /dev/log
  • ubus - add access to a ubus socket
  • procfs - add access to /proc
  • sysfs - add access to /sys

procd_add_jail_mount([mounts])[edit]

Makes a set of filepaths available in the jail as read-only. mounts is an array of filepaths to be mounted in the jail as read only. If you want to mount files read-write, use procd_add_jail_mount_rw.

procd_add_jail_mount_rw([mounts])[edit]

Makes a set of filepaths available in the jail as read-write. mounts is an array of filepaths to be mounted in the jail as read write. If you want to mount files read-only, use procd_add_jail_mount.

procd_set_config_changed(package)[edit]

Notifies ubus immediately that a package's configuration has changed. You may use this in your init script if you've made changes that you want to be immediately seen

TODO: Does modifying via UCI not handle this?

procd_add_mdns[edit]

???

procd_add_mdns_service[edit]

???