Fresh pull from upstream
[librecmc/librecmc.git] / package / system / procd / files / procd.sh
1 # procd API:
2 #
3 # procd_open_service(name, [script]):
4 #   Initialize a new procd command message containing a service with one or more instances
5 #
6 # procd_close_service()
7 #   Send the command message for the service
8 #
9 # procd_open_instance([name]):
10 #   Add an instance to the service described by the previous procd_open_service call
11 #
12 # procd_set_param(type, [value...])
13 #   Available types:
14 #     command: command line (array).
15 #     respawn info: array with 3 values $fail_threshold $restart_timeout $max_fail
16 #     env: environment variable (passed to the process)
17 #     data: arbitrary name/value pairs for detecting config changes (table)
18 #     file: configuration files (array)
19 #     netdev: bound network device (detects ifindex changes)
20 #     limits: resource limits (passed to the process)
21 #     user info: array with 1 values $username
22 #     pidfile: file name to write pid into
23 #
24 #   No space separation is done for arrays/tables - use one function argument per command line argument
25 #
26 # procd_close_instance():
27 #   Complete the instance being prepared
28 #
29 # procd_kill(service, [instance]):
30 #   Kill a service instance (or all instances)
31 #
32 # procd_send_signal(service, [instance], [signal])
33 #   Send a signal to a service instance (or all instances)
34 #
35
36 . $IPKG_INSTROOT/usr/share/libubox/jshn.sh
37
38 PROCD_RELOAD_DELAY=1000
39 _PROCD_SERVICE=
40
41 _procd_call() {
42         local old_cb
43
44         json_set_namespace procd old_cb
45         "$@"
46         json_set_namespace $old_cb
47 }
48
49 _procd_wrapper() {
50         while [ -n "$1" ]; do
51                 eval "$1() { _procd_call _$1 \"\$@\"; }"
52                 shift
53         done
54 }
55
56 _procd_ubus_call() {
57         local cmd="$1"
58
59         [ -n "$PROCD_DEBUG" ] && json_dump >&2
60         ubus call service "$cmd" "$(json_dump)"
61         json_cleanup
62 }
63
64 _procd_open_service() {
65         local name="$1"
66         local script="$2"
67
68         _PROCD_SERVICE="$name"
69         _PROCD_INSTANCE_SEQ=0
70
71         json_init
72         json_add_string name "$name"
73         [ -n "$script" ] && json_add_string script "$script"
74         json_add_object instances
75 }
76
77 _procd_close_service() {
78         json_close_object
79         _procd_open_trigger
80         service_triggers
81         _procd_close_trigger
82         _procd_ubus_call ${1:-set}
83 }
84
85 _procd_add_array_data() {
86         while [ "$#" -gt 0 ]; do
87                 json_add_string "" "$1"
88                 shift
89         done
90 }
91
92 _procd_add_array() {
93         json_add_array "$1"
94         shift
95         _procd_add_array_data "$@"
96         json_close_array
97 }
98
99 _procd_add_table_data() {
100         while [ -n "$1" ]; do
101                 local var="${1%%=*}"
102                 local val="${1#*=}"
103                 [ "$1" = "$val" ] && val=
104                 json_add_string "$var" "$val"
105                 shift
106         done
107 }
108
109 _procd_add_table() {
110         json_add_object "$1"
111         shift
112         _procd_add_table_data "$@"
113         json_close_object
114 }
115
116 _procd_open_instance() {
117         local name="$1"; shift
118
119         _PROCD_INSTANCE_SEQ="$(($_PROCD_INSTANCE_SEQ + 1))"
120         name="${name:-instance$_PROCD_INSTANCE_SEQ}"
121         json_add_object "$name"
122         [ -n "$TRACE_SYSCALLS" ] && json_add_boolean trace "1"
123 }
124
125 _procd_open_trigger() {
126         let '_procd_trigger_open = _procd_trigger_open + 1'
127         [ "$_procd_trigger_open" -gt 1 ] && return
128         json_add_array "triggers"
129 }
130
131 _procd_close_trigger() {
132         let '_procd_trigger_open = _procd_trigger_open - 1'
133         [ "$_procd_trigger_open" -lt 1 ] || return
134         json_close_array
135 }
136
137 _procd_open_validate() {
138         json_select ..
139         json_add_array "validate"
140 }
141
142 _procd_close_validate() {
143         json_close_array
144         json_select triggers
145 }
146
147 _procd_add_jail() {
148         json_add_object "jail"
149         json_add_string name "$1"
150
151         shift
152         
153         for a in $@; do
154                 case $a in
155                 log)    json_add_boolean "log" "1";;
156                 ubus)   json_add_boolean "ubus" "1";;
157                 procfs) json_add_boolean "procfs" "1";;
158                 sysfs)  json_add_boolean "sysfs" "1";;
159                 ronly)  json_add_boolean "ronly" "1";;
160                 esac
161         done
162         json_add_object "mount"
163         json_close_object
164         json_close_object
165 }
166
167 _procd_add_jail_mount() {
168         local _json_no_warning=1
169
170         json_select "jail"
171         [ $? = 0 ] || return
172         json_select "mount"
173         [ $? = 0 ] || {
174                 json_select ..
175                 return
176         }
177         for a in $@; do
178                 json_add_string "$a" "0"
179         done
180         json_select ..
181         json_select ..
182 }
183
184 _procd_add_jail_mount_rw() {
185         local _json_no_warning=1
186
187         json_select "jail"
188         [ $? = 0 ] || return
189         json_select "mount"
190         [ $? = 0 ] || {
191                 json_select ..
192                 return
193         }
194         for a in $@; do
195                 json_add_string "$a" "1"
196         done
197         json_select ..
198         json_select ..
199 }
200
201 _procd_set_param() {
202         local type="$1"; shift
203
204         case "$type" in
205                 env|data|limits)
206                         _procd_add_table "$type" "$@"
207                 ;;
208                 command|netdev|file|respawn|watch)
209                         _procd_add_array "$type" "$@"
210                 ;;
211                 error)
212                         json_add_array "$type"
213                         json_add_string "" "$@"
214                         json_close_array
215                 ;;
216                 nice|reload_signal)
217                         json_add_int "$type" "$1"
218                 ;;
219                 pidfile|user|seccomp|capabilities)
220                         json_add_string "$type" "$1"
221                 ;;
222                 stdout|stderr|no_new_privs)
223                         json_add_boolean "$type" "$1"
224                 ;;
225         esac
226 }
227
228 _procd_add_timeout() {
229         [ "$PROCD_RELOAD_DELAY" -gt 0 ] && json_add_int "" "$PROCD_RELOAD_DELAY"
230         return 0
231 }
232
233 _procd_add_interface_trigger() {
234         json_add_array
235         _procd_add_array_data "$1"
236         shift
237
238         json_add_array
239         _procd_add_array_data "if"
240
241         json_add_array
242         _procd_add_array_data "eq" "interface" "$1"
243         shift
244         json_close_array
245
246         json_add_array
247         _procd_add_array_data "run_script" "$@"
248         json_close_array
249
250         json_close_array
251         json_close_array
252
253         _procd_add_timeout
254 }
255
256 _procd_add_reload_interface_trigger() {
257         local script=$(readlink "$initscript")
258         local name=$(basename ${script:-$initscript})
259
260         _procd_open_trigger
261         _procd_add_interface_trigger "interface.*" $1 /etc/init.d/$name reload
262         _procd_close_trigger
263 }
264
265 _procd_add_config_trigger() {
266         json_add_array
267         _procd_add_array_data "$1"
268         shift
269
270         json_add_array
271         _procd_add_array_data "if"
272
273         json_add_array
274         _procd_add_array_data "eq" "package" "$1"
275         shift
276         json_close_array
277
278         json_add_array
279         _procd_add_array_data "run_script" "$@"
280         json_close_array
281
282         json_close_array
283
284         json_close_array
285
286         _procd_add_timeout
287 }
288
289 _procd_add_raw_trigger() {
290         json_add_array
291         _procd_add_array_data "$1"
292         shift
293         local timeout=$1
294         shift
295
296         json_add_array
297         json_add_array
298         _procd_add_array_data "run_script" "$@"
299         json_close_array
300         json_close_array
301
302         json_add_int "" "$timeout"
303
304         json_close_array
305 }
306
307 _procd_add_reload_trigger() {
308         local script=$(readlink "$initscript")
309         local name=$(basename ${script:-$initscript})
310         local file
311
312         _procd_open_trigger
313         for file in "$@"; do
314                 _procd_add_config_trigger "config.change" "$file" /etc/init.d/$name reload
315         done
316         _procd_close_trigger
317 }
318
319 _procd_add_validation() {
320         _procd_open_validate
321         $@
322         _procd_close_validate
323 }
324
325 _procd_append_param() {
326         local type="$1"; shift
327         local _json_no_warning=1
328
329         json_select "$type"
330         [ $? = 0 ] || {
331                 _procd_set_param "$type" "$@"
332                 return
333         }
334         case "$type" in
335                 env|data|limits)
336                         _procd_add_table_data "$@"
337                 ;;
338                 command|netdev|file|respawn|watch)
339                         _procd_add_array_data "$@"
340                 ;;
341                 error)
342                         json_add_string "" "$@"
343                 ;;
344         esac
345         json_select ..
346 }
347
348 _procd_close_instance() {
349         local respawn_vals
350         _json_no_warning=1
351         if json_select respawn ; then
352                 json_get_values respawn_vals
353                 if [ -z "$respawn_vals" ]; then
354                         local respawn_retry=$(uci_get system.@service[0].respawn_retry)
355                         _procd_add_array_data 3600 5 ${respawn_retry:-5}
356                 fi
357                 json_select ..
358         fi
359
360         json_close_object
361 }
362
363 _procd_add_instance() {
364         _procd_open_instance
365         _procd_set_param command "$@"
366         _procd_close_instance
367 }
368
369 _procd_kill() {
370         local service="$1"
371         local instance="$2"
372
373         json_init
374         [ -n "$service" ] && json_add_string name "$service"
375         [ -n "$instance" ] && json_add_string instance "$instance"
376         _procd_ubus_call delete
377 }
378
379 _procd_send_signal() {
380         local service="$1"
381         local instance="$2"
382         local signal="$3"
383
384         json_init
385         json_add_string name "$service"
386         [ -n "$instance" -a "$instance" != "*" ] && json_add_string instance "$instance"
387         [ -n "$signal" ] && json_add_int signal "$signal"
388         _procd_ubus_call signal
389 }
390
391 procd_open_data() {
392         local name="$1"
393         json_set_namespace procd __procd_old_cb
394         json_add_object data
395 }
396
397 procd_close_data() {
398         json_close_object
399         json_set_namespace $__procd_old_cb
400 }
401
402 _procd_set_config_changed() {
403         local package="$1"
404
405         json_init
406         json_add_string type config.change
407         json_add_object data
408         json_add_string package "$package"
409         json_close_object
410
411         ubus call service event "$(json_dump)"
412 }
413
414 procd_add_mdns_service() {
415         local service proto port
416         service=$1; shift
417         proto=$1; shift
418         port=$1; shift
419         json_add_object "${service}_$port"
420         json_add_string "service" "_$service._$proto.local"
421         json_add_int port "$port"
422         [ -n "$1" ] && {
423                 json_add_array txt
424                 for txt in $@; do json_add_string "" $txt; done
425                 json_select ..
426         }
427         json_select ..
428 }
429
430 procd_add_mdns() {
431         procd_open_data
432         json_add_object "mdns"
433         procd_add_mdns_service $@
434         json_close_object
435         procd_close_data
436 }
437
438 uci_validate_section()
439 {
440         local _package="$1"
441         local _type="$2"
442         local _name="$3"
443         local _result
444         local _error
445         shift; shift; shift
446         _result=`/sbin/validate_data "$_package" "$_type" "$_name" "$@" 2> /dev/null`
447         _error=$?
448         eval "$_result"
449         [ "$_error" = "0" ] || `/sbin/validate_data "$_package" "$_type" "$_name" "$@" 1> /dev/null`
450         return $_error
451 }
452
453 _procd_wrapper \
454         procd_open_service \
455         procd_close_service \
456         procd_add_instance \
457         procd_add_raw_trigger \
458         procd_add_config_trigger \
459         procd_add_interface_trigger \
460         procd_add_reload_trigger \
461         procd_add_reload_interface_trigger \
462         procd_open_trigger \
463         procd_close_trigger \
464         procd_open_instance \
465         procd_close_instance \
466         procd_open_validate \
467         procd_close_validate \
468         procd_add_jail \
469         procd_add_jail_mount \
470         procd_add_jail_mount_rw \
471         procd_set_param \
472         procd_append_param \
473         procd_add_validation \
474         procd_set_config_changed \
475         procd_kill \
476         procd_send_signal