mini_snmpd.init (10010B)
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 _log() { 12 logger -p daemon.info -t mini_snmpd "$@" 13 } 14 15 _err() { 16 logger -p daemon.err -t mini_snmpd "$@" 17 } 18 19 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 28 29 mini_snmpd_validation="enabled:bool:0 \ 30 ipv6:bool:0 \ 31 debug:bool:0 \ 32 auth:bool:1 \ 33 community:rangelength(1,32):public \ 34 contact:maxlength(255) \ 35 location:maxlength(255) \ 36 listen_interface:uciname \ 37 udp_port:port \ 38 tcp_port:port \ 39 vendor_oid:string \ 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 47 # in syslog 48 49 append_disk() { 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() 55 [ -x "$disk" ] || { 56 _err "$cfg: mountpoint $disk for snmp monitoring EACCES error. Check permissions, ignoring" 57 return 1 58 } 59 if [ $disk_count -lt 4 ] ; then 60 append disks_arg "$disk" ',' 61 disk_count=$((disk_count++)) 62 else 63 _err "$cfg: more than 4 mountpoints defined in uci. Disc $disk ignored." 64 fi 65 else 66 _err "$cfg: mountpoint $disk for snmp monitoring not mounted, ignoring." 67 fi 68 } 69 70 append_interface() { 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" 78 return 79 } 80 netdev_count=$((netdev_count++)) 81 if [ -n "$interfaces_arg" ]; then 82 append interfaces_arg "$netdev" ',' 83 else 84 append interfaces_arg "$netdev" 85 fi 86 else 87 _err "$cfg: physical interface for network $name not found in uci or kernel so not monitoring" 88 fi 89 } 90 91 append_arg() { 92 local var="$2" 93 local opt="$1" 94 [ -n "$var" ] && procd_append_param command $opt "$var" 95 } 96 97 watch_interfaces() { 98 local cfg="$1" 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} " 107 } 108 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 113 } 114 115 116 service_triggers() { 117 config_load 'mini_snmpd' 118 procd_open_trigger 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 127 done 128 } 129 procd_close_trigger 130 procd_add_validation validate_mini_snmpd_section 131 } 132 133 134 start_instance() { 135 local cfg validation_failed validation_err disks_arg interfaces_arg 136 cfg="$1" 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" 146 return 1 147 } 148 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) 152 ubus_exit=$? 153 [ $ubus_exit = 4 ] && { 154 _err "$cfg: listen_interface $listen_interface not properly configured in ubus network.interface.* not starting this instance " 155 return 1 156 } 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" 159 return 1 160 } 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 " 164 return 1 165 } 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") 169 else 170 listen_interface_ip=$(jsonfilter -s "$listen_interface_json" -e "@['ipv4-address'][0].address") 171 fi 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" 175 return 1 176 } 177 listen_interface_device=$(jsonfilter -s "$listen_interface_json" -e '@.l3_device') 178 } 179 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}" 185 return 1 186 } 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" 192 return 1 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 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" ] && { 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 "-p" $udp_port 217 append_arg "-P" $tcp_port 218 append_arg "-V" "${vendor_oid}" 219 append_arg "-t" $mib_timeout 220 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 232 } 233 procd_close_instance 234 } 235 236 start_service() { 237 config_load 'mini_snmpd' 238 config_foreach start_instance 'mini_snmpd' 239 } 240