|
|
@ -1,65 +1,240 @@ |
|
|
|
#!/bin/sh /etc/rc.common |
|
|
|
# Copyright (C) 2009-2012 OpenWrt.org |
|
|
|
# Copyright (C) 2009-2016 OpenWrt.org |
|
|
|
# Copyright (C) 2016 Luke McKee <hojuruku@gmail.com> |
|
|
|
# Procd init script reference: http://wiki.prplfoundation.org/wiki/Procd_reference |
|
|
|
|
|
|
|
START=50 |
|
|
|
START=98 |
|
|
|
USE_PROCD=1 |
|
|
|
PROG=/usr/bin/mini_snmpd |
|
|
|
NAME=mini_snmpd |
|
|
|
|
|
|
|
SERVICE_DAEMONIZE=1 |
|
|
|
SERVICE_WRITE_PID=1 |
|
|
|
_log() { |
|
|
|
logger -p daemon.info -t mini_snmpd "$@" |
|
|
|
} |
|
|
|
|
|
|
|
_err() { |
|
|
|
logger -p daemon.err -t mini_snmpd "$@" |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
# mini_snmpd 1.3+ now starts later in the game. Expects filesystems monitored to be already mounted, or wont pass args to mini_snmpd |
|
|
|
# and at least configuration entry for network physical interface defined in /etc/config/network |
|
|
|
# It handles network interfaces not yet present (e.g. ppp) but will statfs() the root/wrong filesystem if device not mounted |
|
|
|
# Tip: complex scripts run faster without in openwrt if you stop busybox forking and searching for applets. Faster bootups |
|
|
|
# CONFIG_BUSYBOX_CONFIG_FEATURE_SH_NOFORK |
|
|
|
# CONFIG_BUSYBOX_CONFIG_FEATURE_PREFER_APPLETS |
|
|
|
# BUSYBOX_CONFIG_ASH_OPTIMIZE_FOR_SIZE [=n] |
|
|
|
# CONFIG_BUSYBOX_CONFIG_ASH_CMDCMD |
|
|
|
|
|
|
|
mini_snmpd_validation="enabled:bool:0 \ |
|
|
|
ipv6:bool:0 \ |
|
|
|
debug:bool:0 \ |
|
|
|
auth:bool:1 \ |
|
|
|
community:rangelength(1,32):public \ |
|
|
|
contact:maxlength(255) \ |
|
|
|
location:maxlength(255) \ |
|
|
|
listen_interface:uciname \ |
|
|
|
udp_port:port \ |
|
|
|
tcp_port:port \ |
|
|
|
vendor_oid:string \ |
|
|
|
mib_timeout:and(min(1),uinteger) \ |
|
|
|
disks:list(directory) \ |
|
|
|
interfaces:list(uciname) \ |
|
|
|
respawn_threshold:uinteger respawn_timeout:uinteger respawn_retry:uinteger" |
|
|
|
# busybox ash has no array variable support, when put validations in a string be careful to have no spaces in each validate constraint |
|
|
|
# this makes it very difficult to use the 'or(uciname, "all")' test, so listen_interface '' or undefined now meands bind to "all". |
|
|
|
# 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 |
|
|
|
# in syslog |
|
|
|
|
|
|
|
append_disk() { |
|
|
|
local disk="$1" |
|
|
|
append disks "$disk" ',' |
|
|
|
local disk="$1" disk_count |
|
|
|
[ -z $disk_count ] && disk_count=0 |
|
|
|
if grep -qF "$disk" /proc/mounts ; then |
|
|
|
# check the fileystem is mountpoint, and directory search permissions available for statfs() |
|
|
|
# presence as a directory -d test done is already done by uci_validate_section() |
|
|
|
[ -x "$disk" ] || { |
|
|
|
_err "$cfg: mountpoint $disk for snmp monitoring EACCES error. Check permissions, ignoring" |
|
|
|
return 1 |
|
|
|
} |
|
|
|
if [ $disk_count -lt 4 ] ; then |
|
|
|
append disks_arg "$disk" ',' |
|
|
|
disk_count=$((disk_count++)) |
|
|
|
else |
|
|
|
_err "$cfg: more than 4 mountpoints defined in uci. Disc $disk ignored." |
|
|
|
fi |
|
|
|
else |
|
|
|
_err "$cfg: mountpoint $disk for snmp monitoring not mounted, ignoring." |
|
|
|
fi |
|
|
|
} |
|
|
|
|
|
|
|
append_interface() { |
|
|
|
local name="$1" |
|
|
|
local device |
|
|
|
network_get_device device "$name" |
|
|
|
append interfaces "${device:-$name}" ',' |
|
|
|
local name="$1" netdev netdev_count |
|
|
|
[ -z $netdev_count ] && netdev_count=0 |
|
|
|
# for the purposes of snmp monitoring it doesn't need to be up, it just needs to exist in /proc/net/dev |
|
|
|
netdev=$(ubus -S call network.interface dump|jsonfilter -e "@.interface[@.interface=\"$name\"].device") |
|
|
|
if [ -n "$netdev" ] && grep -qF "$netdev" /proc/net/dev ]; then |
|
|
|
[ $netdev_count -ge 4 ] && { |
|
|
|
_err "$cfg: too many network interfaces configured, ignoring $name" |
|
|
|
return |
|
|
|
} |
|
|
|
netdev_count=$((netdev_count++)) |
|
|
|
if [ -n "$interfaces_arg" ]; then |
|
|
|
append interfaces_arg "$netdev" ',' |
|
|
|
else |
|
|
|
append interfaces_arg "$netdev" |
|
|
|
fi |
|
|
|
else |
|
|
|
_err "$cfg: physical interface for network $name not found in uci or kernel so not monitoring" |
|
|
|
fi |
|
|
|
} |
|
|
|
|
|
|
|
append_string() { |
|
|
|
local section="$1" |
|
|
|
local option="$2" |
|
|
|
local value="$3" |
|
|
|
local _val |
|
|
|
config_get _val "$section" "$option" |
|
|
|
[ -n "$_val" ] && append args "$3 $_val" |
|
|
|
append_arg() { |
|
|
|
local var="$2" |
|
|
|
local opt="$1" |
|
|
|
[ -n "$var" ] && procd_append_param command $opt "$var" |
|
|
|
} |
|
|
|
|
|
|
|
start_instance() { |
|
|
|
watch_interfaces() { |
|
|
|
local cfg="$1" |
|
|
|
local args="" |
|
|
|
local disks="" |
|
|
|
local interfaces="" |
|
|
|
local ipv6 |
|
|
|
local enabled listen_interface # listen_interface_up |
|
|
|
config_get_bool enabled "$cfg" "enabled" '1' |
|
|
|
[ "$enabled" -gt 0 ] || return 0 |
|
|
|
config_get listen_interface "$cfg" listen_interface |
|
|
|
# listen_interface_up=$(ubus -S call network.interface dump | jsonfilter -e "@.interface[@.interface=\"$listen_interface\"].up") |
|
|
|
# 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 |
|
|
|
# Regardless of ubus knowing about an interface (in the case it's not yet configured) |
|
|
|
[ -n "$listen_interface" ] && trigger_interfaces="${listen_interface} ${trigger_interfaces} " |
|
|
|
} |
|
|
|
|
|
|
|
append_string "$cfg" community "-c" |
|
|
|
append_string "$cfg" location "-L" |
|
|
|
append_string "$cfg" contact "-C" |
|
|
|
validate_mini_snmpd_section() { |
|
|
|
# validate a mini_snmpd instance in uci config file mini_snmpd |
|
|
|
# http://luci.subsignal.org/trac/wiki/Documentation/Datatypes ubox/validate/validate.c |
|
|
|
uci_validate_section mini_snmpd mini_snmpd "${1}" $mini_snmpd_validation |
|
|
|
} |
|
|
|
|
|
|
|
config_get_bool ipv6 "$cfg" "ipv6" '0' |
|
|
|
[ "$ipv6" -gt 0 ] && append args "-6" |
|
|
|
|
|
|
|
config_get_bool enabled "$cfg" "enabled" '1' |
|
|
|
[ "$enabled" -gt 0 ] || return 1 |
|
|
|
service_triggers() { |
|
|
|
config_load 'mini_snmpd' |
|
|
|
procd_open_trigger |
|
|
|
procd_add_config_trigger "config.change" "mini_snmpd" /etc/init.d/mini_snmpd reload |
|
|
|
config_foreach watch_interfaces 'mini_snmpd' |
|
|
|
# this only watches interfaces for which there is no running instance due to interface down / not in ubus |
|
|
|
# hence start not reload, this trigger will not affect running instances as another start will not change their procd command arguments |
|
|
|
# or stop the already running process |
|
|
|
[ -n "$trigger_interfaces" ] & { |
|
|
|
for n in $trigger_interfaces ; do |
|
|
|
procd_add_interface_trigger "interface.*" $n /etc/init.d/mini_snmpd start |
|
|
|
done |
|
|
|
} |
|
|
|
procd_close_trigger |
|
|
|
procd_add_validation validate_mini_snmpd_section |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
config_list_foreach "$section" 'disks' append_disk |
|
|
|
args="${args}${disks:+ -d $disks}" |
|
|
|
start_instance() { |
|
|
|
local cfg validation_failed validation_err disks_arg interfaces_arg |
|
|
|
cfg="$1" |
|
|
|
#uci_validate_section should unset undefined variables from other instances |
|
|
|
#however defining uci variables as local will scope them to this instance |
|
|
|
#"local variables are also visible to functions called by the parent function" so it's good practice |
|
|
|
local enabled ipv6 debug auth community contact location listen_interface \ |
|
|
|
udp_port tcp_port vendor_oid mib_timeout |
|
|
|
local disks="" interfaces="" |
|
|
|
validate_mini_snmpd_section "$cfg" 2>/dev/null || validation_failed=1 |
|
|
|
[ "$enabled" == 1 ] || { |
|
|
|
_log "instance:$cfg disabled not starting" |
|
|
|
return 1 |
|
|
|
} |
|
|
|
|
|
|
|
local listen_interface_json listen_interface_ip listen_interface_device listen_interface_up ubus_exit ubus_err |
|
|
|
[ -n "$listen_interface" ] && { |
|
|
|
listen_interface_json=$(ubus -S call network.interface.$listen_interface status) |
|
|
|
ubus_exit=$? |
|
|
|
[ $ubus_exit = 4 ] && { |
|
|
|
_err "$cfg: listen_interface $listen_interface not properly configured in ubus network.interface.* not starting this instance " |
|
|
|
return 1 |
|
|
|
} |
|
|
|
[ $ubus_exit = 255 -a -z "$listen_interface_json" ] && { |
|
|
|
_log "$cfg: ubusd not yet up, will try to start mini_snmpd shorlty when procd detects $listen_interface comes up" |
|
|
|
return 1 |
|
|
|
} |
|
|
|
[ -z "$listen_interface_json" ] && { |
|
|
|
ubus_err=`ubus call network.interface.$listen_interface status 2>&1 >/dev/null` |
|
|
|
_err "$cfg: unknown ubus error. exit: $ubus_exit errormsg: $ubus_err " |
|
|
|
return 1 |
|
|
|
} |
|
|
|
listen_interface_up=$(jsonfilter -s "$listen_interface_json" -e '@.up') |
|
|
|
if [ "$ipv6" = 1 ]; then |
|
|
|
listen_interface_ip=$(jsonfilter -s "$listen_interface_json" -e "@['ipv6-address'][0].address") |
|
|
|
else |
|
|
|
listen_interface_ip=$(jsonfilter -s "$listen_interface_json" -e "@['ipv4-address'][0].address") |
|
|
|
fi |
|
|
|
[ -n "$listen_interface_ip" -a "$listen_interface_up" = 'true' ] || { |
|
|
|
_log "$cfg:listen interface $listen_interface not up yet / not configured properly" |
|
|
|
_log "$cfg:procd will try again when interface state changes" |
|
|
|
return 1 |
|
|
|
} |
|
|
|
listen_interface_device=$(jsonfilter -s "$listen_interface_json" -e '@.l3_device') |
|
|
|
} |
|
|
|
|
|
|
|
config_list_foreach "$section" 'interfaces' append_interface |
|
|
|
args="${args}${interfaces:+ -i $interfaces}" |
|
|
|
[ $validation_failed ] && { |
|
|
|
_err "validation of $NAME configuration for $cfg instance failed, all tests should be within constraints" |
|
|
|
_err "please edit the configuration values below using [l]uci " |
|
|
|
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//' ` |
|
|
|
_err "${validation_err}" |
|
|
|
return 1 |
|
|
|
} |
|
|
|
config_list_foreach "$cfg" 'disks' append_disk |
|
|
|
config_list_foreach "$cfg" 'interfaces' append_interface |
|
|
|
# test if variables are unset or zero length |
|
|
|
[ -z "${disks_arg:+1}" -a -z "${interfaces_arg:+1}" ] && { |
|
|
|
_err "$cfg: you haven't sucessfully configured any mountpoints or disks for this instance, not starting" |
|
|
|
return 1 |
|
|
|
} |
|
|
|
|
|
|
|
procd_open_instance |
|
|
|
|
|
|
|
service_start /usr/bin/mini_snmpd $args |
|
|
|
} |
|
|
|
procd_set_param command "$PROG" -n |
|
|
|
procd_set_param stdout "1" |
|
|
|
procd_set_param stderr "1" |
|
|
|
# don't the like default respawn values? you can override through uci. |
|
|
|
# vars left as global so you only need to do it in the first mini_snmpd instance |
|
|
|
procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-10} ${respawn_retry:-1} |
|
|
|
# this monitors ubus changes |
|
|
|
[ -n "$listen_interface" ] && { |
|
|
|
#procd_open_trigger |
|
|
|
#procd_add_interface_trigger "interface.*" $listen_interface /etc/init.d/mini_snmpd reload |
|
|
|
#procd_close_trigger |
|
|
|
procd_add_reload_interface_trigger $listen_interface #or use shorthand of above |
|
|
|
} |
|
|
|
# this re-starts the daemon if a properly configured network interface is changed whilst it is already running |
|
|
|
# igmpproxy has this as well as "procd_set_param netdev" |
|
|
|
|
|
|
|
start() { |
|
|
|
. /lib/functions/network.sh |
|
|
|
append_arg "-c" "$community" |
|
|
|
append_arg "-L" "${location}" |
|
|
|
append_arg "-C" "${contact}" |
|
|
|
append_arg "-p" $udp_port |
|
|
|
append_arg "-P" $tcp_port |
|
|
|
append_arg "-V" "${vendor_oid}" |
|
|
|
append_arg "-t" $mib_timeout |
|
|
|
|
|
|
|
[ "$ipv6" = 1 ] && procd_append_param command "-6" |
|
|
|
[ "$debug" = 1 ] && procd_append_param command "-v" |
|
|
|
# uci_validate_section() aka /sbin/validate_data can only cast default values not defined in /etc/config/* to string |
|
|
|
# e.g. ="1" however it sets bools defined in /etc/config/* to =1 / =0 |
|
|
|
[ "$auth" = 1 -o "$auth" = "1" ] && procd_append_param command "-a" |
|
|
|
[ -n "$disks_arg" ] && procd_append_param command "-d $disks_arg" |
|
|
|
[ -n "$interfaces_arg" ] && procd_append_param command "-i $interfaces_arg" |
|
|
|
[ -n "$listen_interface_device" ] && { |
|
|
|
procd_append_param command "-I" "$listen_interface_device" |
|
|
|
# and this monitors the hardware device for changes outside of ubus - just a guess |
|
|
|
procd_set_param netdev $listen_interface_device |
|
|
|
} |
|
|
|
procd_close_instance |
|
|
|
} |
|
|
|
|
|
|
|
start_service() { |
|
|
|
config_load 'mini_snmpd' |
|
|
|
config_foreach start_instance 'mini_snmpd' |
|
|
|
} |
|
|
|
|
|
|
|
stop() { |
|
|
|
service_stop /usr/bin/mini_snmpd |
|
|
|
} |