procd: procd.sh: make no assumptions about init script path
[openwrt/staging/jow.git] / package / system / procd / files / procd.sh
index b4b6faa6627af447108bb6542d7c63af65e818a2..8694e087fb7ad7f86c740507f4ed8fdd37f3a4fc 100644 (file)
 #     file: configuration files (array)
 #     netdev: bound network device (detects ifindex changes)
 #     limits: resource limits (passed to the process)
-#     user info: array with 1 values $username
+#     user: $username to run service as
+#     group: $groupname to run service as
 #     pidfile: file name to write pid into
+#     stdout: boolean whether to redirect commands stdout to syslog (default: 0)
+#     stderr: boolean whether to redirect commands stderr to syslog (default: 0)
+#     facility: syslog facility used when logging to syslog (default: daemon)
 #
 #   No space separation is done for arrays/tables - use one function argument per command line argument
 #
 # procd_close_instance():
 #   Complete the instance being prepared
 #
+# procd_running(service, [instance]):
+#   Checks if service/instance is currently running
+#
 # procd_kill(service, [instance]):
 #   Kill a service instance (or all instances)
 #
@@ -33,7 +40,7 @@
 #   Send a signal to a service instance (or all instances)
 #
 
-. $IPKG_INSTROOT/usr/share/libubox/jshn.sh
+. "$IPKG_INSTROOT/usr/share/libubox/jshn.sh"
 
 PROCD_RELOAD_DELAY=1000
 _PROCD_SERVICE=
@@ -44,7 +51,7 @@ procd_lock() {
 
        flock -n 1000 &> /dev/null
        if [ "$?" != "0" ]; then
-               exec 1000>/var/lock/procd_${service_name}.lock
+               exec 1000>"$IPKG_INSTROOT/var/lock/procd_${service_name}.lock"
                flock 1000
                if [ "$?" != "0" ]; then
                        logger "warning: procd flock for $service_name failed"
@@ -187,6 +194,10 @@ _procd_add_jail() {
                procfs) json_add_boolean "procfs" "1";;
                sysfs)  json_add_boolean "sysfs" "1";;
                ronly)  json_add_boolean "ronly" "1";;
+               requirejail)    json_add_boolean "requirejail" "1";;
+               netns)  json_add_boolean "netns" "1";;
+               userns) json_add_boolean "userns" "1";;
+               cgroupsns)      json_add_boolean "cgroupsns" "1";;
                esac
        done
        json_add_object "mount"
@@ -235,7 +246,7 @@ _procd_set_param() {
                env|data|limits)
                        _procd_add_table "$type" "$@"
                ;;
-               command|netdev|file|respawn|watch)
+               command|netdev|file|respawn|watch|watchdog)
                        _procd_add_array "$type" "$@"
                ;;
                error)
@@ -249,7 +260,8 @@ _procd_set_param() {
                reload_signal)
                        json_add_int "$type" $(kill -l "$1")
                ;;
-               pidfile|user|seccomp|capabilities)
+               pidfile|user|group|seccomp|capabilities|facility|\
+               extroot|overlaydir|tmpoverlaysize)
                        json_add_string "$type" "$1"
                ;;
                stdout|stderr|no_new_privs)
@@ -286,11 +298,10 @@ _procd_add_interface_trigger() {
 }
 
 _procd_add_reload_interface_trigger() {
-       local script=$(readlink "$initscript")
-       local name=$(basename ${script:-$initscript})
+       local script=$(readlink -f "$initscript")
 
        _procd_open_trigger
-       _procd_add_interface_trigger "interface.*" $1 /etc/init.d/$name reload
+       _procd_add_interface_trigger "interface.*" $1 "${script:-$initscript}" reload
        _procd_close_trigger
 }
 
@@ -316,6 +327,79 @@ _procd_add_config_trigger() {
        json_close_array
 }
 
+_procd_add_mount_trigger() {
+       json_add_array
+       _procd_add_array_data "$1"
+       local action="$2"
+       local multi=0
+       shift ; shift
+
+       json_add_array
+       _procd_add_array_data "if"
+
+       if [ "$2" ]; then
+               json_add_array
+               _procd_add_array_data "or"
+               multi=1
+       fi
+
+       while [ "$1" ]; do
+               json_add_array
+               _procd_add_array_data "eq" "target" "$1"
+               shift
+               json_close_array
+       done
+
+       [ $multi = 1 ] && json_close_array
+
+       json_add_array
+       _procd_add_array_data "run_script" /etc/init.d/$name $action
+       json_close_array
+
+       json_close_array
+       _procd_add_timeout
+       json_close_array
+}
+
+_procd_add_action_mount_trigger() {
+       local action="$1"
+       shift
+       local mountpoints="$(procd_get_mountpoints "$@")"
+       [ "${mountpoints//[[:space:]]}" ] || return 0
+       local script=$(readlink "$initscript")
+       local name=$(basename ${script:-$initscript})
+
+       _procd_open_trigger
+       _procd_add_mount_trigger mount.add $action "$mountpoints"
+       _procd_close_trigger
+}
+
+procd_get_mountpoints() {
+       (
+               __procd_check_mount() {
+                       local cfg="$1"
+                       local path="${2%%/}/"
+                       local target
+                       config_get target "$cfg" target
+                       target="${target%%/}/"
+                       [ "$path" != "${path##$target}" ] && echo "${target%%/}"
+               }
+               local mpath
+               config_load fstab
+               for mpath in "$@"; do
+                       config_foreach __procd_check_mount mount "$mpath"
+               done
+       ) | sort -u
+}
+
+_procd_add_restart_mount_trigger() {
+       _procd_add_action_mount_trigger restart "$@"
+}
+
+_procd_add_reload_mount_trigger() {
+       _procd_add_action_mount_trigger reload "$@"
+}
+
 _procd_add_raw_trigger() {
        json_add_array
        _procd_add_array_data "$1"
@@ -335,13 +419,12 @@ _procd_add_raw_trigger() {
 }
 
 _procd_add_reload_trigger() {
-       local script=$(readlink "$initscript")
-       local name=$(basename ${script:-$initscript})
+       local script=$(readlink -f "$initscript")
        local file
 
        _procd_open_trigger
        for file in "$@"; do
-               _procd_add_config_trigger "config.change" "$file" /etc/init.d/$name reload
+               _procd_add_config_trigger "config.change" "$file" "${script:-$initscript}" reload
        done
        _procd_close_trigger
 }
@@ -365,7 +448,7 @@ _procd_append_param() {
                env|data|limits)
                        _procd_add_table_data "$@"
                ;;
-               command|netdev|file|respawn|watch)
+               command|netdev|file|respawn|watch|watchdog)
                        _procd_add_array_data "$@"
                ;;
                error)
