#
-# Copyright (C) 2009-2014 OpenWrt.org
+# Copyright (C) 2009-2016 OpenWrt.org
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
include $(TOPDIR)/rules.mk
PKG_NAME:=mini_snmpd
-PKG_VERSION:=1.2b
-PKG_RELEASE:=8
+PKG_VERSION:=1.4-rc1
+PKG_RELEASE:=1
+PKG_LICENSE:=GPL-2.0
+PKG_LICENSE_FILES:=COPYING
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://github.com/troglobit/mini-snmpd.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=203d92e60ed09466d6676c6ad20ad6cb2ce08a5d
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
-PKG_SOURCE_URL:=http://members.aon.at/linuxfreak/linux/
-PKG_MD5SUM:=9e432c50ba8216d7fab0983b11b7112a
-PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+PKG_FIXUP:=autoreconf
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION)
PKG_BUILD_PARALLEL:=1
PKG_INSTALL:=1
+# As warned by upstream maintainer and binutils
+# however compiler warnings can be ignored until next binutils release
+# https://github.com/wongsyrone/openwrt-1/issues/67
+# PKG_SSP:=0
+# PKG_RELRO:=0
include $(INCLUDE_DIR)/package.mk
-define Package/mini-snmpd
+define Package/mini_snmpd
SECTION:=net
CATEGORY:=Network
- TITLE:=SNMP server for embedded systems
- URL:=http://members.aon.at/linuxfreak/linux/mini_snmpd.html
+ TITLE:=A tiny SNMP server for embedded systems
+ URL:=http://troglobit.github.io/mini-snmpd.html
+# uncomment if you just want the binary, not the init script
+# openwrt requires init script runtime dependencies be defined for make menuconfig
+# (e.g busybox sysntpd)
+ DEPENDS:=+jsonfilter +ubus +procd +ubox
endef
-ifneq ($(CONFIG_IPV6),)
- TARGET_CFLAGS+= -D__IPV6__
-else
- TARGET_CFLAGS+= -D__IPV4__
-endif
+CONFIGURE_ARGS+= \
+ $(if $(CONFIG_IPV6),,--disable-ipv6)
-TARGET_CFLAGS+= -DSYSLOG
+# Configure weirdness - Disabled by default, explicitately disabling turns feature on!
+# --disable-debug \
+# --disable-demo - Upstream Github Issue #4 Fixed 20160707
-MAKE_FLAGS+= \
- OFLAGS="$(TARGET_CFLAGS)" \
+# We make sure that only openwrt buildroot does the stripping as per user request via make menuconfig
+CONFIGURE_VARS+= LD="$(TARGET_CC)" \
STRIP="/bin/true" \
- INSTALL_ROOT="$(PKG_INSTALL_DIR)"
+ CFLAGS="$(TARGET_CFLAGS)"
+MAKE_FLAGS+= STRIP="/bin/true"
-define Build/Compile
- $(call Build/Compile/Default,mini_snmpd)
-endef
+# FYI upstream suggested stripping options
+# STRIP="strip -S --strip-unneeded --remove-section=.note.gnu.gold-version --remove-section=.comment --remove-section=.note --remove-section=.note.gnu.build-id --remove-section=.note.ABI-tag mini_snmpd"
-define Package/mini-snmpd/install
+define Package/mini_snmpd/install
$(INSTALL_DIR) $(1)/usr/bin
- $(CP) $(PKG_INSTALL_DIR)/sbin/mini_snmpd $(1)/usr/bin/
+ $(CP) $(PKG_INSTALL_DIR)/usr/bin/mini_snmpd $(1)/usr/bin/
$(INSTALL_DIR) $(1)/etc/config
$(INSTALL_CONF) ./files/mini_snmpd.config $(1)/etc/config/mini_snmpd
$(INSTALL_DIR) $(1)/etc/init.d
$(INSTALL_BIN) ./files/mini_snmpd.init $(1)/etc/init.d/mini_snmpd
endef
-define Package/mini-snmpd/conffiles
+define Package/mini_snmpd/conffiles
/etc/config/mini_snmpd
endef
-$(eval $(call BuildPackage,mini-snmpd))
+$(eval $(call BuildPackage,mini_snmpd))
#!/bin/sh /etc/rc.common
-# Copyright (C) 2009-2012 OpenWrt.org
+# Copyright (C) 2009-2016 OpenWrt.org
+# 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
-}
+++ /dev/null
-#!/bin/sh /etc/rc.common
-# Copyright (C) 2009-2016 OpenWrt.org
-
-START=95
-USE_PROCD=1
-PROCD_DEBUG=1
-PROG=/usr/bin/mini_snmpd
-NAME=mini_snmpd
-
-# mini_snmpd now starts later in the game. Expects filesystems monitored to be already mounted,
-# 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
-
-append_disk() {
- local disk="$1"
- [ -z $disk_count ] && disk_count=1
- if grep -qF "$disk" /proc/mounts ; then
- if [ $disk_count -le 4 ] ; then
- append disks "$disk" ','
- disk_count=$((disk_count++))
- else
- logger -s -t mini_snmpd -p daemon.error "more than 4 mountpoints defined in uci. Disc $disk ignored."
- fi
- else
- logger -s -t mini_snmpd -p daemon.error "mountpoint $disk for snmp monitoring not mounted, ignoring."
- fi
-}
-
-append_interface() {
- local name="$1"
- local device
- [ $(ubus -S call network.interface dump | jsonfilter -e "@.interface[@.interface=\"$name\"].device") ] && {
- append interfaces "${device:-$name}" ','
- }
-}
-
-append_arg() {
- local cfg="$1"
- local var="$2"
- local opt="$3"
- local def="$4"
- local val
- config_get val "$cfg" "$var"
- [ -n "$val" -o -n "$def" ] && procd_append_param command $opt "${val:-$def}"
-}
-
-listen_interface_status() {
- local cfg="$1"
-}
-
-watch_interfaces() {
- local cfg="$1"
- local enabled listen_interface
- config_get_bool enabled "$cfg" "enabled" '1'
- [ "$enabled" -gt 0 ] || return 0
- config_get listen_interface "$cfg" listen_interface
- [ "$listen_interface" = "all" ] && return 0
- local listen_interface_up=$(ubus -S call network.interface dump | jsonfilter -e "@.interface[@.interface=\"$listen_interface\"].up")
- # if ubus knows about it regardless if it's status we'll watch for changes.
- [ -n "$listen_interface" -a -n "$listen_interface_up" ] && trigger_interfaces=" ${listen_interface} ${trigger_interfaces}"
-}
-
-service_triggers() {
- #procd_add_reload_trigger mini_snmpd
- procd_open_trigger
- procd_add_config_trigger "config.change" "mini_snmpd" /etc/init.d/mini_snmpd reload
- config_load 'mini_snmpd'
- config_foreach watch_interfaces 'mini_snmpd'
- [ -n "${trigger_interfaces}" ] & {
- for n in $trigger_interfaces ; do
- procd_add_interface_trigger "interface.*" $n /etc/init.d/mini_snmpd restart
- done
- }
- procd_close_trigger
- #procd_add_validation validate_section_mini_snmpd
-}
-
-
-start_instance() {
- local cfg="$1" disks="" interfaces=""
- local ipv6 debug auth
-
- config_get_bool enabled "$cfg" "enabled" '1'
- [ "$enabled" -gt 0 ] || return 1
-
- local listen_interface listen_interface_json listen_interface_ip listen_interface_device listen_interface_up
- config_get_bool ipv6 "$cfg" "ipv6" '0'
- config_get listen_interface "$cfg" listen_interface
- [ -n "$listen_interface" -a "$listen_interface" != "all" ] && {
- listen_interface_json=$(ubus -S call network.interface.$listen_interface status)
- [ -z "$listen_interface_json" ] && {
- logger -s -t mini_snmpd -p daemon.error "interface configured to bind to is not configured in /etc/config/network"
- return 1
- }
- listen_interface_up=$(jsonfilter -s "$listen_interface_json" -e '@.up')
- if [ "$ipv6" -gt 0 ]; 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' ] || {
- logger -s -t mini_snmpd -p daemon.debug "interface configured to bind to is not up yet, procd will try again later"
- return 0
- }
- listen_interface_device=$(jsonfilter -s "$listen_interface_json" -e '@.l3_device')
- }
-
- procd_open_instance
-
- procd_set_param command "$PROG" -n
- procd_set_param stdout "1"
- procd_set_param stderr "1"
- procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}
-
- append_arg "$cfg" community "-c"
- append_arg "$cfg" location "-L"
- append_arg "$cfg" contact "-C"
- append_arg "$cfg" udp_port "-p"
- append_arg "$cfg" tcp_port "-P"
- append_arg "$cfg" vendor_oid "-V"
- append_arg "$cfg" mib_timeout "-t"
-
- [ "$ipv6" -gt 0 ] && procd_append_param command "-6"
- config_get_bool debug "$cfg" "debug" '0'
- [ "$debug" -gt 0 ] && procd_append_param command "-v"
- config_get_bool auth "$cfg" "auth" '0'
- [ "$auth" -gt 0 ] && procd_append_param command "-a"
- config_list_foreach "$cfg" 'disks' append_disk
- [ -n "$disks" ] && procd_append_param command "-d $disks"
- config_list_foreach "$cfg" 'interfaces' append_interface
- [ -n "$interfaces" ] && procd_append_param command "-i $interfaces"
- # https://github.com/troglobit/mini-snmpd/issues/4 - yes I know there is no space after the -I
- [ -n "$listen_interface_device" ] && procd_append_param command "-I$listen_interface_device"
-
- procd_close_instance
-}
-
-start_service() {
- config_load 'mini_snmpd'
- config_foreach start_instance 'mini_snmpd'
-}
-
-reload_service() {
- stop
- start
-}