fc61fc0a0d9e3a3a546778a24a453e58204132f5
[feed/packages.git] / net / mini_snmpd / files / mini_snmpd.init
1 #!/bin/sh /etc/rc.common
2 # Copyright (C) 2009-2016 OpenWrt.org
3 # Copyright (C) 2016 Luke McKee <hojuruku@gmail.com>
4 # Procd init script reference: http://wiki.prplfoundation.org/wiki/Procd_reference
5
6 START=98
7 USE_PROCD=1
8 PROG=/usr/bin/mini_snmpd
9 NAME=mini_snmpd
10
11 global_respawn_threshold=
12 global_respawn_timeout=
13 global_respawn_retry=
14
15 _log() {
16 logger -p daemon.info -t mini_snmpd "$@"
17 }
18
19 _err() {
20 logger -p daemon.err -t mini_snmpd "$@"
21 }
22
23
24 # mini_snmpd 1.3+ now starts later in the game. Expects filesystems monitored to be already mounted, or wont pass args to mini_snmpd
25 # and at least configuration entry for network physical interface defined in /etc/config/network
26 # It handles network interfaces not yet present (e.g. ppp) but will statfs() the root/wrong filesystem if device not mounted
27 # Tip: complex scripts run faster without in openwrt if you stop busybox forking and searching for applets. Faster bootups
28 # CONFIG_BUSYBOX_CONFIG_FEATURE_SH_NOFORK
29 # CONFIG_BUSYBOX_CONFIG_FEATURE_PREFER_APPLETS
30 # BUSYBOX_CONFIG_ASH_OPTIMIZE_FOR_SIZE [=n]
31 # CONFIG_BUSYBOX_CONFIG_ASH_CMDCMD
32
33 mini_snmpd_validation="enabled:bool:0 \
34 ipv6:bool:0 \
35 debug:bool:0 \
36 auth:bool:1 \
37 community:rangelength(1,32):public \
38 contact:maxlength(255) \
39 description:maxlength(255) \
40 location:maxlength(255) \
41 listen_interface:uciname \
42 udp_port:port \
43 tcp_port:port \
44 vendor_oid:string \
45 mib_timeout:and(min(1),uinteger) \
46 disks:list(directory) \
47 interfaces:list(uciname) \
48 respawn_threshold:uinteger respawn_timeout:uinteger respawn_retry:uinteger"
49 # busybox ash has no array variable support, when put validations in a string be careful to have no spaces in each validate constraint
50 # this makes it very difficult to use the 'or(uciname, "all")' test, so listen_interface '' or undefined now meands bind to "all".
51 # this is the sarafice you have to make to avoid typing it all in twice in this script so we can give feedback to user on what's misconfigered
52 # in syslog
53
54 append_disk() {
55 local disk="$1" disk_count
56 [ -z $disk_count ] && disk_count=0
57 if grep -qF "$disk" /proc/mounts; then
58 # check the fileystem is mountpoint, and directory search permissions available for statfs()
59 # presence as a directory -d test done is already done by uci_validate_section()
60 [ -x "$disk" ] || {
61 _err "$cfg: mountpoint $disk for snmp monitoring EACCES error. Check permissions, ignoring"
62 return 1
63 }
64 if [ $disk_count -lt 4 ]; then
65 append disks_arg "$disk" ','
66 disk_count=$((disk_count++))
67 else
68 _err "$cfg: more than 4 mountpoints defined in uci. Disc $disk ignored."
69 fi
70 else
71 _err "$cfg: mountpoint $disk for snmp monitoring not mounted, ignoring."
72 fi
73 }
74
75 append_interface() {
76 local name="$1" netdev netdev_count
77 [ -z $netdev_count ] && netdev_count=0
78 # for the purposes of snmp monitoring it doesn't need to be up, it just needs to exist in /proc/net/dev
79 network_get_device netdev "$name"
80 if [ -n "$netdev" ] && grep -qF "$netdev" /proc/net/dev; then
81 [ $netdev_count -ge 8 ] && {
82 _err "$cfg: too many network interfaces configured, ignoring $name"
83 return
84 }
85 netdev_count=$((netdev_count++))
86 if [ -n "$interfaces_arg" ]; then
87 append interfaces_arg "$netdev" ','
88 else
89 append interfaces_arg "$netdev"
90 fi
91 else
92 _log "$cfg: physical interface for network $name not found in uci or kernel so not monitoring"
93 fi
94 }
95
96 append_arg() {
97 local var="$2"
98 local opt="$1"
99 [ -n "$var" ] && procd_append_param command $opt "$var"
100 }
101
102 watch_interfaces() {
103 local cfg="$1"
104 local enabled listen_interface # listen_interface_up
105 config_get_bool enabled "$cfg" "enabled" '1'
106 [ "$enabled" -gt 0 ] || return 0
107 config_get listen_interface "$cfg" listen_interface
108 # If the interface is up & instance is running we'll watch at the instance level and only restart that instance if it's bound interface changes
109 # Regardless of ubus knowing about an interface (in the case it's not yet configured)
110 [ -n "$listen_interface" ] && trigger_interfaces="$listen_interface $trigger_interfaces"
111 # Restart daemon if one of monitored interfaces changes
112 config_get reload_interfaces "$cfg" interfaces
113 }
114
115 validate_mini_snmpd_section() {
116 # validate a mini_snmpd instance in uci config file mini_snmpd
117 # http://luci.subsignal.org/trac/wiki/Documentation/Datatypes ubox/validate/validate.c
118 uci_load_validate mini_snmpd mini_snmpd "$1" "$2" $mini_snmpd_validation
119 }
120
121
122 service_triggers() {
123 config_load 'mini_snmpd'
124 procd_open_trigger
125 procd_add_config_trigger "config.change" "mini_snmpd" /etc/init.d/mini_snmpd reload
126 config_foreach watch_interfaces 'mini_snmpd'
127 # this only watches interfaces for which there is no running instance due to interface down / not in ubus
128 # hence start not reload, this trigger will not affect running instances as another start will not change their procd command arguments
129 # or stop the already running process
130 [ -n "$trigger_interfaces" ] && {
131 for n in $trigger_interfaces; do
132 procd_add_interface_trigger "interface.*" $n /etc/init.d/mini_snmpd start
133 done
134 }
135 [ -n "$reload_interfaces" ] && {
136 for n in $reload_interfaces; do
137 procd_add_reload_interface_trigger $n
138 done
139 }
140 procd_close_trigger
141 procd_add_validation validate_mini_snmpd_section
142 }
143
144
145 start_instance() {
146 local cfg validation_failed validation_err disks_arg interfaces_arg
147 cfg="$1"
148 [ "$2" = 0 ] || validation_failed=1
149 [ "$enabled" == 1 ] || {
150 _log "instance:$cfg disabled not starting"
151 return 1
152 }
153
154 local listen_interface_json listen_interface_ip listen_interface_device listen_interface_up
155 [ -n "$listen_interface" ] && {
156 if [ "$ipv6" = 1 ]; then
157 network_get_ipaddrs6 listen_interface_ip "$listen_interface"
158 else
159 network_get_ipaddrs listen_interface_ip "$listen_interface"
160 fi
161 network_is_up "$listen_interface" && [ -n "$listen_interface_ip" ] || {
162 _log "$cfg:listen interface $listen_interface not up yet / not configured properly"
163 _log "$cfg:procd will try again when interface state changes"
164 return 1
165 }
166 network_get_physdev listen_interface_device "$listen_interface"
167 }
168
169 [ $validation_failed ] && {
170 _err "validation of $NAME configuration for $cfg instance failed, all tests should be within constraints"
171 _err "please edit the configuration values below using [l]uci "
172 validation_err=`/sbin/validate_data mini_snmpd mini_snmpd "$cfg" $mini_snmpd_validation 2>&1 | sed '/with\ false$/!d;s/validates\ as\ /needs\ to\ be\ /;s/with\ false//' `
173 _err "$validation_err"
174 return 1
175 }
176 config_list_foreach "$cfg" 'disks' append_disk
177 config_list_foreach "$cfg" 'interfaces' append_interface
178 # test if variables are unset or zero length
179 [ -z "${disks_arg:+1}" -a -z "${interfaces_arg:+1}" ] && {
180 _err "$cfg: you haven't sucessfully configured any mountpoints or disks for this instance, not starting"
181 return 1
182 }
183
184 [ -z "$respawn_threshold$respawn_timeout$respawn_retry" ] && {
185 respawn_threshold=$global_respawn_threshold
186 respawn_timeout=$global_respawn_timeout
187 respawn_retry=$global_respawn_retry
188 }
189 [ -z "$global_respawn_threshold$global_respawn_timeout$global_respawn_retry" ] && {
190 global_respawn_threshold=$respawn_threshold
191 global_respawn_timeout=$respawn_timeout
192 global_respawn_retry=$respawn_retry
193 }
194
195 procd_open_instance
196
197 procd_set_param command "$PROG" -n
198 procd_set_param stdout "1"
199 procd_set_param stderr "1"
200 # don't the like default respawn values? you can override through uci.
201 # vars saved as global so you only need to do it in the first mini_snmpd instance
202 procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-10} ${respawn_retry:-1}
203 # this monitors ubus changes
204 [ -n "$listen_interface" ] && {
205 #procd_open_trigger
206 #procd_add_interface_trigger "interface.*" $listen_interface /etc/init.d/mini_snmpd reload
207 #procd_close_trigger
208 procd_add_reload_interface_trigger $listen_interface #or use shorthand of above
209 }
210 # this re-starts the daemon if a properly configured network interface is changed whilst it is already running
211 # igmpproxy has this as well as "procd_set_param netdev"
212
213 append_arg "-c" "$community"
214 append_arg "-L" "$location"
215 append_arg "-C" "$contact"
216 append_arg "-D" "$description"
217 append_arg "-p" $udp_port
218 append_arg "-P" $tcp_port
219 append_arg "-V" "$vendor_oid"
220 append_arg "-t" $mib_timeout
221
222 [ "$ipv6" = 1 ] && procd_append_param command "-6"
223 [ "$debug" = 1 ] && procd_append_param command "-v"
224 # uci_validate_section() aka /sbin/validate_data can only cast default values not defined in /etc/config/* to string
225 # e.g. ="1" however it sets bools defined in /etc/config/* to =1 / =0
226 [ "$auth" = 1 -o "$auth" = "1" ] && procd_append_param command "-a"
227 [ -n "$disks_arg" ] && procd_append_param command "-d" "$disks_arg"
228 [ -n "$interfaces_arg" ] && {
229 procd_append_param netdev ${interfaces_arg//,/ }
230 procd_append_param command "-i" "$interfaces_arg"
231 }
232 [ -n "$listen_interface_device" ] && {
233 procd_append_param command "-I" "$listen_interface_device"
234 # and this monitors the hardware device for changes outside of ubus - just a guess
235 procd_append_param netdev $listen_interface_device
236 }
237 procd_close_instance
238 }
239
240 start_service() {
241 . /lib/functions.sh
242 . /lib/functions/network.sh
243
244 config_load 'mini_snmpd'
245 config_foreach validate_mini_snmpd_section 'mini_snmpd' start_instance
246 }