@@ -398,6 +481,18 @@ _procd_add_instance() {
        _procd_close_instance
 }
 
+procd_running() {
+       local service="$1"
+       local instance="${2:-*}"
+       [ "$instance" = "*" ] || instance="'$instance'"
+
+       json_init
+       json_add_string name "$service"
+       local running=$(_procd_ubus_call list | jsonfilter -l 1 -e "@['$service'].instances[$instance].running")
+
+       [ "$running" = "true" ]
+}
+
 _procd_kill() {
        local service="$1"
        local instance="$2"
@@ -424,6 +519,53 @@ _procd_send_signal() {
        _procd_ubus_call signal
 }
 
+_procd_status() {
+       local service="$1"
+       local instance="$2"
+       local data state
+       local n_running=0
+       local n_stopped=0
+       local n_total=0
+
+       json_init
+       [ -n "$service" ] && json_add_string name "$service"
+
+       data=$(_procd_ubus_call list | jsonfilter -e '@["'"$service"'"]')
+       [ -z "$data" ] && { echo "inactive"; return 3; }
+
+       data=$(echo "$data" | jsonfilter -e '$.instances')
+       if [ -z "$data" ]; then
+               [ -z "$instance" ] && { echo "active with no instances"; return 0; }
+               data="[]"
+       fi
+
+       [ -n "$instance" ] && instance="\"$instance\"" || instance='*'
+
+       for state in $(jsonfilter -s "$data" -e '$['"$instance"'].running'); do
+               n_total=$((n_total + 1))
+               case "$state" in
+               false) n_stopped=$((n_stopped + 1)) ;;
+               true)  n_running=$((n_running + 1)) ;;
+               esac
+       done
+
+       if [ $n_total -gt 0 ]; then
+               if [ $n_running -gt 0 ] && [ $n_stopped -eq 0 ]; then
+                       echo "running"
+                       return 0
+               elif [ $n_running -gt 0 ]; then
+                       echo "running ($n_running/$n_total)"
+                       return 0
+               else
+                       echo "not running"
+                       return 5
+               fi
+       else
+               echo "unknown instance $instance"
+               return 4
+       fi
+}
+
 procd_open_data() {
        local name="$1"
        json_set_namespace procd __procd_old_cb
@@ -479,13 +621,30 @@ uci_validate_section()
        local _result
        local _error
        shift; shift; shift
-       _result=`/sbin/validate_data "$_package" "$_type" "$_name" "$@" 2> /dev/null`
+       _result=$(/sbin/validate_data "$_package" "$_type" "$_name" "$@" 2> /dev/null)
        _error=$?
        eval "$_result"
-       [ "$_error" = "0" ] || `/sbin/validate_data "$_package" "$_type" "$_name" "$@" 1> /dev/null`
+       [ "$_error" = "0" ] || $(/sbin/validate_data "$_package" "$_type" "$_name" "$@" 1> /dev/null)
        return $_error
 }
 
+uci_load_validate() {
+       local _package="$1"
+       local _type="$2"
+       local _name="$3"
+       local _function="$4"
+       local _option
+       local _result
+       shift; shift; shift; shift
+       for _option in "$@"; do
+               eval "local ${_option%%:*}"
+       done
+       uci_validate_section "$_package" "$_type" "$_name" "$@"
+       _result=$?
+       [ -n "$_function" ] || return $_result
+       eval "$_function \"\$_name\" \"\$_result\""
+}
+
 _procd_wrapper \
        procd_open_service \
        procd_close_service \
@@ -493,8 +652,12 @@ _procd_wrapper \
        procd_add_raw_trigger \
        procd_add_config_trigger \
        procd_add_interface_trigger \
+       procd_add_mount_trigger \
        procd_add_reload_trigger \
        procd_add_reload_interface_trigger \
+       procd_add_action_mount_trigger \
+       procd_add_reload_mount_trigger \
+       procd_add_restart_mount_trigger \
        procd_open_trigger \
        procd_close_trigger \
        procd_open_instance \