The can be convenient for running commands or services as procd services
without needing to separately write initscripts, just uci configuration.
The package was imported from [1].
[1] 0a85f5c75f/pservice
Ref: https://github.com/yousong/waller/issues/1
Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
lilik-openwrt-22.03
@ -0,0 +1,28 @@ | |||||
# Copyright (C) 2017 Yousong Zhou | |||||
include $(TOPDIR)/rules.mk | |||||
PKG_NAME:=pservice | |||||
PKG_VERSION:=2017-08-29 | |||||
PKG_RELEASE=1 | |||||
PKG_MAINTAINER:=Yousong Zhou <yszhou4tech@gmail.com> | |||||
include $(INCLUDE_DIR)/package.mk | |||||
define Package/pservice | |||||
SECTION:=utils | |||||
CATEGORY:=Utilities | |||||
TITLE:=Wrap commands as procd services | |||||
endef | |||||
define Build/Compile | |||||
endef | |||||
define Package/pservice/install | |||||
$(INSTALL_DIR) $(1)/usr/bin $(1)/etc/init.d $(1)/etc/config | |||||
$(INSTALL_BIN) ./files/pservice.init $(1)/etc/init.d/pservice | |||||
$(INSTALL_DATA) ./files/pservice.config $(1)/etc/config/pservice | |||||
endef | |||||
$(eval $(call BuildPackage,pservice)) |
@ -0,0 +1,44 @@ | |||||
# uci | |||||
`disabled`, bool, default `0` | |||||
`name`, string, name of the service instance | |||||
`command`, file, the service instance executable | |||||
`args`, list of args | |||||
`stderr`, bool, default `0`, log stderr output of the service instance | |||||
`stdout`, bool, default `0`, log stdout output of the service instance | |||||
`env`, list of environment variable settings of the form `var=val` | |||||
`file`, list of file names. Service instances will be restarted if content of | |||||
these files have changed on service reload event. | |||||
`respawn_threshold`, uinteger, default `3600`, time in seconds the instances | |||||
have to be in running state to be considered a valid run | |||||
`respawn_timeout`, uinteger, default `5`, time in seconds the instance should | |||||
be delayed to start again after the last crash | |||||
`respawn_maxfail`, uinteger, default `5`, maximum times the instances can | |||||
crash/fail in a row and procd will not try to bring it up again after this | |||||
limit has been reached | |||||
# notes and faq | |||||
Initial environment variables presented to service instances may be different | |||||
from what was observed on the interactive terminal. E.g. `HOME=/` may affect | |||||
reading `~/.ssh/known_hosts` of dropbear ssh instance. | |||||
PATH=/usr/sbin:/usr/bin:/sbin:/bin PWD=/ HOME=/ | |||||
If `list args xxx` seems to be too long causing pain, consider using `/bin/sh` | |||||
as the `command`. It is also worth noting that uci supports multi-line option | |||||
value. | |||||
Child processes will keep running when their parent process was killed. This | |||||
is especially the case and should be taken into account with option `command` | |||||
being `/bin/sh` and it is recommended to use `exec` as the last shell command. |
@ -0,0 +1,24 @@ | |||||
config pservice | |||||
option disabled 1 | |||||
option name 'demo0' | |||||
option command /bin/sh | |||||
option respawn_maxfail 0 | |||||
list args -c | |||||
list args 'env | logger -t $name; exec sleep $time' | |||||
list env 'v0=0' | |||||
list env 'v1=val with space' | |||||
list env 'name=demo0' | |||||
list env 'time=1799' | |||||
list file /tmp/sleep.conf | |||||
config pservice | |||||
option disabled 1 | |||||
option name 8021x | |||||
option command /usr/sbin/wpa_supplicant | |||||
option stdout 1 | |||||
list args -i | |||||
list args eth0.1 | |||||
list args -D | |||||
list args wired | |||||
list args -c | |||||
list args /etc/wpa_supplicant-eth0.1.conf |
@ -0,0 +1,85 @@ | |||||
#!/bin/sh /etc/rc.common | |||||
# Copyright (C) 2017 Yousong Zhou | |||||
START=99 | |||||
USE_PROCD=1 | |||||
pservice_list_cb() { | |||||
local val="$1"; shift | |||||
local param="$1"; shift | |||||
procd_append_param "$param" "$val" | |||||
} | |||||
pservice() { | |||||
local cfg="$1" | |||||
eval "$(validate_pservice_section "$cfg" pservice_validate_mklocal)" | |||||
validate_pservice_section "$cfg" || return 1 | |||||
[ "$disabled" = 0 ] || return 0 | |||||
[ -x "$command" ] || return 1 | |||||
procd_open_instance "$name" | |||||
procd_set_param command "$command" | |||||
procd_set_param stderr "$stderr" | |||||
procd_set_param stdout "$stdout" | |||||
procd_set_param respawn "$respawn_threshold" "$respawn_timeout" "$respawn_maxfail" | |||||
[ -z "$args" ] || config_list_foreach "$cfg" args pservice_list_cb command | |||||
if [ -n "$env" ]; then | |||||
procd_set_param env | |||||
config_list_foreach "$cfg" env pservice_list_cb env | |||||
fi | |||||
if [ -n "$file" ]; then | |||||
procd_set_param file | |||||
config_list_foreach "$cfg" file pservice_list_cb file | |||||
fi | |||||
procd_close_instance | |||||
} | |||||
start_service() { | |||||
config_load 'pservice' | |||||
config_foreach pservice pservice | |||||
} | |||||
stop_service() { | |||||
true | |||||
} | |||||
service_triggers() { | |||||
procd_open_validate | |||||
validate_pservice_section | |||||
procd_close_validate | |||||
} | |||||
pservice_validate_mklocal() { | |||||
local tuple opts | |||||
shift 2 | |||||
for tuple in "$@"; do | |||||
opts="${tuple%%:*} $opts" | |||||
done | |||||
[ -z "$opts" ] || echo "local $opts" | |||||
} | |||||
pservice_validate() { | |||||
uci_validate_section pservice "$@" | |||||
} | |||||
validate_pservice_section() { | |||||
local cfg="$1"; shift | |||||
local func="$1"; shift | |||||
"${func:-pservice_validate}" pservice "$cfg" \ | |||||
"disabled:bool:0" \ | |||||
"name:string" \ | |||||
"env:regex('^[a-zA-Z_][a-zA-Z0-9_]*=.*$')" \ | |||||
"command:file" \ | |||||
"args:list(string)" \ | |||||
"stderr:bool:0" \ | |||||
"stdout:bool:0" \ | |||||
"respawn_threshold:uinteger:3600" \ | |||||
"respawn_timeout:uinteger:5" \ | |||||
"respawn_maxfail:uinteger:5" \ | |||||
"file:string" | |||||
} |