mini_snmpd.init 9.8 KB

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