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
8 PROG
=/usr
/bin
/mini_snmpd
12 logger
-p daemon.info
-t mini_snmpd
"$@"
16 logger
-p daemon.err
-t mini_snmpd
"$@"
20 # mini_snmpd 1.3+ now starts later in the game. Expects filesystems monitored to be already mounted, or wont pass args to mini_snmpd
21 # and at least configuration entry for network physical interface defined in /etc/config/network
22 # It handles network interfaces not yet present (e.g. ppp) but will statfs() the root/wrong filesystem if device not mounted
23 # Tip: complex scripts run faster without in openwrt if you stop busybox forking and searching for applets. Faster bootups
24 # CONFIG_BUSYBOX_CONFIG_FEATURE_SH_NOFORK
25 # CONFIG_BUSYBOX_CONFIG_FEATURE_PREFER_APPLETS
26 # BUSYBOX_CONFIG_ASH_OPTIMIZE_FOR_SIZE [=n]
27 # CONFIG_BUSYBOX_CONFIG_ASH_CMDCMD
29 mini_snmpd_validation
="enabled:bool:0 \
33 community:rangelength(1,32):public \
34 contact:maxlength(255) \
35 location:maxlength(255) \
36 listen_interface:uciname \
40 mib_timeout:and(min(1),uinteger) \
41 disks:list(directory) \
42 interfaces:list(uciname) \
43 respawn_threshold:uinteger respawn_timeout:uinteger respawn_retry:uinteger"
44 # busybox ash has no array variable support, when put validations in a string be careful to have no spaces in each validate constraint
45 # this makes it very difficult to use the 'or(uciname, "all")' test, so listen_interface '' or undefined now meands bind to "all".
46 # 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
50 local disk
="$1" disk_count
51 [ -z $disk_count ] && disk_count
=0
52 if grep -qF "$disk" /proc
/mounts
; then
53 # check the fileystem is mountpoint, and directory search permissions available for statfs()
54 # presence as a directory -d test done is already done by uci_validate_section()
56 _err
"$cfg: mountpoint $disk for snmp monitoring EACCES error. Check permissions, ignoring"
59 if [ $disk_count -lt 4 ] ; then
60 append disks_arg
"$disk" ','
61 disk_count
=$
((disk_count
++))
63 _err
"$cfg: more than 4 mountpoints defined in uci. Disc $disk ignored."
66 _err
"$cfg: mountpoint $disk for snmp monitoring not mounted, ignoring."
71 local name
="$1" netdev netdev_count
72 [ -z $netdev_count ] && netdev_count
=0
73 # for the purposes of snmp monitoring it doesn't need to be up, it just needs to exist in /proc/net/dev
74 netdev
=$
(ubus
-S call network.interface dump|jsonfilter
-e "@.interface[@.interface=\"$name\"].l3_device")
75 if [ -n "$netdev" ] && grep -qF "$netdev" /proc
/net
/dev
]; then
76 [ $netdev_count -ge 4 ] && {
77 _err
"$cfg: too many network interfaces configured, ignoring $name"
80 netdev_count
=$
((netdev_count
++))
81 if [ -n "$interfaces_arg" ]; then
82 append interfaces_arg
"$netdev" ','
84 append interfaces_arg
"$netdev"
87 _err
"$cfg: physical interface for network $name not found in uci or kernel so not monitoring"
94 [ -n "$var" ] && procd_append_param
command $opt "$var"
99 local enabled listen_interface
# listen_interface_up
100 config_get_bool enabled
"$cfg" "enabled" '1'
101 [ "$enabled" -gt 0 ] ||
return 0
102 config_get listen_interface
"$cfg" listen_interface
103 # listen_interface_up=$(ubus -S call network.interface dump | jsonfilter -e "@.interface[@.interface=\"$listen_interface\"].up")
104 # 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
105 # Regardless of ubus knowing about an interface (in the case it's not yet configured)
106 [ -n "$listen_interface" ] && trigger_interfaces
="${listen_interface} ${trigger_interfaces} "
109 validate_mini_snmpd_section
() {
110 # validate a mini_snmpd instance in uci config file mini_snmpd
111 # http://luci.subsignal.org/trac/wiki/Documentation/Datatypes ubox/validate/validate.c
112 uci_validate_section mini_snmpd mini_snmpd
"${1}" $mini_snmpd_validation
117 config_load
'mini_snmpd'
119 procd_add_config_trigger
"config.change" "mini_snmpd" /etc
/init.d
/mini_snmpd reload
120 config_foreach watch_interfaces
'mini_snmpd'
121 # this only watches interfaces for which there is no running instance due to interface down / not in ubus
122 # hence start not reload, this trigger will not affect running instances as another start will not change their procd command arguments
123 # or stop the already running process
124 [ -n "$trigger_interfaces" ] & {
125 for n
in $trigger_interfaces ; do
126 procd_add_interface_trigger
"interface.*" $n /etc
/init.d
/mini_snmpd start
130 procd_add_validation validate_mini_snmpd_section
135 local cfg validation_failed validation_err disks_arg interfaces_arg
137 #uci_validate_section should unset undefined variables from other instances
138 #however defining uci variables as local will scope them to this instance
139 #"local variables are also visible to functions called by the parent function" so it's good practice
140 local enabled ipv6 debug auth community contact location listen_interface \
141 udp_port tcp_port vendor_oid mib_timeout
142 local disks
="" interfaces
=""
143 validate_mini_snmpd_section
"$cfg" 2>/dev
/null || validation_failed
=1
144 [ "$enabled" == 1 ] ||
{
145 _log
"instance:$cfg disabled not starting"
149 local listen_interface_json listen_interface_ip listen_interface_device listen_interface_up ubus_exit ubus_err
150 [ -n "$listen_interface" ] && {
151 listen_interface_json
=$
(ubus
-S call network.interface.
$listen_interface status
)
153 [ $ubus_exit = 4 ] && {
154 _err
"$cfg: listen_interface $listen_interface not properly configured in ubus network.interface.* not starting this instance "
157 [ $ubus_exit = 255 -a -z "$listen_interface_json" ] && {
158 _log
"$cfg: ubusd not yet up, will try to start mini_snmpd shorlty when procd detects $listen_interface comes up"
161 [ -z "$listen_interface_json" ] && {
162 ubus_err
=`ubus call network.interface.$listen_interface status 2>&1 >/dev/null`
163 _err
"$cfg: unknown ubus error. exit: $ubus_exit errormsg: $ubus_err "
166 listen_interface_up
=$
(jsonfilter
-s "$listen_interface_json" -e '@.up')
167 if [ "$ipv6" = 1 ]; then
168 listen_interface_ip
=$
(jsonfilter
-s "$listen_interface_json" -e "@['ipv6-address'][0].address")
170 listen_interface_ip
=$
(jsonfilter
-s "$listen_interface_json" -e "@['ipv4-address'][0].address")
172 [ -n "$listen_interface_ip" -a "$listen_interface_up" = 'true' ] ||
{
173 _log
"$cfg:listen interface $listen_interface not up yet / not configured properly"
174 _log
"$cfg:procd will try again when interface state changes"
177 listen_interface_device
=$
(jsonfilter
-s "$listen_interface_json" -e '@.l3_device')
180 [ $validation_failed ] && {
181 _err
"validation of $NAME configuration for $cfg instance failed, all tests should be within constraints"
182 _err
"please edit the configuration values below using [l]uci "
183 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//' `
184 _err
"${validation_err}"
187 config_list_foreach
"$cfg" 'disks' append_disk
188 config_list_foreach
"$cfg" 'interfaces' append_interface
189 # test if variables are unset or zero length
190 [ -z "${disks_arg:+1}" -a -z "${interfaces_arg:+1}" ] && {
191 _err
"$cfg: you haven't sucessfully configured any mountpoints or disks for this instance, not starting"
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 left 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" ] && {
206 #procd_add_interface_trigger "interface.*" $listen_interface /etc/init.d/mini_snmpd reload
208 procd_add_reload_interface_trigger
$listen_interface #or use shorthand of above
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"
213 append_arg
"-c" "$community"
214 append_arg
"-L" "${location}"
215 append_arg
"-C" "${contact}"
216 append_arg
"-p" $udp_port
217 append_arg
"-P" $tcp_port
218 append_arg
"-V" "${vendor_oid}"
219 append_arg
"-t" $mib_timeout
221 [ "$ipv6" = 1 ] && procd_append_param
command "-6"
222 [ "$debug" = 1 ] && procd_append_param
command "-v"
223 # uci_validate_section() aka /sbin/validate_data can only cast default values not defined in /etc/config/* to string
224 # e.g. ="1" however it sets bools defined in /etc/config/* to =1 / =0
225 [ "$auth" = 1 -o "$auth" = "1" ] && procd_append_param
command "-a"
226 [ -n "$disks_arg" ] && procd_append_param
command "-d $disks_arg"
227 [ -n "$interfaces_arg" ] && procd_append_param
command "-i $interfaces_arg"
228 [ -n "$listen_interface_device" ] && {
229 procd_append_param
command "-I" "$listen_interface_device"
230 # and this monitors the hardware device for changes outside of ubus - just a guess
231 procd_set_param netdev
$listen_interface_device
237 config_load
'mini_snmpd'
238 config_foreach start_instance
'mini_snmpd'