[1/5] nodewatcher: split into nodewatcher.d scripts for individual task

Submitted by Adrian Schmutzler on Jan. 7, 2020, 1:40 p.m.

Details

Message ID 20200107134024.1755-1-freifunk@adrianschmutzler.de
State Accepted
Headers show

Commit Message

Adrian Schmutzler Jan. 7, 2020, 1:40 p.m.
From: Tim Niemeyer <tim@tn-x.org>

This splits up the data extraction/assembly of the nodewatcher
script into several parts and distributes them across packages, so
that each nodewatcher.d subscript is located in the package providing
the relevant functionality. This allows to extend the nodewatcher data
by enabling/disabling packages.
This scheme is not perfectly fulfilled for fff-network vs. fff-wireless,
as data cannot uniquely assigned there and the XML syntax does not allow
separation anyway.

In general, this moves code without applying code improvements, yielding
at an easy comparison of moved fragments. However, the following changes
were done to improve experience:

- The function writing debug output has been renamed from "err" to "debug"
- Since we catch the stdout of the nodewatcher.d functions anyway,
  those scripts were adjusted to echo output directly instead of first
  writing it into a variable and then outputting it at the end.
- The uci config has been kept, but initialization for the network part
  has been moved to the fff-network package.
- Space indent has been changed to tab, which is more common in the
  firmware and requires less space.
- Remove support for nodewatcher run without uci config. Script-based
  nodewatcher on other platforms will have altered code anyway, and
  splitting it up will prevent effective use as a blueprint for those
  cases. After this change, nodewatcher in firmware is supposed to be
  used only for this firmware.

Note that since the nodewatcher.d scripts are evaluated by using there
echo output, having a function created uncaught output to stdout there
will corrupt the XML.

Signed-off-by: Tim Niemeyer <tim@tn-x.org>
[rebase and adjustments for current master, use simpler mechanism to
call nodewatcher.d scripts, use tab indent, remove debug() definition
where not needed, do not remove uci config, add commit message, use
echo -n]
Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>

---

AFAIK POSIX shell does not support echo flags. Thus, we most probably
should change /bin/sh to /bin/ash for all scripts?
---
 src/packages/fff/fff-babeld/Makefile          |   2 +-
 .../files/usr/lib/nodewatcher.d/80-babeld.sh  |  16 +
 src/packages/fff/fff-batman-adv/Makefile      |   2 +-
 .../usr/lib/nodewatcher.d/30-batman-adv.sh    |  60 ++++
 src/packages/fff/fff-network/Makefile         |   2 +-
 .../uci-defaults/94-fff-nodewatcher-network   |   9 +
 .../usr/lib/nodewatcher.d/20-interfaces.sh    |  74 ++++
 .../files/usr/lib/nodewatcher.d/50-clients.sh |  25 ++
 src/packages/fff/fff-nodewatcher/Makefile     |   2 +-
 .../files/etc/uci-defaults/93-fff-nodewatcher |   4 -
 .../usr/lib/nodewatcher.d/10-systemdata.sh    | 123 +++++++
 .../files/usr/sbin/nodewatcher                | 324 ++----------------
 src/packages/fff/fff-wireless/Makefile        |   2 +-
 .../files/usr/lib/nodewatcher.d/60-airtime.sh |  18 +
 14 files changed, 361 insertions(+), 302 deletions(-)
 create mode 100755 src/packages/fff/fff-babeld/files/usr/lib/nodewatcher.d/80-babeld.sh
 create mode 100755 src/packages/fff/fff-batman-adv/files/usr/lib/nodewatcher.d/30-batman-adv.sh
 create mode 100644 src/packages/fff/fff-network/files/etc/uci-defaults/94-fff-nodewatcher-network
 create mode 100755 src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-interfaces.sh
 create mode 100755 src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh
 create mode 100755 src/packages/fff/fff-nodewatcher/files/usr/lib/nodewatcher.d/10-systemdata.sh
 create mode 100755 src/packages/fff/fff-wireless/files/usr/lib/nodewatcher.d/60-airtime.sh

Patch hide | download patch | download mbox

diff --git a/src/packages/fff/fff-babeld/Makefile b/src/packages/fff/fff-babeld/Makefile
index 29fd8e53..b2ccac89 100644
--- a/src/packages/fff/fff-babeld/Makefile
+++ b/src/packages/fff/fff-babeld/Makefile
@@ -1,7 +1,7 @@ 
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=fff-babeld
-PKG_RELEASE:=1
+PKG_RELEASE:=2
 
 PKG_BUILD_DIR:=$(BUILD_DIR)/fff-babeld
 
diff --git a/src/packages/fff/fff-babeld/files/usr/lib/nodewatcher.d/80-babeld.sh b/src/packages/fff/fff-babeld/files/usr/lib/nodewatcher.d/80-babeld.sh
new file mode 100755
index 00000000..80196970
--- /dev/null
+++ b/src/packages/fff/fff-babeld/files/usr/lib/nodewatcher.d/80-babeld.sh
@@ -0,0 +1,16 @@ 
+#!/bin/sh
+
+if pgrep babeld >/dev/null; then
+	neighbours="$(echo dump | nc ::1 33123 | grep '^add neighbour' |
+		awk '{
+				for (i=2; i < NF; i += 2) {
+					vars[$i] = $(i+1)
+				}
+			}
+			{
+				printf "<neighbour><ip>%s</ip><outgoing_interface>%s</outgoing_interface><link_cost>%s</link_cost></neighbour>", vars["address"], vars["if"], vars["cost"]
+			}')"
+	echo -n "<babel_neighbours>$neighbours</babel_neighbours>"
+fi
+
+exit 0
diff --git a/src/packages/fff/fff-batman-adv/Makefile b/src/packages/fff/fff-batman-adv/Makefile
index 9ef58042..9d553dc0 100644
--- a/src/packages/fff/fff-batman-adv/Makefile
+++ b/src/packages/fff/fff-batman-adv/Makefile
@@ -1,7 +1,7 @@ 
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=fff-batman-adv
-PKG_RELEASE:=1
+PKG_RELEASE:=2
 
 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
 
diff --git a/src/packages/fff/fff-batman-adv/files/usr/lib/nodewatcher.d/30-batman-adv.sh b/src/packages/fff/fff-batman-adv/files/usr/lib/nodewatcher.d/30-batman-adv.sh
new file mode 100755
index 00000000..37100a2d
--- /dev/null
+++ b/src/packages/fff/fff-batman-adv/files/usr/lib/nodewatcher.d/30-batman-adv.sh
@@ -0,0 +1,60 @@ 
+#!/bin/sh
+# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
+# License; GPL v3
+
+debug() {
+	(>&2 echo "$1")
+}
+
+debug "$(date): Collecting information from batman advanced and its interfaces"
+#B.A.T.M.A.N. advanced
+if [ -f /sys/module/batman_adv/version ]; then
+	for iface in $(batctl if | sed 's/ //'); do
+		status=${iface##*:}
+		iface=${iface%%:*}
+		BATMAN_ADV_INTERFACES=$BATMAN_ADV_INTERFACES"<$iface><name>$iface</name><status>$status</status></$iface>"
+	done
+
+	echo -n "<batman_adv_interfaces>$BATMAN_ADV_INTERFACES</batman_adv_interfaces>"
+
+	# Build a list of direct neighbors
+	batman_adv_originators=$(/usr/sbin/batctl o -H | awk \
+		'BEGIN { FS=" "; i=0 } # set the delimiter to " "
+		{   sub("\\(", "", $0) # remove parentheses
+			sub("\\)", "", $0)
+			sub("\\[", "", $0)
+			sub("\\]", "", $0)
+			sub("\\*", "", $0)
+			sub("  ", " ", $0)
+			o=$1".*"$1 # build a regex to find lines that contains the $1 (=originator) twice
+			if ($0 ~ o) # filter for this regex (will remove entries without direct neighbor)
+			{
+				printf "<originator_"i"><originator>"$1"</originator><link_quality>"$3"</link_quality><nexthop>"$4"</nexthop><last_seen>"$2"</last_seen><outgoing_interface>"$5"</outgoing_interface></originator_"i">"
+				i++
+			}
+		}')
+
+	echo -n "<batman_adv_originators>$batman_adv_originators</batman_adv_originators>"
+
+	echo -n "<batman_adv_gateway_mode>$(/usr/sbin/batctl gw)</batman_adv_gateway_mode>"
+
+	batman_adv_gateway_list=$(/usr/sbin/batctl gwl -H | awk \
+		'BEGIN { FS=" "; i=0 }
+		/No gateways/ { next }
+		{   sub("\\(", "", $0)
+			sub("\\)", "", $0)
+			sub("\\[ *", "", $0)
+			sub("\\]:", "", $0)
+			sub("\\* ", "true ", $0)
+			sub("  ", "false ", $0)
+			printf "<gateway_"i"><selected>"$1"</selected><gateway>"$2"</gateway><link_quality>"$3"</link_quality><nexthop>"$4"</nexthop><outgoing_interface>"$5"</outgoing_interface><gw_class>"$6" "$7" "$8"</gw_class></gateway_"i">"
+			i++
+		}')
+
+	echo -n "<batman_adv_gateway_list>$batman_adv_gateway_list</batman_adv_gateway_list>"
+else
+	debug "$(date): No batman data .."
+	exit 1
+fi
+
+exit 0
diff --git a/src/packages/fff/fff-network/Makefile b/src/packages/fff/fff-network/Makefile
index 95f99e52..31928de8 100644
--- a/src/packages/fff/fff-network/Makefile
+++ b/src/packages/fff/fff-network/Makefile
@@ -1,7 +1,7 @@ 
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=fff-network
-PKG_RELEASE:=12
+PKG_RELEASE:=13
 
 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
 
diff --git a/src/packages/fff/fff-network/files/etc/uci-defaults/94-fff-nodewatcher-network b/src/packages/fff/fff-network/files/etc/uci-defaults/94-fff-nodewatcher-network
new file mode 100644
index 00000000..353ab1b4
--- /dev/null
+++ b/src/packages/fff/fff-network/files/etc/uci-defaults/94-fff-nodewatcher-network
@@ -0,0 +1,9 @@ 
+uci batch <<EOF
+  add nodewatcher network
+  set nodewatcher.@network[-1].mesh_interface='br-mesh'
+  set nodewatcher.@network[-1].iface_blacklist='lo ifb0'
+  set nodewatcher.@network[-1].ip_whitelist='br-mesh'
+EOF
+uci commit nodewatcher
+
+exit 0
diff --git a/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-interfaces.sh b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-interfaces.sh
new file mode 100755
index 00000000..5373d6ef
--- /dev/null
+++ b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-interfaces.sh
@@ -0,0 +1,74 @@ 
+#!/bin/sh
+# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
+# License; GPL v3
+
+IFACEBLACKLIST=$(uci get nodewatcher.@network[0].iface_blacklist)
+IPWHITELIST=$(uci get nodewatcher.@network[0].ip_whitelist)
+
+debug() {
+	(>&2 echo "$1")
+}
+
+inArray() {
+	local value
+	for value in $1; do
+		if [ "$value" = "$2" ]; then
+			return 0
+		fi
+	done
+	return 1
+}
+
+debug "$(date): Collecting information from network interfaces"
+
+#Get interfaces
+interface_data=""
+#Loop interfaces
+#for entry in $IFACES; do
+for filename in $(grep 'up\|unknown' /sys/class/net/*/operstate); do
+	ifpath=${filename%/operstate*}
+	iface=${ifpath#/sys/class/net/}
+	if inArray "$IFACEBLACKLIST" "$iface"; then
+		continue
+	fi
+
+	#Get interface data for whitelisted interfaces
+	# shellcheck disable=SC2016
+	awkscript='
+		/ether/ { printf "<mac_addr>"$2"</mac_addr>" }
+		/mtu/ { printf "<mtu>"$5"</mtu>" }'
+	if inArray "$IPWHITELIST" "$iface"; then
+		# shellcheck disable=SC2016
+		awkscript=$awkscript'
+			/inet / { split($2, a, "/"); printf "<ipv4_addr>"a[1]"</ipv4_addr>" }
+			/inet6/ && /scope global/ { printf "<ipv6_addr>"$2"</ipv6_addr>" }
+			/inet6/ && /scope link/ { printf "<ipv6_link_local_addr>"$2"</ipv6_link_local_addr>"}'
+	fi
+	addrs=$(ip addr show dev "${iface}" | awk "$awkscript")
+
+	traffic_rx=$(cat "$ifpath/statistics/rx_bytes")
+	traffic_tx=$(cat "$ifpath/statistics/tx_bytes")
+
+	interface_data=$interface_data"<$iface><name>$iface</name>$addrs<traffic_rx>$traffic_rx</traffic_rx><traffic_tx>$traffic_tx</traffic_tx>"
+
+	interface_data=$interface_data$(iwconfig "${iface}" 2>/dev/null | awk -F':' '
+		/Mode/{ split($2, m, " "); printf "<wlan_mode>"m[1]"</wlan_mode>" }
+		/Cell/{ split($0, c, " "); printf "<wlan_bssid>"c[5]"</wlan_bssid>" }
+		/ESSID/ { split($0, e, "\""); printf "<wlan_essid>"e[2]"</wlan_essid>" }
+		/Freq/{ split($3, f, " "); printf "<wlan_frequency>"f[1]f[2]"</wlan_frequency>" }
+		/Tx-Power/{ split($0, p, "="); sub(/[[:space:]]*$/, "", p[2]); printf "<wlan_tx_power>"p[2]"</wlan_tx_power>" }
+	')
+
+	interface_data=$interface_data$(iw dev "${iface}" info 2>/dev/null | awk '
+		/ssid/{ split($0, s, " "); printf "<wlan_ssid>"s[2]"</wlan_ssid>" }
+		/type/ { split($0, t, " "); printf "<wlan_type>"t[2]"</wlan_type>" }
+		/channel/{ split($0, c, " "); printf "<wlan_channel>"c[2]"</wlan_channel>" }
+		/width/{ split($0, w, ": "); sub(/ .*/, "", w[2]); printf "<wlan_width>"w[2]"</wlan_width>" }
+	')
+
+	interface_data=$interface_data"</$iface>"
+done
+
+echo -n "<interface_data>$interface_data</interface_data>"
+
+exit 0
diff --git a/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh
new file mode 100755
index 00000000..91d9b868
--- /dev/null
+++ b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh
@@ -0,0 +1,25 @@ 
+#!/bin/sh
+# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
+# License; GPL v3
+
+MESH_INTERFACE=$(uci get nodewatcher.@network[0].mesh_interface)
+
+debug() {
+	(>&2 echo "$1")
+}
+
+debug "$(date): Collecting information about connected clients"
+
+client_count=0
+dataclient=""
+CLIENT_INTERFACES=$(ls "/sys/class/net/$MESH_INTERFACE/brif" | grep -v '^bat')
+for clientif in ${CLIENT_INTERFACES}; do
+	local cc=$(bridge fdb show br "$MESH_INTERFACE" brport "$clientif" | grep -v self | grep -v permanent -c)
+	client_count=$((client_count + cc))
+	dataclient="$dataclient<$clientif>$cc</$clientif>"
+done
+
+echo -n "<client_count>$client_count</client_count>"
+echo -n "<clients>$dataclient</clients>"
+
+exit 0
diff --git a/src/packages/fff/fff-nodewatcher/Makefile b/src/packages/fff/fff-nodewatcher/Makefile
index 0ed6684d..423b7288 100644
--- a/src/packages/fff/fff-nodewatcher/Makefile
+++ b/src/packages/fff/fff-nodewatcher/Makefile
@@ -1,7 +1,7 @@ 
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=fff-nodewatcher
-PKG_RELEASE:=55
+PKG_RELEASE:=56
 
 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
 
diff --git a/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-nodewatcher b/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-nodewatcher
index 4e564352..0fc2e90e 100644
--- a/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-nodewatcher
+++ b/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-nodewatcher
@@ -8,10 +8,6 @@  uci batch <<EOF
   set nodewatcher.@script[0].logfile='/var/log/nodewatcher.log'
   set nodewatcher.@script[0].data_file='/tmp/crawldata/node.data'
   set nodewatcher.@script[0].status_text_file='/tmp/status.txt'
-  add nodewatcher network
-  set nodewatcher.@network[0].mesh_interface='br-mesh'
-  set nodewatcher.@network[0].iface_blacklist='lo ifb0'
-  set nodewatcher.@network[0].ip_whitelist='br-mesh'
 EOF
 uci commit
 
diff --git a/src/packages/fff/fff-nodewatcher/files/usr/lib/nodewatcher.d/10-systemdata.sh b/src/packages/fff/fff-nodewatcher/files/usr/lib/nodewatcher.d/10-systemdata.sh
new file mode 100755
index 00000000..713cea6c
--- /dev/null
+++ b/src/packages/fff/fff-nodewatcher/files/usr/lib/nodewatcher.d/10-systemdata.sh
@@ -0,0 +1,123 @@ 
+#!/bin/sh
+# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
+# License; GPL v3
+
+SCRIPT_STATUS_FILE=$(uci get nodewatcher.@script[0].status_text_file)
+SCRIPT_VERSION="56"
+
+debug() {
+	(>&2 echo "$1")
+}
+
+#Get system data from other locations
+debug "$(date): Collecting basic system status data"
+hostname="$(cat /proc/sys/kernel/hostname)"
+mac=$(awk '{ mac=toupper($1); gsub(":", "", mac); print mac }' /sys/class/net/br-mesh/address 2>/dev/null)
+[ "$hostname" = "OpenWrt" ] && hostname="$mac"
+[ "$hostname" = "FFF" ] && hostname="$mac"
+description="$(uci -q get fff.system.description)"
+if [ -n "$description" ]; then
+	description="<description><![CDATA[$description]]></description>"
+fi
+latitude="$(uci -q get fff.system.latitude)"
+longitude="$(uci -q get fff.system.longitude)"
+if [ -n "$longitude" -a -n "$latitude" ]; then
+	geo="<geo><lat>$latitude</lat><lng>$longitude</lng></geo>";
+fi
+position_comment="$(uci -q get fff.system.position_comment)"
+if [ -n "$position_comment" ]; then
+	position_comment="<position_comment><![CDATA[$position_comment]]></position_comment>"
+fi
+contact="$(uci -q get fff.system.contact)"
+if [ -n "$contact" ]; then
+	contact="<contact>$contact</contact>"
+fi
+uptime=$(awk '{ printf "<uptime>"$1"</uptime><idletime>"$2"</idletime>" }' /proc/uptime)
+
+memory=$(awk '
+	/^MemTotal/ { printf "<memory_total>"$2"</memory_total>" }
+	/^Cached:/ { printf "<memory_caching>"$2"</memory_caching>" }
+	/^Buffers/ { printf "<memory_buffering>"$2"</memory_buffering>" }
+	/^MemFree/ { printf "<memory_free>"$2"</memory_free>" }
+' /proc/meminfo)
+cpu=$(awk -F': ' '
+	/model/ { printf "<cpu>"$2"</cpu>" }
+	/system type/ { printf "<chipset>"$2"</chipset>" }
+	/platform/ { printf "<chipset>"$2"</chipset>" }
+' /proc/cpuinfo)
+model="<model>$(cat /var/sysinfo/model)</model>"
+local_time="$(date +%s)"
+load=$(awk '{ printf "<loadavg>"$3"</loadavg><processes>"$4"</processes>" }' /proc/loadavg)
+
+debug "$(date): Collecting version information"
+
+batman_adv_version=$(cat /sys/module/batman_adv/version)
+kernel_version=$(uname -r)
+if [ -x /usr/bin/fastd ]; then
+	fastd_version="<fastd_version>$(/usr/bin/fastd -v | awk '{ print $2 }')</fastd_version>"
+fi
+nodewatcher_version=$SCRIPT_VERSION
+if [ -x /usr/sbin/babeld ]; then
+	babel_version="<babel_version>$(/usr/sbin/babeld -V 2>&1)</babel_version>"
+fi
+
+if [ -f "$SCRIPT_STATUS_FILE" ]; then
+	status_text="<status_text>$(cat "$SCRIPT_STATUS_FILE")</status_text>"
+fi
+
+# Checks if fastd is running
+if pidof fastd >/dev/null ; then
+	vpn_active="<vpn_active>1</vpn_active>"
+else
+	vpn_active="<vpn_active>0</vpn_active>"
+fi
+
+# example for /etc/openwrt_release:
+#DISTRIB_ID="OpenWrt"
+#DISTRIB_RELEASE="Attitude Adjustment"
+#DISTRIB_REVISION="r35298"
+#DISTRIB_CODENAME="attitude_adjustment"
+#DISTRIB_TARGET="atheros/generic"
+#DISTRIB_DESCRIPTION="OpenWrt Attitude Adjustment 12.09-rc1"
+. /etc/openwrt_release
+distname=$DISTRIB_ID
+distversion=$DISTRIB_RELEASE
+
+# example for /etc/firmware_release:
+#FIRMWARE_VERSION="95f36685e7b6cbf423f02cf5c7f1e785fd4ccdae-dirty"
+#BUILD_DATE="build date: Di 29. Jan 19:33:34 CET 2013"
+#OPENWRT_CORE_REVISION="35298"
+#OPENWRT_FEEDS_PACKAGES_REVISION="35298"
+. /etc/firmware_release
+
+SYSTEM_DATA="<status>online</status>"
+SYSTEM_DATA=$SYSTEM_DATA"$status_text"
+SYSTEM_DATA=$SYSTEM_DATA"<hostname>$hostname</hostname>"
+SYSTEM_DATA=$SYSTEM_DATA"${description}"
+SYSTEM_DATA=$SYSTEM_DATA"${geo}"
+SYSTEM_DATA=$SYSTEM_DATA"${position_comment}"
+SYSTEM_DATA=$SYSTEM_DATA"${contact}"
+SYSTEM_DATA=$SYSTEM_DATA"<hood>$(uci -q get "system.@system[0].hood")</hood>"
+SYSTEM_DATA=$SYSTEM_DATA"<hoodid>$(uci -q get "system.@system[0].hoodid")</hoodid>"
+SYSTEM_DATA=$SYSTEM_DATA"<distname>$distname</distname>"
+SYSTEM_DATA=$SYSTEM_DATA"<distversion>$distversion</distversion>"
+SYSTEM_DATA=$SYSTEM_DATA"$cpu"
+SYSTEM_DATA=$SYSTEM_DATA"$model"
+SYSTEM_DATA=$SYSTEM_DATA"$memory"
+SYSTEM_DATA=$SYSTEM_DATA"$load"
+SYSTEM_DATA=$SYSTEM_DATA"$uptime"
+SYSTEM_DATA=$SYSTEM_DATA"<local_time>$local_time</local_time>"
+SYSTEM_DATA=$SYSTEM_DATA"<batman_advanced_version>$batman_adv_version</batman_advanced_version>"
+SYSTEM_DATA=$SYSTEM_DATA"<kernel_version>$kernel_version</kernel_version>"
+SYSTEM_DATA=$SYSTEM_DATA"$fastd_version"
+SYSTEM_DATA=$SYSTEM_DATA"<nodewatcher_version>$nodewatcher_version</nodewatcher_version>"
+SYSTEM_DATA=$SYSTEM_DATA"$babel_version"
+SYSTEM_DATA=$SYSTEM_DATA"<firmware_version>$FIRMWARE_VERSION</firmware_version>"
+SYSTEM_DATA=$SYSTEM_DATA"<firmware_revision>$BUILD_DATE</firmware_revision>"
+SYSTEM_DATA=$SYSTEM_DATA"<openwrt_core_revision>$OPENWRT_CORE_REVISION</openwrt_core_revision>"
+SYSTEM_DATA=$SYSTEM_DATA"<openwrt_feeds_packages_revision>$OPENWRT_FEEDS_PACKAGES_REVISION</openwrt_feeds_packages_revision>"
+SYSTEM_DATA=$SYSTEM_DATA"$vpn_active"
+
+echo -n "<system_data>$SYSTEM_DATA</system_data>"
+
+exit 0
diff --git a/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher b/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
index 42e5ce8f..21880fbe 100755
--- a/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
+++ b/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
@@ -7,327 +7,65 @@  test -f /tmp/started || exit
 # Allow only one instance
 lockfile="/var/lock/${0##*/}.lock"
 if ! lock -n "$lockfile"; then
-        echo "Only one instance of $0 allowed."
-        exit 1
+	echo "Only one instance of $0 allowed."
+	exit 1
 fi
 trap "lock -u \"$lockfile\"" INT TERM EXIT
 
-SCRIPT_VERSION="55"
+[ -s /etc/config/nodewatcher ] || exit 1
 
-#Get the configuration from the uci configuration file
-#If it does not exists, then get it from a normal bash file with variables.
-if [ -f /etc/config/nodewatcher ];then
-    SCRIPT_ERROR_LEVEL=$(uci get nodewatcher.@script[0].error_level)
-    SCRIPT_LOGFILE=$(uci get nodewatcher.@script[0].logfile)
-    SCRIPT_DATA_FILE=$(uci get nodewatcher.@script[0].data_file)
-    MESH_INTERFACE=$(uci get nodewatcher.@network[0].mesh_interface)
-    IFACEBLACKLIST=$(uci get nodewatcher.@network[0].iface_blacklist)
-    IPWHITELIST=$(uci get nodewatcher.@network[0].ip_whitelist)
-    SCRIPT_STATUS_FILE=$(uci get nodewatcher.@script[0].status_text_file)
-else
-    . "$(dirname "$0")/nodewatcher_config"
-fi
+SCRIPT_ERROR_LEVEL=$(uci get nodewatcher.@script[0].error_level)
+SCRIPT_LOGFILE=$(uci get nodewatcher.@script[0].logfile)
+SCRIPT_DATA_FILE=$(uci get nodewatcher.@script[0].data_file)
 
 if [ "$SCRIPT_ERROR_LEVEL" -gt "1" ]; then
-    err() {
-        echo "$1" >> "$SCRIPT_LOGFILE"
-    }
+	debug() {
+		echo "$1" >> "$SCRIPT_LOGFILE"
+	}
 else
-    err() {
-        :
-    }
+	debug() {
+		:
+	}
 fi
 
 #This method checks if the log file has become too big and deletes the first X lines
 delete_log() {
-    if [ -f "$SCRIPT_LOGFILE" ]; then
-        if [ "$(find "$SCRIPT_LOGFILE" -printf "%s")" -gt "6000" ]; then
-            sed -i '1,60d' "$SCRIPT_LOGFILE"
-            err "$(date): Logfile has been made smaller"
-        fi
-    fi
-}
-
-inArray() {
-    local value
-    for value in $1; do
-        if [ "$value" = "$2" ]; then
-            return 0
-        fi
-    done
-    return 1
+	if [ -f "$SCRIPT_LOGFILE" ]; then
+		if [ "$(find "$SCRIPT_LOGFILE" -printf "%s")" -gt "6000" ]; then
+			sed -i '1,60d' "$SCRIPT_LOGFILE"
+			debug "$(date): Logfile has been made smaller"
+		fi
+	fi
 }
 
 #This method generates the crawl data XML file that is being fetched by netmon
 #and provided by a small local httpd
 crawl() {
-    #Get system data from other locations
-    err "$(date): Collecting basic system status data"
-    hostname="$(cat /proc/sys/kernel/hostname)"
-    mac=$(awk '{ mac=toupper($1); gsub(":", "", mac); print mac }' /sys/class/net/br-mesh/address 2>/dev/null)
-    [ "$hostname" = "OpenWrt" ] && hostname="$mac"
-    [ "$hostname" = "FFF" ] && hostname="$mac"
-    description="$(uci -q get fff.system.description)"
-    if [ -n "$description" ]; then
-        description="<description><![CDATA[$description]]></description>"
-    fi
-    latitude="$(uci -q get fff.system.latitude)"
-    longitude="$(uci -q get fff.system.longitude)"
-    if [ -n "$longitude" -a -n "$latitude" ]; then
-        geo="<geo><lat>$latitude</lat><lng>$longitude</lng></geo>";
-    fi
-    position_comment="$(uci -q get fff.system.position_comment)"
-    if [ -n "$position_comment" ]; then
-        position_comment="<position_comment><![CDATA[$position_comment]]></position_comment>"
-    fi
-    contact="$(uci -q get fff.system.contact)"
-    if [ -n "$contact" ]; then
-        contact="<contact>$contact</contact>"
-    fi
-    uptime=$(awk '{ printf "<uptime>"$1"</uptime><idletime>"$2"</idletime>" }' /proc/uptime)
-
-    memory=$(awk '
-        /^MemTotal/ { printf "<memory_total>"$2"</memory_total>" }
-        /^Cached:/ { printf "<memory_caching>"$2"</memory_caching>" }
-        /^Buffers/ { printf "<memory_buffering>"$2"</memory_buffering>" }
-        /^MemFree/ { printf "<memory_free>"$2"</memory_free>" }
-    ' /proc/meminfo)
-    cpu=$(awk -F': ' '
-        /model/ { printf "<cpu>"$2"</cpu>" }
-        /system type/ { printf "<chipset>"$2"</chipset>" }
-        /platform/ { printf "<chipset>"$2"</chipset>" }
-    ' /proc/cpuinfo)
-    model="<model>$(cat /var/sysinfo/model)</model>"
-    local_time="$(date +%s)"
-    load=$(awk '{ printf "<loadavg>"$3"</loadavg><processes>"$4"</processes>" }' /proc/loadavg)
-
-    err "$(date): Collecting version information"
-
-    batman_adv_version=$(cat /sys/module/batman_adv/version)
-    kernel_version=$(uname -r)
-    if [ -x /usr/bin/fastd ]; then
-        fastd_version="<fastd_version>$(/usr/bin/fastd -v | awk '{ print $2 }')</fastd_version>"
-    fi
-    nodewatcher_version=$SCRIPT_VERSION
-    if [ -x /usr/sbin/babeld ]; then
-        babel_version="<babel_version>$(/usr/sbin/babeld -V 2>&1)</babel_version>"
-    fi
-
-    if [ -f "$SCRIPT_STATUS_FILE" ]; then
-        status_text="<status_text>$(cat "$SCRIPT_STATUS_FILE")</status_text>"
-    fi
-
-    # Checks if fastd is running
-    if pidof fastd >/dev/null ; then
-        vpn_active="<vpn_active>1</vpn_active>"
-    else
-        vpn_active="<vpn_active>0</vpn_active>"
-    fi
-
-    # example for /etc/openwrt_release:
-    #DISTRIB_ID="OpenWrt"
-    #DISTRIB_RELEASE="Attitude Adjustment"
-    #DISTRIB_REVISION="r35298"
-    #DISTRIB_CODENAME="attitude_adjustment"
-    #DISTRIB_TARGET="atheros/generic"
-    #DISTRIB_DESCRIPTION="OpenWrt Attitude Adjustment 12.09-rc1"
-    . /etc/openwrt_release
-    distname=$DISTRIB_ID
-    distversion=$DISTRIB_RELEASE
-
-    # example for /etc/firmware_release:
-    #FIRMWARE_VERSION="95f36685e7b6cbf423f02cf5c7f1e785fd4ccdae-dirty"
-    #BUILD_DATE="build date: Di 29. Jan 19:33:34 CET 2013"
-    #OPENWRT_CORE_REVISION="35298"
-    #OPENWRT_FEEDS_PACKAGES_REVISION="35298"
-    . /etc/firmware_release
-
-    SYSTEM_DATA="<status>online</status>"
-    SYSTEM_DATA=$SYSTEM_DATA"$status_text"
-    SYSTEM_DATA=$SYSTEM_DATA"<hostname>$hostname</hostname>"
-    SYSTEM_DATA=$SYSTEM_DATA"${description}"
-    SYSTEM_DATA=$SYSTEM_DATA"${geo}"
-    SYSTEM_DATA=$SYSTEM_DATA"${position_comment}"
-    SYSTEM_DATA=$SYSTEM_DATA"${contact}"
-    SYSTEM_DATA=$SYSTEM_DATA"<hood>$(uci -q get "system.@system[0].hood")</hood>"
-    SYSTEM_DATA=$SYSTEM_DATA"<hoodid>$(uci -q get "system.@system[0].hoodid")</hoodid>"
-    SYSTEM_DATA=$SYSTEM_DATA"<distname>$distname</distname>"
-    SYSTEM_DATA=$SYSTEM_DATA"<distversion>$distversion</distversion>"
-    SYSTEM_DATA=$SYSTEM_DATA"$cpu"
-    SYSTEM_DATA=$SYSTEM_DATA"$model"
-    SYSTEM_DATA=$SYSTEM_DATA"$memory"
-    SYSTEM_DATA=$SYSTEM_DATA"$load"
-    SYSTEM_DATA=$SYSTEM_DATA"$uptime"
-    SYSTEM_DATA=$SYSTEM_DATA"<local_time>$local_time</local_time>"
-    SYSTEM_DATA=$SYSTEM_DATA"<batman_advanced_version>$batman_adv_version</batman_advanced_version>"
-    SYSTEM_DATA=$SYSTEM_DATA"<kernel_version>$kernel_version</kernel_version>"
-    SYSTEM_DATA=$SYSTEM_DATA"$fastd_version"
-    SYSTEM_DATA=$SYSTEM_DATA"<nodewatcher_version>$nodewatcher_version</nodewatcher_version>"
-    SYSTEM_DATA=$SYSTEM_DATA"$babel_version"
-    SYSTEM_DATA=$SYSTEM_DATA"<firmware_version>$FIRMWARE_VERSION</firmware_version>"
-    SYSTEM_DATA=$SYSTEM_DATA"<firmware_revision>$BUILD_DATE</firmware_revision>"
-    SYSTEM_DATA=$SYSTEM_DATA"<openwrt_core_revision>$OPENWRT_CORE_REVISION</openwrt_core_revision>"
-    SYSTEM_DATA=$SYSTEM_DATA"<openwrt_feeds_packages_revision>$OPENWRT_FEEDS_PACKAGES_REVISION</openwrt_feeds_packages_revision>"
-    SYSTEM_DATA=$SYSTEM_DATA"$vpn_active"
-
-    err "$(date): Collecting information from network interfaces"
-
-    #Get interfaces
-    interface_data=""
-    #Loop interfaces
-    #for entry in $IFACES; do
-    for filename in $(grep 'up\|unknown' /sys/class/net/*/operstate); do
-        ifpath=${filename%/operstate*}
-        iface=${ifpath#/sys/class/net/}
-        if inArray "$IFACEBLACKLIST" "$iface"; then
-            continue
-        fi
-
-        #Get interface data for whitelisted interfaces
-        # shellcheck disable=SC2016
-        awkscript='
-            /ether/ { printf "<mac_addr>"$2"</mac_addr>" }
-            /mtu/ { printf "<mtu>"$5"</mtu>" }'
-        if inArray "$IPWHITELIST" "$iface"; then
-            # shellcheck disable=SC2016
-            awkscript=$awkscript'
-                /inet / { split($2, a, "/"); printf "<ipv4_addr>"a[1]"</ipv4_addr>" }
-                /inet6/ && /scope global/ { printf "<ipv6_addr>"$2"</ipv6_addr>" }
-                /inet6/ && /scope link/ { printf "<ipv6_link_local_addr>"$2"</ipv6_link_local_addr>"}'
-        fi
-        addrs=$(ip addr show dev "${iface}" | awk "$awkscript")
-
-        traffic_rx=$(cat "$ifpath/statistics/rx_bytes")
-        traffic_tx=$(cat "$ifpath/statistics/tx_bytes")
-
-        interface_data=$interface_data"<$iface><name>$iface</name>$addrs<traffic_rx>$traffic_rx</traffic_rx><traffic_tx>$traffic_tx</traffic_tx>"
-
-        interface_data=$interface_data$(iwconfig "${iface}" 2>/dev/null | awk -F':' '
-            /Mode/{ split($2, m, " "); printf "<wlan_mode>"m[1]"</wlan_mode>" }
-            /Cell/{ split($0, c, " "); printf "<wlan_bssid>"c[5]"</wlan_bssid>" }
-            /ESSID/ { split($0, e, "\""); printf "<wlan_essid>"e[2]"</wlan_essid>" }
-            /Freq/{ split($3, f, " "); printf "<wlan_frequency>"f[1]f[2]"</wlan_frequency>" }
-            /Tx-Power/{ split($0, p, "="); sub(/[[:space:]]*$/, "", p[2]); printf "<wlan_tx_power>"p[2]"</wlan_tx_power>" }
-        ')
-
-        interface_data=$interface_data$(iw dev "${iface}" info 2>/dev/null | awk '
-            /ssid/{ split($0, s, " "); printf "<wlan_ssid>"s[2]"</wlan_ssid>" }
-            /type/ { split($0, t, " "); printf "<wlan_type>"t[2]"</wlan_type>" }
-            /channel/{ split($0, c, " "); printf "<wlan_channel>"c[2]"</wlan_channel>" }
-            /width/{ split($0, w, ": "); sub(/ .*/, "", w[2]); printf "<wlan_width>"w[2]"</wlan_width>" }
-        ')
-
-        interface_data=$interface_data"</$iface>"
-    done
-
-    err "$(date): Collecting information from batman advanced and its interfaces"
-    #B.A.T.M.A.N. advanced
-    if [ -f /sys/module/batman_adv/version ]; then
-        for iface in $(batctl if | sed 's/ //'); do
-            status=${iface##*:}
-            iface=${iface%%:*}
-            BATMAN_ADV_INTERFACES=$BATMAN_ADV_INTERFACES"<$iface><name>$iface</name><status>$status</status></$iface>"
-        done
-
-        # Build a list of direct neighbors
-        batman_adv_originators=$(/usr/sbin/batctl o -H | awk \
-            'BEGIN { FS=" "; i=0 } # set the delimiter to " "
-            {   sub("\\(", "", $0) # remove parentheses
-                sub("\\)", "", $0)
-                sub("\\[", "", $0)
-                sub("\\]", "", $0)
-                sub("\\*", "", $0)
-                sub("  ", " ", $0)
-                o=$1".*"$1 # build a regex to find lines that contains the $1 (=originator) twice
-                if ($0 ~ o) # filter for this regex (will remove entries without direct neighbor)
-                {
-                    printf "<originator_"i"><originator>"$1"</originator><link_quality>"$3"</link_quality><nexthop>"$4"</nexthop><last_seen>"$2"</last_seen><outgoing_interface>"$5"</outgoing_interface></originator_"i">"
-                    i++
-                }
-            }')
-
-        batman_adv_gateway_mode=$(/usr/sbin/batctl gw)
-
-        batman_adv_gateway_list=$(/usr/sbin/batctl gwl -H | awk \
-            'BEGIN { FS=" "; i=0 }
-            /No gateways/ { next }
-            {   sub("\\(", "", $0)
-                sub("\\)", "", $0)
-                sub("\\[ *", "", $0)
-                sub("\\]:", "", $0)
-                sub("\\* ", "true ", $0)
-                sub("  ", "false ", $0)
-                printf "<gateway_"i"><selected>"$1"</selected><gateway>"$2"</gateway><link_quality>"$3"</link_quality><nexthop>"$4"</nexthop><outgoing_interface>"$5"</outgoing_interface><gw_class>"$6" "$7" "$8"</gw_class></gateway_"i">"
-                i++
-            }')
-    fi
-    err "$(date): Collecting information about conected clients"
-    #CLIENTS
-    client_count=0
-    dataclient=""
-    CLIENT_INTERFACES=$(ls "/sys/class/net/$MESH_INTERFACE/brif" | grep -v '^bat')
-    for clientif in ${CLIENT_INTERFACES}; do
-        local cc=$(bridge fdb show br "$MESH_INTERFACE" brport "$clientif" | grep -v self | grep -v permanent -c)
-        client_count=$((client_count + cc))
-        dataclient="$dataclient<$clientif>$cc</$clientif>"
-    done
-
-    dataair=""
-    w2dump="$(iw dev w2ap survey dump 2> /dev/null | sed '/Survey/,/\[in use\]/d')"
-    if [ -n "$w2dump" ] ; then
-        w2_ACT="$(ACTIVE=$(echo "$w2dump" | grep "active time:"); set ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
-        w2_BUS="$(BUSY=$(echo "$w2dump" | grep "busy time:"); set ${BUSY:-0 0 0 0 0}; echo -e "${4}")"
-        dataair="$dataair<airtime2><active>$w2_ACT</active><busy>$w2_BUS</busy></airtime2>"
-    fi
-    w5dump="$(iw dev w5ap survey dump 2> /dev/null | sed '/Survey/,/\[in use\]/d')"
-    if [ -n "$w5dump" ] ; then
-        w5_ACT="$(ACTIVE=$(echo "$w5dump" | grep "active time:"); set ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
-        w5_BUS="$(BUSY=$(echo "$w5dump" | grep "busy time:"); set ${BUSY:-0 0 0 0 0}; echo -e "${4}")"
-        dataair="$dataair<airtime5><active>$w5_ACT</active><busy>$w5_BUS</busy></airtime5>"
-    fi
+	debug "$(date): Putting all information into a XML-File and save it at $SCRIPT_DATA_FILE"
 
-    if pgrep babeld >/dev/null; then
-        neighbours="$(echo dump | nc ::1 33123 | grep '^add neighbour' |
-            awk '{
-                   for (i=2; i < NF; i += 2) {
-                     vars[$i] = $(i+1)
-                   }
-                 }
-                 {
-                   printf "<neighbour><ip>%s</ip><outgoing_interface>%s</outgoing_interface><link_cost>%s</link_cost></neighbour>", vars["address"], vars["if"], vars["cost"]
-                 }')"
-        BABELS="<babel_neighbours>$neighbours</babel_neighbours>"
-    fi
+	DATA="<?xml version='1.0' standalone='yes'?><data>"
 
-    err "$(date): Putting all information into a XML-File and save it at $SCRIPT_DATA_FILE"
+	for f in /usr/lib/nodewatcher.d/*.sh; do
+		tmp="$($f)"
+		DATA="$DATA$tmp"
+	done
 
-    DATA="<?xml version='1.0' standalone='yes'?><data>"
-    DATA=$DATA"<system_data>$SYSTEM_DATA</system_data>"
-    DATA=$DATA"<interface_data>$interface_data</interface_data>"
-    DATA=$DATA"<batman_adv_interfaces>$BATMAN_ADV_INTERFACES</batman_adv_interfaces>"
-    DATA=$DATA"<batman_adv_originators>$batman_adv_originators</batman_adv_originators>"
-    DATA=$DATA"<batman_adv_gateway_mode>$batman_adv_gateway_mode</batman_adv_gateway_mode>"
-    DATA=$DATA"<batman_adv_gateway_list>$batman_adv_gateway_list</batman_adv_gateway_list>"
-    DATA=$DATA"$BABELS"
-    DATA=$DATA"<client_count>$client_count</client_count>"
-    DATA=$DATA"<clients>$dataclient</clients>"
-    DATA=$DATA"$dataair"
-    DATA=$DATA"</data>"
+	DATA="$DATA</data>"
 
-    #write data to xml file that provides the data on httpd
-    SCRIPT_DATA_DIR=$(dirname "$SCRIPT_DATA_FILE")
-    test -d "$SCRIPT_DATA_DIR" || mkdir -p "$SCRIPT_DATA_DIR"
-    echo "$DATA" | gzip | tee "$SCRIPT_DATA_FILE" | alfred -s 64
+	#write data to xml file that provides the data on httpd
+	SCRIPT_DATA_DIR=$(dirname "$SCRIPT_DATA_FILE")
+	test -d "$SCRIPT_DATA_DIR" || mkdir -p "$SCRIPT_DATA_DIR"
+	echo "$DATA" | gzip | tee "$SCRIPT_DATA_FILE" | alfred -s 64
 }
 
 LANG=C
 
 #Prüft ob das logfile zu groß geworden ist
-err "$(date): Check logfile"
+debug "$(date): Check logfile"
 delete_log
 
 #Erzeugt die statusdaten
-err "$(date): Generate actual status data"
+debug "$(date): Generate actual status data"
 crawl
 
 exit 0
diff --git a/src/packages/fff/fff-wireless/Makefile b/src/packages/fff/fff-wireless/Makefile
index 00b1c7ca..e805ea22 100644
--- a/src/packages/fff/fff-wireless/Makefile
+++ b/src/packages/fff/fff-wireless/Makefile
@@ -1,7 +1,7 @@ 
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=fff-wireless
-PKG_RELEASE:=13
+PKG_RELEASE:=14
 
 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
 
diff --git a/src/packages/fff/fff-wireless/files/usr/lib/nodewatcher.d/60-airtime.sh b/src/packages/fff/fff-wireless/files/usr/lib/nodewatcher.d/60-airtime.sh
new file mode 100755
index 00000000..ca53d904
--- /dev/null
+++ b/src/packages/fff/fff-wireless/files/usr/lib/nodewatcher.d/60-airtime.sh
@@ -0,0 +1,18 @@ 
+#!/bin/sh
+# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
+# License; GPL v3
+
+w2dump="$(iw dev w2ap survey dump 2> /dev/null | sed '/Survey/,/\[in use\]/d')"
+if [ -n "$w2dump" ] ; then
+	w2_ACT="$(ACTIVE=$(echo "$w2dump" | grep "active time:"); set ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
+	w2_BUS="$(BUSY=$(echo "$w2dump" | grep "busy time:"); set ${BUSY:-0 0 0 0 0}; echo -e "${4}")"
+	echo -n "$dataair<airtime2><active>$w2_ACT</active><busy>$w2_BUS</busy></airtime2>"
+fi
+w5dump="$(iw dev w5ap survey dump 2> /dev/null | sed '/Survey/,/\[in use\]/d')"
+if [ -n "$w5dump" ] ; then
+	w5_ACT="$(ACTIVE=$(echo "$w5dump" | grep "active time:"); set ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
+	w5_BUS="$(BUSY=$(echo "$w5dump" | grep "busy time:"); set ${BUSY:-0 0 0 0 0}; echo -e "${4}")"
+	echo -n "$dataair<airtime5><active>$w5_ACT</active><busy>$w5_BUS</busy></airtime5>"
+fi
+
+exit 0

Comments

Christian Dresel Jan. 7, 2020, 2:13 p.m.
Hi Adrian

grundlegende Frage, warum /usr/lib/nodewatcher.d? Die gateway.d  haben
wir in /etc liegen.

Zweite Frage: Es steht ja schon die Idee im Raum das ganze Zeug neu
sauber aufzubauen (vorallem Lemmi war da ja hinterher) und eine
ordentliche Datenstruktur hinzubekommen. Will man das in dem Zug vllt.
gleich mitmachen, sich eine ordentliche API im Monitoring überlegen und
das gleich damit umsetzen? Schade das du (und/oder Tim?) dir jetzt schon
die Arbeit gemacht hast und das alte Ding zerrupft hast.

Gruß

Christian

On 07.01.20 14:40, Adrian Schmutzler wrote:
> From: Tim Niemeyer <tim@tn-x.org>
> 
> This splits up the data extraction/assembly of the nodewatcher
> script into several parts and distributes them across packages, so
> that each nodewatcher.d subscript is located in the package providing
> the relevant functionality. This allows to extend the nodewatcher data
> by enabling/disabling packages.
> This scheme is not perfectly fulfilled for fff-network vs. fff-wireless,
> as data cannot uniquely assigned there and the XML syntax does not allow
> separation anyway.
> 
> In general, this moves code without applying code improvements, yielding
> at an easy comparison of moved fragments. However, the following changes
> were done to improve experience:
> 
> - The function writing debug output has been renamed from "err" to "debug"
> - Since we catch the stdout of the nodewatcher.d functions anyway,
>   those scripts were adjusted to echo output directly instead of first
>   writing it into a variable and then outputting it at the end.
> - The uci config has been kept, but initialization for the network part
>   has been moved to the fff-network package.
> - Space indent has been changed to tab, which is more common in the
>   firmware and requires less space.
> - Remove support for nodewatcher run without uci config. Script-based
>   nodewatcher on other platforms will have altered code anyway, and
>   splitting it up will prevent effective use as a blueprint for those
>   cases. After this change, nodewatcher in firmware is supposed to be
>   used only for this firmware.
> 
> Note that since the nodewatcher.d scripts are evaluated by using there
> echo output, having a function created uncaught output to stdout there
> will corrupt the XML.
> 
> Signed-off-by: Tim Niemeyer <tim@tn-x.org>
> [rebase and adjustments for current master, use simpler mechanism to
> call nodewatcher.d scripts, use tab indent, remove debug() definition
> where not needed, do not remove uci config, add commit message, use
> echo -n]
> Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>
> 
> ---
> 
> AFAIK POSIX shell does not support echo flags. Thus, we most probably
> should change /bin/sh to /bin/ash for all scripts?
> ---
>  src/packages/fff/fff-babeld/Makefile          |   2 +-
>  .../files/usr/lib/nodewatcher.d/80-babeld.sh  |  16 +
>  src/packages/fff/fff-batman-adv/Makefile      |   2 +-
>  .../usr/lib/nodewatcher.d/30-batman-adv.sh    |  60 ++++
>  src/packages/fff/fff-network/Makefile         |   2 +-
>  .../uci-defaults/94-fff-nodewatcher-network   |   9 +
>  .../usr/lib/nodewatcher.d/20-interfaces.sh    |  74 ++++
>  .../files/usr/lib/nodewatcher.d/50-clients.sh |  25 ++
>  src/packages/fff/fff-nodewatcher/Makefile     |   2 +-
>  .../files/etc/uci-defaults/93-fff-nodewatcher |   4 -
>  .../usr/lib/nodewatcher.d/10-systemdata.sh    | 123 +++++++
>  .../files/usr/sbin/nodewatcher                | 324 ++----------------
>  src/packages/fff/fff-wireless/Makefile        |   2 +-
>  .../files/usr/lib/nodewatcher.d/60-airtime.sh |  18 +
>  14 files changed, 361 insertions(+), 302 deletions(-)
>  create mode 100755 src/packages/fff/fff-babeld/files/usr/lib/nodewatcher.d/80-babeld.sh
>  create mode 100755 src/packages/fff/fff-batman-adv/files/usr/lib/nodewatcher.d/30-batman-adv.sh
>  create mode 100644 src/packages/fff/fff-network/files/etc/uci-defaults/94-fff-nodewatcher-network
>  create mode 100755 src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-interfaces.sh
>  create mode 100755 src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh
>  create mode 100755 src/packages/fff/fff-nodewatcher/files/usr/lib/nodewatcher.d/10-systemdata.sh
>  create mode 100755 src/packages/fff/fff-wireless/files/usr/lib/nodewatcher.d/60-airtime.sh
> 
> diff --git a/src/packages/fff/fff-babeld/Makefile b/src/packages/fff/fff-babeld/Makefile
> index 29fd8e53..b2ccac89 100644
> --- a/src/packages/fff/fff-babeld/Makefile
> +++ b/src/packages/fff/fff-babeld/Makefile
> @@ -1,7 +1,7 @@
>  include $(TOPDIR)/rules.mk
>  
>  PKG_NAME:=fff-babeld
> -PKG_RELEASE:=1
> +PKG_RELEASE:=2
>  
>  PKG_BUILD_DIR:=$(BUILD_DIR)/fff-babeld
>  
> diff --git a/src/packages/fff/fff-babeld/files/usr/lib/nodewatcher.d/80-babeld.sh b/src/packages/fff/fff-babeld/files/usr/lib/nodewatcher.d/80-babeld.sh
> new file mode 100755
> index 00000000..80196970
> --- /dev/null
> +++ b/src/packages/fff/fff-babeld/files/usr/lib/nodewatcher.d/80-babeld.sh
> @@ -0,0 +1,16 @@
> +#!/bin/sh
> +
> +if pgrep babeld >/dev/null; then
> +	neighbours="$(echo dump | nc ::1 33123 | grep '^add neighbour' |
> +		awk '{
> +				for (i=2; i < NF; i += 2) {
> +					vars[$i] = $(i+1)
> +				}
> +			}
> +			{
> +				printf "<neighbour><ip>%s</ip><outgoing_interface>%s</outgoing_interface><link_cost>%s</link_cost></neighbour>", vars["address"], vars["if"], vars["cost"]
> +			}')"
> +	echo -n "<babel_neighbours>$neighbours</babel_neighbours>"
> +fi
> +
> +exit 0
> diff --git a/src/packages/fff/fff-batman-adv/Makefile b/src/packages/fff/fff-batman-adv/Makefile
> index 9ef58042..9d553dc0 100644
> --- a/src/packages/fff/fff-batman-adv/Makefile
> +++ b/src/packages/fff/fff-batman-adv/Makefile
> @@ -1,7 +1,7 @@
>  include $(TOPDIR)/rules.mk
>  
>  PKG_NAME:=fff-batman-adv
> -PKG_RELEASE:=1
> +PKG_RELEASE:=2
>  
>  PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
>  
> diff --git a/src/packages/fff/fff-batman-adv/files/usr/lib/nodewatcher.d/30-batman-adv.sh b/src/packages/fff/fff-batman-adv/files/usr/lib/nodewatcher.d/30-batman-adv.sh
> new file mode 100755
> index 00000000..37100a2d
> --- /dev/null
> +++ b/src/packages/fff/fff-batman-adv/files/usr/lib/nodewatcher.d/30-batman-adv.sh
> @@ -0,0 +1,60 @@
> +#!/bin/sh
> +# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
> +# License; GPL v3
> +
> +debug() {
> +	(>&2 echo "$1")
> +}
> +
> +debug "$(date): Collecting information from batman advanced and its interfaces"
> +#B.A.T.M.A.N. advanced
> +if [ -f /sys/module/batman_adv/version ]; then
> +	for iface in $(batctl if | sed 's/ //'); do
> +		status=${iface##*:}
> +		iface=${iface%%:*}
> +		BATMAN_ADV_INTERFACES=$BATMAN_ADV_INTERFACES"<$iface><name>$iface</name><status>$status</status></$iface>"
> +	done
> +
> +	echo -n "<batman_adv_interfaces>$BATMAN_ADV_INTERFACES</batman_adv_interfaces>"
> +
> +	# Build a list of direct neighbors
> +	batman_adv_originators=$(/usr/sbin/batctl o -H | awk \
> +		'BEGIN { FS=" "; i=0 } # set the delimiter to " "
> +		{   sub("\\(", "", $0) # remove parentheses
> +			sub("\\)", "", $0)
> +			sub("\\[", "", $0)
> +			sub("\\]", "", $0)
> +			sub("\\*", "", $0)
> +			sub("  ", " ", $0)
> +			o=$1".*"$1 # build a regex to find lines that contains the $1 (=originator) twice
> +			if ($0 ~ o) # filter for this regex (will remove entries without direct neighbor)
> +			{
> +				printf "<originator_"i"><originator>"$1"</originator><link_quality>"$3"</link_quality><nexthop>"$4"</nexthop><last_seen>"$2"</last_seen><outgoing_interface>"$5"</outgoing_interface></originator_"i">"
> +				i++
> +			}
> +		}')
> +
> +	echo -n "<batman_adv_originators>$batman_adv_originators</batman_adv_originators>"
> +
> +	echo -n "<batman_adv_gateway_mode>$(/usr/sbin/batctl gw)</batman_adv_gateway_mode>"
> +
> +	batman_adv_gateway_list=$(/usr/sbin/batctl gwl -H | awk \
> +		'BEGIN { FS=" "; i=0 }
> +		/No gateways/ { next }
> +		{   sub("\\(", "", $0)
> +			sub("\\)", "", $0)
> +			sub("\\[ *", "", $0)
> +			sub("\\]:", "", $0)
> +			sub("\\* ", "true ", $0)
> +			sub("  ", "false ", $0)
> +			printf "<gateway_"i"><selected>"$1"</selected><gateway>"$2"</gateway><link_quality>"$3"</link_quality><nexthop>"$4"</nexthop><outgoing_interface>"$5"</outgoing_interface><gw_class>"$6" "$7" "$8"</gw_class></gateway_"i">"
> +			i++
> +		}')
> +
> +	echo -n "<batman_adv_gateway_list>$batman_adv_gateway_list</batman_adv_gateway_list>"
> +else
> +	debug "$(date): No batman data .."
> +	exit 1
> +fi
> +
> +exit 0
> diff --git a/src/packages/fff/fff-network/Makefile b/src/packages/fff/fff-network/Makefile
> index 95f99e52..31928de8 100644
> --- a/src/packages/fff/fff-network/Makefile
> +++ b/src/packages/fff/fff-network/Makefile
> @@ -1,7 +1,7 @@
>  include $(TOPDIR)/rules.mk
>  
>  PKG_NAME:=fff-network
> -PKG_RELEASE:=12
> +PKG_RELEASE:=13
>  
>  PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
>  
> diff --git a/src/packages/fff/fff-network/files/etc/uci-defaults/94-fff-nodewatcher-network b/src/packages/fff/fff-network/files/etc/uci-defaults/94-fff-nodewatcher-network
> new file mode 100644
> index 00000000..353ab1b4
> --- /dev/null
> +++ b/src/packages/fff/fff-network/files/etc/uci-defaults/94-fff-nodewatcher-network
> @@ -0,0 +1,9 @@
> +uci batch <<EOF
> +  add nodewatcher network
> +  set nodewatcher.@network[-1].mesh_interface='br-mesh'
> +  set nodewatcher.@network[-1].iface_blacklist='lo ifb0'
> +  set nodewatcher.@network[-1].ip_whitelist='br-mesh'
> +EOF
> +uci commit nodewatcher
> +
> +exit 0
> diff --git a/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-interfaces.sh b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-interfaces.sh
> new file mode 100755
> index 00000000..5373d6ef
> --- /dev/null
> +++ b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-interfaces.sh
> @@ -0,0 +1,74 @@
> +#!/bin/sh
> +# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
> +# License; GPL v3
> +
> +IFACEBLACKLIST=$(uci get nodewatcher.@network[0].iface_blacklist)
> +IPWHITELIST=$(uci get nodewatcher.@network[0].ip_whitelist)
> +
> +debug() {
> +	(>&2 echo "$1")
> +}
> +
> +inArray() {
> +	local value
> +	for value in $1; do
> +		if [ "$value" = "$2" ]; then
> +			return 0
> +		fi
> +	done
> +	return 1
> +}
> +
> +debug "$(date): Collecting information from network interfaces"
> +
> +#Get interfaces
> +interface_data=""
> +#Loop interfaces
> +#for entry in $IFACES; do
> +for filename in $(grep 'up\|unknown' /sys/class/net/*/operstate); do
> +	ifpath=${filename%/operstate*}
> +	iface=${ifpath#/sys/class/net/}
> +	if inArray "$IFACEBLACKLIST" "$iface"; then
> +		continue
> +	fi
> +
> +	#Get interface data for whitelisted interfaces
> +	# shellcheck disable=SC2016
> +	awkscript='
> +		/ether/ { printf "<mac_addr>"$2"</mac_addr>" }
> +		/mtu/ { printf "<mtu>"$5"</mtu>" }'
> +	if inArray "$IPWHITELIST" "$iface"; then
> +		# shellcheck disable=SC2016
> +		awkscript=$awkscript'
> +			/inet / { split($2, a, "/"); printf "<ipv4_addr>"a[1]"</ipv4_addr>" }
> +			/inet6/ && /scope global/ { printf "<ipv6_addr>"$2"</ipv6_addr>" }
> +			/inet6/ && /scope link/ { printf "<ipv6_link_local_addr>"$2"</ipv6_link_local_addr>"}'
> +	fi
> +	addrs=$(ip addr show dev "${iface}" | awk "$awkscript")
> +
> +	traffic_rx=$(cat "$ifpath/statistics/rx_bytes")
> +	traffic_tx=$(cat "$ifpath/statistics/tx_bytes")
> +
> +	interface_data=$interface_data"<$iface><name>$iface</name>$addrs<traffic_rx>$traffic_rx</traffic_rx><traffic_tx>$traffic_tx</traffic_tx>"
> +
> +	interface_data=$interface_data$(iwconfig "${iface}" 2>/dev/null | awk -F':' '
> +		/Mode/{ split($2, m, " "); printf "<wlan_mode>"m[1]"</wlan_mode>" }
> +		/Cell/{ split($0, c, " "); printf "<wlan_bssid>"c[5]"</wlan_bssid>" }
> +		/ESSID/ { split($0, e, "\""); printf "<wlan_essid>"e[2]"</wlan_essid>" }
> +		/Freq/{ split($3, f, " "); printf "<wlan_frequency>"f[1]f[2]"</wlan_frequency>" }
> +		/Tx-Power/{ split($0, p, "="); sub(/[[:space:]]*$/, "", p[2]); printf "<wlan_tx_power>"p[2]"</wlan_tx_power>" }
> +	')
> +
> +	interface_data=$interface_data$(iw dev "${iface}" info 2>/dev/null | awk '
> +		/ssid/{ split($0, s, " "); printf "<wlan_ssid>"s[2]"</wlan_ssid>" }
> +		/type/ { split($0, t, " "); printf "<wlan_type>"t[2]"</wlan_type>" }
> +		/channel/{ split($0, c, " "); printf "<wlan_channel>"c[2]"</wlan_channel>" }
> +		/width/{ split($0, w, ": "); sub(/ .*/, "", w[2]); printf "<wlan_width>"w[2]"</wlan_width>" }
> +	')
> +
> +	interface_data=$interface_data"</$iface>"
> +done
> +
> +echo -n "<interface_data>$interface_data</interface_data>"
> +
> +exit 0
> diff --git a/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh
> new file mode 100755
> index 00000000..91d9b868
> --- /dev/null
> +++ b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh
> @@ -0,0 +1,25 @@
> +#!/bin/sh
> +# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
> +# License; GPL v3
> +
> +MESH_INTERFACE=$(uci get nodewatcher.@network[0].mesh_interface)
> +
> +debug() {
> +	(>&2 echo "$1")
> +}
> +
> +debug "$(date): Collecting information about connected clients"
> +
> +client_count=0
> +dataclient=""
> +CLIENT_INTERFACES=$(ls "/sys/class/net/$MESH_INTERFACE/brif" | grep -v '^bat')
> +for clientif in ${CLIENT_INTERFACES}; do
> +	local cc=$(bridge fdb show br "$MESH_INTERFACE" brport "$clientif" | grep -v self | grep -v permanent -c)
> +	client_count=$((client_count + cc))
> +	dataclient="$dataclient<$clientif>$cc</$clientif>"
> +done
> +
> +echo -n "<client_count>$client_count</client_count>"
> +echo -n "<clients>$dataclient</clients>"
> +
> +exit 0
> diff --git a/src/packages/fff/fff-nodewatcher/Makefile b/src/packages/fff/fff-nodewatcher/Makefile
> index 0ed6684d..423b7288 100644
> --- a/src/packages/fff/fff-nodewatcher/Makefile
> +++ b/src/packages/fff/fff-nodewatcher/Makefile
> @@ -1,7 +1,7 @@
>  include $(TOPDIR)/rules.mk
>  
>  PKG_NAME:=fff-nodewatcher
> -PKG_RELEASE:=55
> +PKG_RELEASE:=56
>  
>  PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
>  
> diff --git a/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-nodewatcher b/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-nodewatcher
> index 4e564352..0fc2e90e 100644
> --- a/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-nodewatcher
> +++ b/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-nodewatcher
> @@ -8,10 +8,6 @@ uci batch <<EOF
>    set nodewatcher.@script[0].logfile='/var/log/nodewatcher.log'
>    set nodewatcher.@script[0].data_file='/tmp/crawldata/node.data'
>    set nodewatcher.@script[0].status_text_file='/tmp/status.txt'
> -  add nodewatcher network
> -  set nodewatcher.@network[0].mesh_interface='br-mesh'
> -  set nodewatcher.@network[0].iface_blacklist='lo ifb0'
> -  set nodewatcher.@network[0].ip_whitelist='br-mesh'
>  EOF
>  uci commit
>  
> diff --git a/src/packages/fff/fff-nodewatcher/files/usr/lib/nodewatcher.d/10-systemdata.sh b/src/packages/fff/fff-nodewatcher/files/usr/lib/nodewatcher.d/10-systemdata.sh
> new file mode 100755
> index 00000000..713cea6c
> --- /dev/null
> +++ b/src/packages/fff/fff-nodewatcher/files/usr/lib/nodewatcher.d/10-systemdata.sh
> @@ -0,0 +1,123 @@
> +#!/bin/sh
> +# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
> +# License; GPL v3
> +
> +SCRIPT_STATUS_FILE=$(uci get nodewatcher.@script[0].status_text_file)
> +SCRIPT_VERSION="56"
> +
> +debug() {
> +	(>&2 echo "$1")
> +}
> +
> +#Get system data from other locations
> +debug "$(date): Collecting basic system status data"
> +hostname="$(cat /proc/sys/kernel/hostname)"
> +mac=$(awk '{ mac=toupper($1); gsub(":", "", mac); print mac }' /sys/class/net/br-mesh/address 2>/dev/null)
> +[ "$hostname" = "OpenWrt" ] && hostname="$mac"
> +[ "$hostname" = "FFF" ] && hostname="$mac"
> +description="$(uci -q get fff.system.description)"
> +if [ -n "$description" ]; then
> +	description="<description><![CDATA[$description]]></description>"
> +fi
> +latitude="$(uci -q get fff.system.latitude)"
> +longitude="$(uci -q get fff.system.longitude)"
> +if [ -n "$longitude" -a -n "$latitude" ]; then
> +	geo="<geo><lat>$latitude</lat><lng>$longitude</lng></geo>";
> +fi
> +position_comment="$(uci -q get fff.system.position_comment)"
> +if [ -n "$position_comment" ]; then
> +	position_comment="<position_comment><![CDATA[$position_comment]]></position_comment>"
> +fi
> +contact="$(uci -q get fff.system.contact)"
> +if [ -n "$contact" ]; then
> +	contact="<contact>$contact</contact>"
> +fi
> +uptime=$(awk '{ printf "<uptime>"$1"</uptime><idletime>"$2"</idletime>" }' /proc/uptime)
> +
> +memory=$(awk '
> +	/^MemTotal/ { printf "<memory_total>"$2"</memory_total>" }
> +	/^Cached:/ { printf "<memory_caching>"$2"</memory_caching>" }
> +	/^Buffers/ { printf "<memory_buffering>"$2"</memory_buffering>" }
> +	/^MemFree/ { printf "<memory_free>"$2"</memory_free>" }
> +' /proc/meminfo)
> +cpu=$(awk -F': ' '
> +	/model/ { printf "<cpu>"$2"</cpu>" }
> +	/system type/ { printf "<chipset>"$2"</chipset>" }
> +	/platform/ { printf "<chipset>"$2"</chipset>" }
> +' /proc/cpuinfo)
> +model="<model>$(cat /var/sysinfo/model)</model>"
> +local_time="$(date +%s)"
> +load=$(awk '{ printf "<loadavg>"$3"</loadavg><processes>"$4"</processes>" }' /proc/loadavg)
> +
> +debug "$(date): Collecting version information"
> +
> +batman_adv_version=$(cat /sys/module/batman_adv/version)
> +kernel_version=$(uname -r)
> +if [ -x /usr/bin/fastd ]; then
> +	fastd_version="<fastd_version>$(/usr/bin/fastd -v | awk '{ print $2 }')</fastd_version>"
> +fi
> +nodewatcher_version=$SCRIPT_VERSION
> +if [ -x /usr/sbin/babeld ]; then
> +	babel_version="<babel_version>$(/usr/sbin/babeld -V 2>&1)</babel_version>"
> +fi
> +
> +if [ -f "$SCRIPT_STATUS_FILE" ]; then
> +	status_text="<status_text>$(cat "$SCRIPT_STATUS_FILE")</status_text>"
> +fi
> +
> +# Checks if fastd is running
> +if pidof fastd >/dev/null ; then
> +	vpn_active="<vpn_active>1</vpn_active>"
> +else
> +	vpn_active="<vpn_active>0</vpn_active>"
> +fi
> +
> +# example for /etc/openwrt_release:
> +#DISTRIB_ID="OpenWrt"
> +#DISTRIB_RELEASE="Attitude Adjustment"
> +#DISTRIB_REVISION="r35298"
> +#DISTRIB_CODENAME="attitude_adjustment"
> +#DISTRIB_TARGET="atheros/generic"
> +#DISTRIB_DESCRIPTION="OpenWrt Attitude Adjustment 12.09-rc1"
> +. /etc/openwrt_release
> +distname=$DISTRIB_ID
> +distversion=$DISTRIB_RELEASE
> +
> +# example for /etc/firmware_release:
> +#FIRMWARE_VERSION="95f36685e7b6cbf423f02cf5c7f1e785fd4ccdae-dirty"
> +#BUILD_DATE="build date: Di 29. Jan 19:33:34 CET 2013"
> +#OPENWRT_CORE_REVISION="35298"
> +#OPENWRT_FEEDS_PACKAGES_REVISION="35298"
> +. /etc/firmware_release
> +
> +SYSTEM_DATA="<status>online</status>"
> +SYSTEM_DATA=$SYSTEM_DATA"$status_text"
> +SYSTEM_DATA=$SYSTEM_DATA"<hostname>$hostname</hostname>"
> +SYSTEM_DATA=$SYSTEM_DATA"${description}"
> +SYSTEM_DATA=$SYSTEM_DATA"${geo}"
> +SYSTEM_DATA=$SYSTEM_DATA"${position_comment}"
> +SYSTEM_DATA=$SYSTEM_DATA"${contact}"
> +SYSTEM_DATA=$SYSTEM_DATA"<hood>$(uci -q get "system.@system[0].hood")</hood>"
> +SYSTEM_DATA=$SYSTEM_DATA"<hoodid>$(uci -q get "system.@system[0].hoodid")</hoodid>"
> +SYSTEM_DATA=$SYSTEM_DATA"<distname>$distname</distname>"
> +SYSTEM_DATA=$SYSTEM_DATA"<distversion>$distversion</distversion>"
> +SYSTEM_DATA=$SYSTEM_DATA"$cpu"
> +SYSTEM_DATA=$SYSTEM_DATA"$model"
> +SYSTEM_DATA=$SYSTEM_DATA"$memory"
> +SYSTEM_DATA=$SYSTEM_DATA"$load"
> +SYSTEM_DATA=$SYSTEM_DATA"$uptime"
> +SYSTEM_DATA=$SYSTEM_DATA"<local_time>$local_time</local_time>"
> +SYSTEM_DATA=$SYSTEM_DATA"<batman_advanced_version>$batman_adv_version</batman_advanced_version>"
> +SYSTEM_DATA=$SYSTEM_DATA"<kernel_version>$kernel_version</kernel_version>"
> +SYSTEM_DATA=$SYSTEM_DATA"$fastd_version"
> +SYSTEM_DATA=$SYSTEM_DATA"<nodewatcher_version>$nodewatcher_version</nodewatcher_version>"
> +SYSTEM_DATA=$SYSTEM_DATA"$babel_version"
> +SYSTEM_DATA=$SYSTEM_DATA"<firmware_version>$FIRMWARE_VERSION</firmware_version>"
> +SYSTEM_DATA=$SYSTEM_DATA"<firmware_revision>$BUILD_DATE</firmware_revision>"
> +SYSTEM_DATA=$SYSTEM_DATA"<openwrt_core_revision>$OPENWRT_CORE_REVISION</openwrt_core_revision>"
> +SYSTEM_DATA=$SYSTEM_DATA"<openwrt_feeds_packages_revision>$OPENWRT_FEEDS_PACKAGES_REVISION</openwrt_feeds_packages_revision>"
> +SYSTEM_DATA=$SYSTEM_DATA"$vpn_active"
> +
> +echo -n "<system_data>$SYSTEM_DATA</system_data>"
> +
> +exit 0
> diff --git a/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher b/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
> index 42e5ce8f..21880fbe 100755
> --- a/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
> +++ b/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
> @@ -7,327 +7,65 @@ test -f /tmp/started || exit
>  # Allow only one instance
>  lockfile="/var/lock/${0##*/}.lock"
>  if ! lock -n "$lockfile"; then
> -        echo "Only one instance of $0 allowed."
> -        exit 1
> +	echo "Only one instance of $0 allowed."
> +	exit 1
>  fi
>  trap "lock -u \"$lockfile\"" INT TERM EXIT
>  
> -SCRIPT_VERSION="55"
> +[ -s /etc/config/nodewatcher ] || exit 1
>  
> -#Get the configuration from the uci configuration file
> -#If it does not exists, then get it from a normal bash file with variables.
> -if [ -f /etc/config/nodewatcher ];then
> -    SCRIPT_ERROR_LEVEL=$(uci get nodewatcher.@script[0].error_level)
> -    SCRIPT_LOGFILE=$(uci get nodewatcher.@script[0].logfile)
> -    SCRIPT_DATA_FILE=$(uci get nodewatcher.@script[0].data_file)
> -    MESH_INTERFACE=$(uci get nodewatcher.@network[0].mesh_interface)
> -    IFACEBLACKLIST=$(uci get nodewatcher.@network[0].iface_blacklist)
> -    IPWHITELIST=$(uci get nodewatcher.@network[0].ip_whitelist)
> -    SCRIPT_STATUS_FILE=$(uci get nodewatcher.@script[0].status_text_file)
> -else
> -    . "$(dirname "$0")/nodewatcher_config"
> -fi
> +SCRIPT_ERROR_LEVEL=$(uci get nodewatcher.@script[0].error_level)
> +SCRIPT_LOGFILE=$(uci get nodewatcher.@script[0].logfile)
> +SCRIPT_DATA_FILE=$(uci get nodewatcher.@script[0].data_file)
>  
>  if [ "$SCRIPT_ERROR_LEVEL" -gt "1" ]; then
> -    err() {
> -        echo "$1" >> "$SCRIPT_LOGFILE"
> -    }
> +	debug() {
> +		echo "$1" >> "$SCRIPT_LOGFILE"
> +	}
>  else
> -    err() {
> -        :
> -    }
> +	debug() {
> +		:
> +	}
>  fi
>  
>  #This method checks if the log file has become too big and deletes the first X lines
>  delete_log() {
> -    if [ -f "$SCRIPT_LOGFILE" ]; then
> -        if [ "$(find "$SCRIPT_LOGFILE" -printf "%s")" -gt "6000" ]; then
> -            sed -i '1,60d' "$SCRIPT_LOGFILE"
> -            err "$(date): Logfile has been made smaller"
> -        fi
> -    fi
> -}
> -
> -inArray() {
> -    local value
> -    for value in $1; do
> -        if [ "$value" = "$2" ]; then
> -            return 0
> -        fi
> -    done
> -    return 1
> +	if [ -f "$SCRIPT_LOGFILE" ]; then
> +		if [ "$(find "$SCRIPT_LOGFILE" -printf "%s")" -gt "6000" ]; then
> +			sed -i '1,60d' "$SCRIPT_LOGFILE"
> +			debug "$(date): Logfile has been made smaller"
> +		fi
> +	fi
>  }
>  
>  #This method generates the crawl data XML file that is being fetched by netmon
>  #and provided by a small local httpd
>  crawl() {
> -    #Get system data from other locations
> -    err "$(date): Collecting basic system status data"
> -    hostname="$(cat /proc/sys/kernel/hostname)"
> -    mac=$(awk '{ mac=toupper($1); gsub(":", "", mac); print mac }' /sys/class/net/br-mesh/address 2>/dev/null)
> -    [ "$hostname" = "OpenWrt" ] && hostname="$mac"
> -    [ "$hostname" = "FFF" ] && hostname="$mac"
> -    description="$(uci -q get fff.system.description)"
> -    if [ -n "$description" ]; then
> -        description="<description><![CDATA[$description]]></description>"
> -    fi
> -    latitude="$(uci -q get fff.system.latitude)"
> -    longitude="$(uci -q get fff.system.longitude)"
> -    if [ -n "$longitude" -a -n "$latitude" ]; then
> -        geo="<geo><lat>$latitude</lat><lng>$longitude</lng></geo>";
> -    fi
> -    position_comment="$(uci -q get fff.system.position_comment)"
> -    if [ -n "$position_comment" ]; then
> -        position_comment="<position_comment><![CDATA[$position_comment]]></position_comment>"
> -    fi
> -    contact="$(uci -q get fff.system.contact)"
> -    if [ -n "$contact" ]; then
> -        contact="<contact>$contact</contact>"
> -    fi
> -    uptime=$(awk '{ printf "<uptime>"$1"</uptime><idletime>"$2"</idletime>" }' /proc/uptime)
> -
> -    memory=$(awk '
> -        /^MemTotal/ { printf "<memory_total>"$2"</memory_total>" }
> -        /^Cached:/ { printf "<memory_caching>"$2"</memory_caching>" }
> -        /^Buffers/ { printf "<memory_buffering>"$2"</memory_buffering>" }
> -        /^MemFree/ { printf "<memory_free>"$2"</memory_free>" }
> -    ' /proc/meminfo)
> -    cpu=$(awk -F': ' '
> -        /model/ { printf "<cpu>"$2"</cpu>" }
> -        /system type/ { printf "<chipset>"$2"</chipset>" }
> -        /platform/ { printf "<chipset>"$2"</chipset>" }
> -    ' /proc/cpuinfo)
> -    model="<model>$(cat /var/sysinfo/model)</model>"
> -    local_time="$(date +%s)"
> -    load=$(awk '{ printf "<loadavg>"$3"</loadavg><processes>"$4"</processes>" }' /proc/loadavg)
> -
> -    err "$(date): Collecting version information"
> -
> -    batman_adv_version=$(cat /sys/module/batman_adv/version)
> -    kernel_version=$(uname -r)
> -    if [ -x /usr/bin/fastd ]; then
> -        fastd_version="<fastd_version>$(/usr/bin/fastd -v | awk '{ print $2 }')</fastd_version>"
> -    fi
> -    nodewatcher_version=$SCRIPT_VERSION
> -    if [ -x /usr/sbin/babeld ]; then
> -        babel_version="<babel_version>$(/usr/sbin/babeld -V 2>&1)</babel_version>"
> -    fi
> -
> -    if [ -f "$SCRIPT_STATUS_FILE" ]; then
> -        status_text="<status_text>$(cat "$SCRIPT_STATUS_FILE")</status_text>"
> -    fi
> -
> -    # Checks if fastd is running
> -    if pidof fastd >/dev/null ; then
> -        vpn_active="<vpn_active>1</vpn_active>"
> -    else
> -        vpn_active="<vpn_active>0</vpn_active>"
> -    fi
> -
> -    # example for /etc/openwrt_release:
> -    #DISTRIB_ID="OpenWrt"
> -    #DISTRIB_RELEASE="Attitude Adjustment"
> -    #DISTRIB_REVISION="r35298"
> -    #DISTRIB_CODENAME="attitude_adjustment"
> -    #DISTRIB_TARGET="atheros/generic"
> -    #DISTRIB_DESCRIPTION="OpenWrt Attitude Adjustment 12.09-rc1"
> -    . /etc/openwrt_release
> -    distname=$DISTRIB_ID
> -    distversion=$DISTRIB_RELEASE
> -
> -    # example for /etc/firmware_release:
> -    #FIRMWARE_VERSION="95f36685e7b6cbf423f02cf5c7f1e785fd4ccdae-dirty"
> -    #BUILD_DATE="build date: Di 29. Jan 19:33:34 CET 2013"
> -    #OPENWRT_CORE_REVISION="35298"
> -    #OPENWRT_FEEDS_PACKAGES_REVISION="35298"
> -    . /etc/firmware_release
> -
> -    SYSTEM_DATA="<status>online</status>"
> -    SYSTEM_DATA=$SYSTEM_DATA"$status_text"
> -    SYSTEM_DATA=$SYSTEM_DATA"<hostname>$hostname</hostname>"
> -    SYSTEM_DATA=$SYSTEM_DATA"${description}"
> -    SYSTEM_DATA=$SYSTEM_DATA"${geo}"
> -    SYSTEM_DATA=$SYSTEM_DATA"${position_comment}"
> -    SYSTEM_DATA=$SYSTEM_DATA"${contact}"
> -    SYSTEM_DATA=$SYSTEM_DATA"<hood>$(uci -q get "system.@system[0].hood")</hood>"
> -    SYSTEM_DATA=$SYSTEM_DATA"<hoodid>$(uci -q get "system.@system[0].hoodid")</hoodid>"
> -    SYSTEM_DATA=$SYSTEM_DATA"<distname>$distname</distname>"
> -    SYSTEM_DATA=$SYSTEM_DATA"<distversion>$distversion</distversion>"
> -    SYSTEM_DATA=$SYSTEM_DATA"$cpu"
> -    SYSTEM_DATA=$SYSTEM_DATA"$model"
> -    SYSTEM_DATA=$SYSTEM_DATA"$memory"
> -    SYSTEM_DATA=$SYSTEM_DATA"$load"
> -    SYSTEM_DATA=$SYSTEM_DATA"$uptime"
> -    SYSTEM_DATA=$SYSTEM_DATA"<local_time>$local_time</local_time>"
> -    SYSTEM_DATA=$SYSTEM_DATA"<batman_advanced_version>$batman_adv_version</batman_advanced_version>"
> -    SYSTEM_DATA=$SYSTEM_DATA"<kernel_version>$kernel_version</kernel_version>"
> -    SYSTEM_DATA=$SYSTEM_DATA"$fastd_version"
> -    SYSTEM_DATA=$SYSTEM_DATA"<nodewatcher_version>$nodewatcher_version</nodewatcher_version>"
> -    SYSTEM_DATA=$SYSTEM_DATA"$babel_version"
> -    SYSTEM_DATA=$SYSTEM_DATA"<firmware_version>$FIRMWARE_VERSION</firmware_version>"
> -    SYSTEM_DATA=$SYSTEM_DATA"<firmware_revision>$BUILD_DATE</firmware_revision>"
> -    SYSTEM_DATA=$SYSTEM_DATA"<openwrt_core_revision>$OPENWRT_CORE_REVISION</openwrt_core_revision>"
> -    SYSTEM_DATA=$SYSTEM_DATA"<openwrt_feeds_packages_revision>$OPENWRT_FEEDS_PACKAGES_REVISION</openwrt_feeds_packages_revision>"
> -    SYSTEM_DATA=$SYSTEM_DATA"$vpn_active"
> -
> -    err "$(date): Collecting information from network interfaces"
> -
> -    #Get interfaces
> -    interface_data=""
> -    #Loop interfaces
> -    #for entry in $IFACES; do
> -    for filename in $(grep 'up\|unknown' /sys/class/net/*/operstate); do
> -        ifpath=${filename%/operstate*}
> -        iface=${ifpath#/sys/class/net/}
> -        if inArray "$IFACEBLACKLIST" "$iface"; then
> -            continue
> -        fi
> -
> -        #Get interface data for whitelisted interfaces
> -        # shellcheck disable=SC2016
> -        awkscript='
> -            /ether/ { printf "<mac_addr>"$2"</mac_addr>" }
> -            /mtu/ { printf "<mtu>"$5"</mtu>" }'
> -        if inArray "$IPWHITELIST" "$iface"; then
> -            # shellcheck disable=SC2016
> -            awkscript=$awkscript'
> -                /inet / { split($2, a, "/"); printf "<ipv4_addr>"a[1]"</ipv4_addr>" }
> -                /inet6/ && /scope global/ { printf "<ipv6_addr>"$2"</ipv6_addr>" }
> -                /inet6/ && /scope link/ { printf "<ipv6_link_local_addr>"$2"</ipv6_link_local_addr>"}'
> -        fi
> -        addrs=$(ip addr show dev "${iface}" | awk "$awkscript")
> -
> -        traffic_rx=$(cat "$ifpath/statistics/rx_bytes")
> -        traffic_tx=$(cat "$ifpath/statistics/tx_bytes")
> -
> -        interface_data=$interface_data"<$iface><name>$iface</name>$addrs<traffic_rx>$traffic_rx</traffic_rx><traffic_tx>$traffic_tx</traffic_tx>"
> -
> -        interface_data=$interface_data$(iwconfig "${iface}" 2>/dev/null | awk -F':' '
> -            /Mode/{ split($2, m, " "); printf "<wlan_mode>"m[1]"</wlan_mode>" }
> -            /Cell/{ split($0, c, " "); printf "<wlan_bssid>"c[5]"</wlan_bssid>" }
> -            /ESSID/ { split($0, e, "\""); printf "<wlan_essid>"e[2]"</wlan_essid>" }
> -            /Freq/{ split($3, f, " "); printf "<wlan_frequency>"f[1]f[2]"</wlan_frequency>" }
> -            /Tx-Power/{ split($0, p, "="); sub(/[[:space:]]*$/, "", p[2]); printf "<wlan_tx_power>"p[2]"</wlan_tx_power>" }
> -        ')
> -
> -        interface_data=$interface_data$(iw dev "${iface}" info 2>/dev/null | awk '
> -            /ssid/{ split($0, s, " "); printf "<wlan_ssid>"s[2]"</wlan_ssid>" }
> -            /type/ { split($0, t, " "); printf "<wlan_type>"t[2]"</wlan_type>" }
> -            /channel/{ split($0, c, " "); printf "<wlan_channel>"c[2]"</wlan_channel>" }
> -            /width/{ split($0, w, ": "); sub(/ .*/, "", w[2]); printf "<wlan_width>"w[2]"</wlan_width>" }
> -        ')
> -
> -        interface_data=$interface_data"</$iface>"
> -    done
> -
> -    err "$(date): Collecting information from batman advanced and its interfaces"
> -    #B.A.T.M.A.N. advanced
> -    if [ -f /sys/module/batman_adv/version ]; then
> -        for iface in $(batctl if | sed 's/ //'); do
> -            status=${iface##*:}
> -            iface=${iface%%:*}
> -            BATMAN_ADV_INTERFACES=$BATMAN_ADV_INTERFACES"<$iface><name>$iface</name><status>$status</status></$iface>"
> -        done
> -
> -        # Build a list of direct neighbors
> -        batman_adv_originators=$(/usr/sbin/batctl o -H | awk \
> -            'BEGIN { FS=" "; i=0 } # set the delimiter to " "
> -            {   sub("\\(", "", $0) # remove parentheses
> -                sub("\\)", "", $0)
> -                sub("\\[", "", $0)
> -                sub("\\]", "", $0)
> -                sub("\\*", "", $0)
> -                sub("  ", " ", $0)
> -                o=$1".*"$1 # build a regex to find lines that contains the $1 (=originator) twice
> -                if ($0 ~ o) # filter for this regex (will remove entries without direct neighbor)
> -                {
> -                    printf "<originator_"i"><originator>"$1"</originator><link_quality>"$3"</link_quality><nexthop>"$4"</nexthop><last_seen>"$2"</last_seen><outgoing_interface>"$5"</outgoing_interface></originator_"i">"
> -                    i++
> -                }
> -            }')
> -
> -        batman_adv_gateway_mode=$(/usr/sbin/batctl gw)
> -
> -        batman_adv_gateway_list=$(/usr/sbin/batctl gwl -H | awk \
> -            'BEGIN { FS=" "; i=0 }
> -            /No gateways/ { next }
> -            {   sub("\\(", "", $0)
> -                sub("\\)", "", $0)
> -                sub("\\[ *", "", $0)
> -                sub("\\]:", "", $0)
> -                sub("\\* ", "true ", $0)
> -                sub("  ", "false ", $0)
> -                printf "<gateway_"i"><selected>"$1"</selected><gateway>"$2"</gateway><link_quality>"$3"</link_quality><nexthop>"$4"</nexthop><outgoing_interface>"$5"</outgoing_interface><gw_class>"$6" "$7" "$8"</gw_class></gateway_"i">"
> -                i++
> -            }')
> -    fi
> -    err "$(date): Collecting information about conected clients"
> -    #CLIENTS
> -    client_count=0
> -    dataclient=""
> -    CLIENT_INTERFACES=$(ls "/sys/class/net/$MESH_INTERFACE/brif" | grep -v '^bat')
> -    for clientif in ${CLIENT_INTERFACES}; do
> -        local cc=$(bridge fdb show br "$MESH_INTERFACE" brport "$clientif" | grep -v self | grep -v permanent -c)
> -        client_count=$((client_count + cc))
> -        dataclient="$dataclient<$clientif>$cc</$clientif>"
> -    done
> -
> -    dataair=""
> -    w2dump="$(iw dev w2ap survey dump 2> /dev/null | sed '/Survey/,/\[in use\]/d')"
> -    if [ -n "$w2dump" ] ; then
> -        w2_ACT="$(ACTIVE=$(echo "$w2dump" | grep "active time:"); set ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
> -        w2_BUS="$(BUSY=$(echo "$w2dump" | grep "busy time:"); set ${BUSY:-0 0 0 0 0}; echo -e "${4}")"
> -        dataair="$dataair<airtime2><active>$w2_ACT</active><busy>$w2_BUS</busy></airtime2>"
> -    fi
> -    w5dump="$(iw dev w5ap survey dump 2> /dev/null | sed '/Survey/,/\[in use\]/d')"
> -    if [ -n "$w5dump" ] ; then
> -        w5_ACT="$(ACTIVE=$(echo "$w5dump" | grep "active time:"); set ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
> -        w5_BUS="$(BUSY=$(echo "$w5dump" | grep "busy time:"); set ${BUSY:-0 0 0 0 0}; echo -e "${4}")"
> -        dataair="$dataair<airtime5><active>$w5_ACT</active><busy>$w5_BUS</busy></airtime5>"
> -    fi
> +	debug "$(date): Putting all information into a XML-File and save it at $SCRIPT_DATA_FILE"
>  
> -    if pgrep babeld >/dev/null; then
> -        neighbours="$(echo dump | nc ::1 33123 | grep '^add neighbour' |
> -            awk '{
> -                   for (i=2; i < NF; i += 2) {
> -                     vars[$i] = $(i+1)
> -                   }
> -                 }
> -                 {
> -                   printf "<neighbour><ip>%s</ip><outgoing_interface>%s</outgoing_interface><link_cost>%s</link_cost></neighbour>", vars["address"], vars["if"], vars["cost"]
> -                 }')"
> -        BABELS="<babel_neighbours>$neighbours</babel_neighbours>"
> -    fi
> +	DATA="<?xml version='1.0' standalone='yes'?><data>"
>  
> -    err "$(date): Putting all information into a XML-File and save it at $SCRIPT_DATA_FILE"
> +	for f in /usr/lib/nodewatcher.d/*.sh; do
> +		tmp="$($f)"
> +		DATA="$DATA$tmp"
> +	done
>  
> -    DATA="<?xml version='1.0' standalone='yes'?><data>"
> -    DATA=$DATA"<system_data>$SYSTEM_DATA</system_data>"
> -    DATA=$DATA"<interface_data>$interface_data</interface_data>"
> -    DATA=$DATA"<batman_adv_interfaces>$BATMAN_ADV_INTERFACES</batman_adv_interfaces>"
> -    DATA=$DATA"<batman_adv_originators>$batman_adv_originators</batman_adv_originators>"
> -    DATA=$DATA"<batman_adv_gateway_mode>$batman_adv_gateway_mode</batman_adv_gateway_mode>"
> -    DATA=$DATA"<batman_adv_gateway_list>$batman_adv_gateway_list</batman_adv_gateway_list>"
> -    DATA=$DATA"$BABELS"
> -    DATA=$DATA"<client_count>$client_count</client_count>"
> -    DATA=$DATA"<clients>$dataclient</clients>"
> -    DATA=$DATA"$dataair"
> -    DATA=$DATA"</data>"
> +	DATA="$DATA</data>"
>  
> -    #write data to xml file that provides the data on httpd
> -    SCRIPT_DATA_DIR=$(dirname "$SCRIPT_DATA_FILE")
> -    test -d "$SCRIPT_DATA_DIR" || mkdir -p "$SCRIPT_DATA_DIR"
> -    echo "$DATA" | gzip | tee "$SCRIPT_DATA_FILE" | alfred -s 64
> +	#write data to xml file that provides the data on httpd
> +	SCRIPT_DATA_DIR=$(dirname "$SCRIPT_DATA_FILE")
> +	test -d "$SCRIPT_DATA_DIR" || mkdir -p "$SCRIPT_DATA_DIR"
> +	echo "$DATA" | gzip | tee "$SCRIPT_DATA_FILE" | alfred -s 64
>  }
>  
>  LANG=C
>  
>  #Prüft ob das logfile zu groß geworden ist
> -err "$(date): Check logfile"
> +debug "$(date): Check logfile"
>  delete_log
>  
>  #Erzeugt die statusdaten
> -err "$(date): Generate actual status data"
> +debug "$(date): Generate actual status data"
>  crawl
>  
>  exit 0
> diff --git a/src/packages/fff/fff-wireless/Makefile b/src/packages/fff/fff-wireless/Makefile
> index 00b1c7ca..e805ea22 100644
> --- a/src/packages/fff/fff-wireless/Makefile
> +++ b/src/packages/fff/fff-wireless/Makefile
> @@ -1,7 +1,7 @@
>  include $(TOPDIR)/rules.mk
>  
>  PKG_NAME:=fff-wireless
> -PKG_RELEASE:=13
> +PKG_RELEASE:=14
>  
>  PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
>  
> diff --git a/src/packages/fff/fff-wireless/files/usr/lib/nodewatcher.d/60-airtime.sh b/src/packages/fff/fff-wireless/files/usr/lib/nodewatcher.d/60-airtime.sh
> new file mode 100755
> index 00000000..ca53d904
> --- /dev/null
> +++ b/src/packages/fff/fff-wireless/files/usr/lib/nodewatcher.d/60-airtime.sh
> @@ -0,0 +1,18 @@
> +#!/bin/sh
> +# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
> +# License; GPL v3
> +
> +w2dump="$(iw dev w2ap survey dump 2> /dev/null | sed '/Survey/,/\[in use\]/d')"
> +if [ -n "$w2dump" ] ; then
> +	w2_ACT="$(ACTIVE=$(echo "$w2dump" | grep "active time:"); set ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
> +	w2_BUS="$(BUSY=$(echo "$w2dump" | grep "busy time:"); set ${BUSY:-0 0 0 0 0}; echo -e "${4}")"
> +	echo -n "$dataair<airtime2><active>$w2_ACT</active><busy>$w2_BUS</busy></airtime2>"
> +fi
> +w5dump="$(iw dev w5ap survey dump 2> /dev/null | sed '/Survey/,/\[in use\]/d')"
> +if [ -n "$w5dump" ] ; then
> +	w5_ACT="$(ACTIVE=$(echo "$w5dump" | grep "active time:"); set ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
> +	w5_BUS="$(BUSY=$(echo "$w5dump" | grep "busy time:"); set ${BUSY:-0 0 0 0 0}; echo -e "${4}")"
> +	echo -n "$dataair<airtime5><active>$w5_ACT</active><busy>$w5_BUS</busy></airtime5>"
> +fi
> +
> +exit 0
>
Adrian Schmutzler Jan. 7, 2020, 2:25 p.m.
Hallo Christian,

> -----Original Message-----
> From: franken-dev [mailto:franken-dev-bounces@freifunk.net] On Behalf Of
> Christian Dresel
> Sent: Dienstag, 7. Januar 2020 15:14
> To: Adrian Schmutzler <freifunk@adrianschmutzler.de>; franken-
> dev@freifunk.net
> Subject: Re: [PATCH 1/5] nodewatcher: split into nodewatcher.d scripts for
> individual task
> 
> Hi Adrian
> 
> grundlegende Frage, warum /usr/lib/nodewatcher.d? Die gateway.d  haben
> wir in /etc liegen.

die Verzeichnisse habe ich ohne viel drüber nachzudenken von Tim übernommen. Ein grundsätzlicher Unterschied zu gateway.d besteht aber darin, dass nodewatcher.d ausführbare Skripte enthält (+x), während gateway.d nur gesourced wird (denke ich). Ist mir aber prinzipiell egal, wo das am Schluss liegt. (OpenWrt hat z.B. auch ausführbare Skripte in /etc/board.d/) Wenn es jemand woanders haben will, verschiebe ich das gerne dahin.

> 
> Zweite Frage: Es steht ja schon die Idee im Raum das ganze Zeug neu
> sauber aufzubauen (vorallem Lemmi war da ja hinterher) und eine
> ordentliche Datenstruktur hinzubekommen. Will man das in dem Zug vllt.
> gleich mitmachen, sich eine ordentliche API im Monitoring überlegen und
> das gleich damit umsetzen? Schade das du (und/oder Tim?) dir jetzt schon
> die Arbeit gemacht hast und das alte Ding zerrupft hast.

Bisher ist diesbezüglich ja nichts passiert, außer festzustellen, dass man das gerne hätte.

Tatsächlich sind beide Projekte aber relativ unabhängig voneinander: Wir haben jetzt erstmal die Skripte aufgeteilt, dies richtet sich zunächst nach den Packages in der Firmware und eigentlich kaum nach dem Inhalt des XML. Wenn man nun irgendwann ein json hat, kann man einfach die Syntax in den Dateien anpassen; an der Aufteilung würde sich dadurch aber wohl wenig ändern, genauso wenig wie an den Datenquellen und dazugehörigen Parser-Funktionen. Insofern sehe ich hier keine Konkurrenz mehr zwischen den beiden Dingen (Aufteilen und Syntax ändern), und wenn wir jetzt schon mal aufteilen haben wir später weniger Arbeit (falls sich irgendwann tatsächlich jemand die Arbeit macht).

Grüße

Adrian

> 
> Gruß
> 
> Christian
> 
> On 07.01.20 14:40, Adrian Schmutzler wrote:
> > From: Tim Niemeyer <tim@tn-x.org>
> >
> > This splits up the data extraction/assembly of the nodewatcher
> > script into several parts and distributes them across packages, so
> > that each nodewatcher.d subscript is located in the package providing
> > the relevant functionality. This allows to extend the nodewatcher data
> > by enabling/disabling packages.
> > This scheme is not perfectly fulfilled for fff-network vs. fff-wireless,
> > as data cannot uniquely assigned there and the XML syntax does not allow
> > separation anyway.
> >
> > In general, this moves code without applying code improvements, yielding
> > at an easy comparison of moved fragments. However, the following changes
> > were done to improve experience:
> >
> > - The function writing debug output has been renamed from "err" to "debug"
> > - Since we catch the stdout of the nodewatcher.d functions anyway,
> >   those scripts were adjusted to echo output directly instead of first
> >   writing it into a variable and then outputting it at the end.
> > - The uci config has been kept, but initialization for the network part
> >   has been moved to the fff-network package.
> > - Space indent has been changed to tab, which is more common in the
> >   firmware and requires less space.
> > - Remove support for nodewatcher run without uci config. Script-based
> >   nodewatcher on other platforms will have altered code anyway, and
> >   splitting it up will prevent effective use as a blueprint for those
> >   cases. After this change, nodewatcher in firmware is supposed to be
> >   used only for this firmware.
> >
> > Note that since the nodewatcher.d scripts are evaluated by using there
> > echo output, having a function created uncaught output to stdout there
> > will corrupt the XML.
> >
> > Signed-off-by: Tim Niemeyer <tim@tn-x.org>
> > [rebase and adjustments for current master, use simpler mechanism to
> > call nodewatcher.d scripts, use tab indent, remove debug() definition
> > where not needed, do not remove uci config, add commit message, use
> > echo -n]
> > Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>
> >
> > ---
> >
> > AFAIK POSIX shell does not support echo flags. Thus, we most probably
> > should change /bin/sh to /bin/ash for all scripts?
> > ---
> >  src/packages/fff/fff-babeld/Makefile          |   2 +-
> >  .../files/usr/lib/nodewatcher.d/80-babeld.sh  |  16 +
> >  src/packages/fff/fff-batman-adv/Makefile      |   2 +-
> >  .../usr/lib/nodewatcher.d/30-batman-adv.sh    |  60 ++++
> >  src/packages/fff/fff-network/Makefile         |   2 +-
> >  .../uci-defaults/94-fff-nodewatcher-network   |   9 +
> >  .../usr/lib/nodewatcher.d/20-interfaces.sh    |  74 ++++
> >  .../files/usr/lib/nodewatcher.d/50-clients.sh |  25 ++
> >  src/packages/fff/fff-nodewatcher/Makefile     |   2 +-
> >  .../files/etc/uci-defaults/93-fff-nodewatcher |   4 -
> >  .../usr/lib/nodewatcher.d/10-systemdata.sh    | 123 +++++++
> >  .../files/usr/sbin/nodewatcher                | 324 ++----------------
> >  src/packages/fff/fff-wireless/Makefile        |   2 +-
> >  .../files/usr/lib/nodewatcher.d/60-airtime.sh |  18 +
> >  14 files changed, 361 insertions(+), 302 deletions(-)
> >  create mode 100755 src/packages/fff/fff-
> babeld/files/usr/lib/nodewatcher.d/80-babeld.sh
> >  create mode 100755 src/packages/fff/fff-batman-
> adv/files/usr/lib/nodewatcher.d/30-batman-adv.sh
> >  create mode 100644 src/packages/fff/fff-network/files/etc/uci-defaults/94-
> fff-nodewatcher-network
> >  create mode 100755 src/packages/fff/fff-
> network/files/usr/lib/nodewatcher.d/20-interfaces.sh
> >  create mode 100755 src/packages/fff/fff-
> network/files/usr/lib/nodewatcher.d/50-clients.sh
> >  create mode 100755 src/packages/fff/fff-
> nodewatcher/files/usr/lib/nodewatcher.d/10-systemdata.sh
> >  create mode 100755 src/packages/fff/fff-
> wireless/files/usr/lib/nodewatcher.d/60-airtime.sh
> >
> > diff --git a/src/packages/fff/fff-babeld/Makefile b/src/packages/fff/fff-
> babeld/Makefile
> > index 29fd8e53..b2ccac89 100644
> > --- a/src/packages/fff/fff-babeld/Makefile
> > +++ b/src/packages/fff/fff-babeld/Makefile
> > @@ -1,7 +1,7 @@
> >  include $(TOPDIR)/rules.mk
> >
> >  PKG_NAME:=fff-babeld
> > -PKG_RELEASE:=1
> > +PKG_RELEASE:=2
> >
> >  PKG_BUILD_DIR:=$(BUILD_DIR)/fff-babeld
> >
> > diff --git a/src/packages/fff/fff-babeld/files/usr/lib/nodewatcher.d/80-
> babeld.sh b/src/packages/fff/fff-babeld/files/usr/lib/nodewatcher.d/80-
> babeld.sh
> > new file mode 100755
> > index 00000000..80196970
> > --- /dev/null
> > +++ b/src/packages/fff/fff-babeld/files/usr/lib/nodewatcher.d/80-babeld.sh
> > @@ -0,0 +1,16 @@
> > +#!/bin/sh
> > +
> > +if pgrep babeld >/dev/null; then
> > +	neighbours="$(echo dump | nc ::1 33123 | grep '^add neighbour' |
> > +		awk '{
> > +				for (i=2; i < NF; i += 2) {
> > +					vars[$i] = $(i+1)
> > +				}
> > +			}
> > +			{
> > +				printf
> "<neighbour><ip>%s</ip><outgoing_interface>%s</outgoing_interface><link_c
> ost>%s</link_cost></neighbour>", vars["address"], vars["if"], vars["cost"]
> > +			}')"
> > +	echo -n "<babel_neighbours>$neighbours</babel_neighbours>"
> > +fi
> > +
> > +exit 0
> > diff --git a/src/packages/fff/fff-batman-adv/Makefile b/src/packages/fff/fff-
> batman-adv/Makefile
> > index 9ef58042..9d553dc0 100644
> > --- a/src/packages/fff/fff-batman-adv/Makefile
> > +++ b/src/packages/fff/fff-batman-adv/Makefile
> > @@ -1,7 +1,7 @@
> >  include $(TOPDIR)/rules.mk
> >
> >  PKG_NAME:=fff-batman-adv
> > -PKG_RELEASE:=1
> > +PKG_RELEASE:=2
> >
> >  PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
> >
> > diff --git a/src/packages/fff/fff-batman-adv/files/usr/lib/nodewatcher.d/30-
> batman-adv.sh b/src/packages/fff/fff-batman-
> adv/files/usr/lib/nodewatcher.d/30-batman-adv.sh
> > new file mode 100755
> > index 00000000..37100a2d
> > --- /dev/null
> > +++ b/src/packages/fff/fff-batman-adv/files/usr/lib/nodewatcher.d/30-
> batman-adv.sh
> > @@ -0,0 +1,60 @@
> > +#!/bin/sh
> > +# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
> > +# License; GPL v3
> > +
> > +debug() {
> > +	(>&2 echo "$1")
> > +}
> > +
> > +debug "$(date): Collecting information from batman advanced and its
> interfaces"
> > +#B.A.T.M.A.N. advanced
> > +if [ -f /sys/module/batman_adv/version ]; then
> > +	for iface in $(batctl if | sed 's/ //'); do
> > +		status=${iface##*:}
> > +		iface=${iface%%:*}
> > +
> 	BATMAN_ADV_INTERFACES=$BATMAN_ADV_INTERFACES"<$iface><na
> me>$iface</name><status>$status</status></$iface>"
> > +	done
> > +
> > +	echo -n
> "<batman_adv_interfaces>$BATMAN_ADV_INTERFACES</batman_adv_interfac
> es>"
> > +
> > +	# Build a list of direct neighbors
> > +	batman_adv_originators=$(/usr/sbin/batctl o -H | awk \
> > +		'BEGIN { FS=" "; i=0 } # set the delimiter to " "
> > +		{   sub("\\(", "", $0) # remove parentheses
> > +			sub("\\)", "", $0)
> > +			sub("\\[", "", $0)
> > +			sub("\\]", "", $0)
> > +			sub("\\*", "", $0)
> > +			sub("  ", " ", $0)
> > +			o=$1".*"$1 # build a regex to find lines that contains the
> $1 (=originator) twice
> > +			if ($0 ~ o) # filter for this regex (will remove entries
> without direct neighbor)
> > +			{
> > +				printf
> "<originator_"i"><originator>"$1"</originator><link_quality>"$3"</link_quality>
> <nexthop>"$4"</nexthop><last_seen>"$2"</last_seen><outgoing_interface>"$
> 5"</outgoing_interface></originator_"i">"
> > +				i++
> > +			}
> > +		}')
> > +
> > +	echo -n
> "<batman_adv_originators>$batman_adv_originators</batman_adv_originators
> >"
> > +
> > +	echo -n "<batman_adv_gateway_mode>$(/usr/sbin/batctl
> gw)</batman_adv_gateway_mode>"
> > +
> > +	batman_adv_gateway_list=$(/usr/sbin/batctl gwl -H | awk \
> > +		'BEGIN { FS=" "; i=0 }
> > +		/No gateways/ { next }
> > +		{   sub("\\(", "", $0)
> > +			sub("\\)", "", $0)
> > +			sub("\\[ *", "", $0)
> > +			sub("\\]:", "", $0)
> > +			sub("\\* ", "true ", $0)
> > +			sub("  ", "false ", $0)
> > +			printf
> "<gateway_"i"><selected>"$1"</selected><gateway>"$2"</gateway><link_qual
> ity>"$3"</link_quality><nexthop>"$4"</nexthop><outgoing_interface>"$5"</o
> utgoing_interface><gw_class>"$6" "$7" "$8"</gw_class></gateway_"i">"
> > +			i++
> > +		}')
> > +
> > +	echo -n
> "<batman_adv_gateway_list>$batman_adv_gateway_list</batman_adv_gatew
> ay_list>"
> > +else
> > +	debug "$(date): No batman data .."
> > +	exit 1
> > +fi
> > +
> > +exit 0
> > diff --git a/src/packages/fff/fff-network/Makefile b/src/packages/fff/fff-
> network/Makefile
> > index 95f99e52..31928de8 100644
> > --- a/src/packages/fff/fff-network/Makefile
> > +++ b/src/packages/fff/fff-network/Makefile
> > @@ -1,7 +1,7 @@
> >  include $(TOPDIR)/rules.mk
> >
> >  PKG_NAME:=fff-network
> > -PKG_RELEASE:=12
> > +PKG_RELEASE:=13
> >
> >  PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
> >
> > diff --git a/src/packages/fff/fff-network/files/etc/uci-defaults/94-fff-
> nodewatcher-network b/src/packages/fff/fff-network/files/etc/uci-defaults/94-
> fff-nodewatcher-network
> > new file mode 100644
> > index 00000000..353ab1b4
> > --- /dev/null
> > +++ b/src/packages/fff/fff-network/files/etc/uci-defaults/94-fff-nodewatcher-
> network
> > @@ -0,0 +1,9 @@
> > +uci batch <<EOF
> > +  add nodewatcher network
> > +  set nodewatcher.@network[-1].mesh_interface='br-mesh'
> > +  set nodewatcher.@network[-1].iface_blacklist='lo ifb0'
> > +  set nodewatcher.@network[-1].ip_whitelist='br-mesh'
> > +EOF
> > +uci commit nodewatcher
> > +
> > +exit 0
> > diff --git a/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-
> interfaces.sh b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-
> interfaces.sh
> > new file mode 100755
> > index 00000000..5373d6ef
> > --- /dev/null
> > +++ b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/20-
> interfaces.sh
> > @@ -0,0 +1,74 @@
> > +#!/bin/sh
> > +# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
> > +# License; GPL v3
> > +
> > +IFACEBLACKLIST=$(uci get nodewatcher.@network[0].iface_blacklist)
> > +IPWHITELIST=$(uci get nodewatcher.@network[0].ip_whitelist)
> > +
> > +debug() {
> > +	(>&2 echo "$1")
> > +}
> > +
> > +inArray() {
> > +	local value
> > +	for value in $1; do
> > +		if [ "$value" = "$2" ]; then
> > +			return 0
> > +		fi
> > +	done
> > +	return 1
> > +}
> > +
> > +debug "$(date): Collecting information from network interfaces"
> > +
> > +#Get interfaces
> > +interface_data=""
> > +#Loop interfaces
> > +#for entry in $IFACES; do
> > +for filename in $(grep 'up\|unknown' /sys/class/net/*/operstate); do
> > +	ifpath=${filename%/operstate*}
> > +	iface=${ifpath#/sys/class/net/}
> > +	if inArray "$IFACEBLACKLIST" "$iface"; then
> > +		continue
> > +	fi
> > +
> > +	#Get interface data for whitelisted interfaces
> > +	# shellcheck disable=SC2016
> > +	awkscript='
> > +		/ether/ { printf "<mac_addr>"$2"</mac_addr>" }
> > +		/mtu/ { printf "<mtu>"$5"</mtu>" }'
> > +	if inArray "$IPWHITELIST" "$iface"; then
> > +		# shellcheck disable=SC2016
> > +		awkscript=$awkscript'
> > +			/inet / { split($2, a, "/"); printf
> "<ipv4_addr>"a[1]"</ipv4_addr>" }
> > +			/inet6/ && /scope global/ { printf
> "<ipv6_addr>"$2"</ipv6_addr>" }
> > +			/inet6/ && /scope link/ { printf
> "<ipv6_link_local_addr>"$2"</ipv6_link_local_addr>"}'
> > +	fi
> > +	addrs=$(ip addr show dev "${iface}" | awk "$awkscript")
> > +
> > +	traffic_rx=$(cat "$ifpath/statistics/rx_bytes")
> > +	traffic_tx=$(cat "$ifpath/statistics/tx_bytes")
> > +
> > +
> 	interface_data=$interface_data"<$iface><name>$iface</name>$addrs<
> traffic_rx>$traffic_rx</traffic_rx><traffic_tx>$traffic_tx</traffic_tx>"
> > +
> > +	interface_data=$interface_data$(iwconfig "${iface}" 2>/dev/null | awk -
> F':' '
> > +		/Mode/{ split($2, m, " "); printf
> "<wlan_mode>"m[1]"</wlan_mode>" }
> > +		/Cell/{ split($0, c, " "); printf "<wlan_bssid>"c[5]"</wlan_bssid>" }
> > +		/ESSID/ { split($0, e, "\""); printf
> "<wlan_essid>"e[2]"</wlan_essid>" }
> > +		/Freq/{ split($3, f, " "); printf
> "<wlan_frequency>"f[1]f[2]"</wlan_frequency>" }
> > +		/Tx-Power/{ split($0, p, "="); sub(/[[:space:]]*$/, "", p[2]); printf
> "<wlan_tx_power>"p[2]"</wlan_tx_power>" }
> > +	')
> > +
> > +	interface_data=$interface_data$(iw dev "${iface}" info 2>/dev/null | awk
> '
> > +		/ssid/{ split($0, s, " "); printf "<wlan_ssid>"s[2]"</wlan_ssid>" }
> > +		/type/ { split($0, t, " "); printf "<wlan_type>"t[2]"</wlan_type>" }
> > +		/channel/{ split($0, c, " "); printf
> "<wlan_channel>"c[2]"</wlan_channel>" }
> > +		/width/{ split($0, w, ": "); sub(/ .*/, "", w[2]); printf
> "<wlan_width>"w[2]"</wlan_width>" }
> > +	')
> > +
> > +	interface_data=$interface_data"</$iface>"
> > +done
> > +
> > +echo -n "<interface_data>$interface_data</interface_data>"
> > +
> > +exit 0
> > diff --git a/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-
> clients.sh b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-
> clients.sh
> > new file mode 100755
> > index 00000000..91d9b868
> > --- /dev/null
> > +++ b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh
> > @@ -0,0 +1,25 @@
> > +#!/bin/sh
> > +# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
> > +# License; GPL v3
> > +
> > +MESH_INTERFACE=$(uci get nodewatcher.@network[0].mesh_interface)
> > +
> > +debug() {
> > +	(>&2 echo "$1")
> > +}
> > +
> > +debug "$(date): Collecting information about connected clients"
> > +
> > +client_count=0
> > +dataclient=""
> > +CLIENT_INTERFACES=$(ls "/sys/class/net/$MESH_INTERFACE/brif" | grep -v
> '^bat')
> > +for clientif in ${CLIENT_INTERFACES}; do
> > +	local cc=$(bridge fdb show br "$MESH_INTERFACE" brport "$clientif" |
> grep -v self | grep -v permanent -c)
> > +	client_count=$((client_count + cc))
> > +	dataclient="$dataclient<$clientif>$cc</$clientif>"
> > +done
> > +
> > +echo -n "<client_count>$client_count</client_count>"
> > +echo -n "<clients>$dataclient</clients>"
> > +
> > +exit 0
> > diff --git a/src/packages/fff/fff-nodewatcher/Makefile b/src/packages/fff/fff-
> nodewatcher/Makefile
> > index 0ed6684d..423b7288 100644
> > --- a/src/packages/fff/fff-nodewatcher/Makefile
> > +++ b/src/packages/fff/fff-nodewatcher/Makefile
> > @@ -1,7 +1,7 @@
> >  include $(TOPDIR)/rules.mk
> >
> >  PKG_NAME:=fff-nodewatcher
> > -PKG_RELEASE:=55
> > +PKG_RELEASE:=56
> >
> >  PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
> >
> > diff --git a/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-
> nodewatcher b/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-
> nodewatcher
> > index 4e564352..0fc2e90e 100644
> > --- a/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-
> nodewatcher
> > +++ b/src/packages/fff/fff-nodewatcher/files/etc/uci-defaults/93-fff-
> nodewatcher
> > @@ -8,10 +8,6 @@ uci batch <<EOF
> >    set nodewatcher.@script[0].logfile='/var/log/nodewatcher.log'
> >    set nodewatcher.@script[0].data_file='/tmp/crawldata/node.data'
> >    set nodewatcher.@script[0].status_text_file='/tmp/status.txt'
> > -  add nodewatcher network
> > -  set nodewatcher.@network[0].mesh_interface='br-mesh'
> > -  set nodewatcher.@network[0].iface_blacklist='lo ifb0'
> > -  set nodewatcher.@network[0].ip_whitelist='br-mesh'
> >  EOF
> >  uci commit
> >
> > diff --git a/src/packages/fff/fff-nodewatcher/files/usr/lib/nodewatcher.d/10-
> systemdata.sh b/src/packages/fff/fff-
> nodewatcher/files/usr/lib/nodewatcher.d/10-systemdata.sh
> > new file mode 100755
> > index 00000000..713cea6c
> > --- /dev/null
> > +++ b/src/packages/fff/fff-nodewatcher/files/usr/lib/nodewatcher.d/10-
> systemdata.sh
> > @@ -0,0 +1,123 @@
> > +#!/bin/sh
> > +# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
> > +# License; GPL v3
> > +
> > +SCRIPT_STATUS_FILE=$(uci get nodewatcher.@script[0].status_text_file)
> > +SCRIPT_VERSION="56"
> > +
> > +debug() {
> > +	(>&2 echo "$1")
> > +}
> > +
> > +#Get system data from other locations
> > +debug "$(date): Collecting basic system status data"
> > +hostname="$(cat /proc/sys/kernel/hostname)"
> > +mac=$(awk '{ mac=toupper($1); gsub(":", "", mac); print mac }'
> /sys/class/net/br-mesh/address 2>/dev/null)
> > +[ "$hostname" = "OpenWrt" ] && hostname="$mac"
> > +[ "$hostname" = "FFF" ] && hostname="$mac"
> > +description="$(uci -q get fff.system.description)"
> > +if [ -n "$description" ]; then
> > +	description="<description><![CDATA[$description]]></description>"
> > +fi
> > +latitude="$(uci -q get fff.system.latitude)"
> > +longitude="$(uci -q get fff.system.longitude)"
> > +if [ -n "$longitude" -a -n "$latitude" ]; then
> > +	geo="<geo><lat>$latitude</lat><lng>$longitude</lng></geo>";
> > +fi
> > +position_comment="$(uci -q get fff.system.position_comment)"
> > +if [ -n "$position_comment" ]; then
> > +
> 	position_comment="<position_comment><![CDATA[$position_commen
> t]]></position_comment>"
> > +fi
> > +contact="$(uci -q get fff.system.contact)"
> > +if [ -n "$contact" ]; then
> > +	contact="<contact>$contact</contact>"
> > +fi
> > +uptime=$(awk '{ printf "<uptime>"$1"</uptime><idletime>"$2"</idletime>"
> }' /proc/uptime)
> > +
> > +memory=$(awk '
> > +	/^MemTotal/ { printf "<memory_total>"$2"</memory_total>" }
> > +	/^Cached:/ { printf "<memory_caching>"$2"</memory_caching>" }
> > +	/^Buffers/ { printf "<memory_buffering>"$2"</memory_buffering>" }
> > +	/^MemFree/ { printf "<memory_free>"$2"</memory_free>" }
> > +' /proc/meminfo)
> > +cpu=$(awk -F': ' '
> > +	/model/ { printf "<cpu>"$2"</cpu>" }
> > +	/system type/ { printf "<chipset>"$2"</chipset>" }
> > +	/platform/ { printf "<chipset>"$2"</chipset>" }
> > +' /proc/cpuinfo)
> > +model="<model>$(cat /var/sysinfo/model)</model>"
> > +local_time="$(date +%s)"
> > +load=$(awk '{ printf
> "<loadavg>"$3"</loadavg><processes>"$4"</processes>" }' /proc/loadavg)
> > +
> > +debug "$(date): Collecting version information"
> > +
> > +batman_adv_version=$(cat /sys/module/batman_adv/version)
> > +kernel_version=$(uname -r)
> > +if [ -x /usr/bin/fastd ]; then
> > +	fastd_version="<fastd_version>$(/usr/bin/fastd -v | awk '{ print $2
> }')</fastd_version>"
> > +fi
> > +nodewatcher_version=$SCRIPT_VERSION
> > +if [ -x /usr/sbin/babeld ]; then
> > +	babel_version="<babel_version>$(/usr/sbin/babeld -V
> 2>&1)</babel_version>"
> > +fi
> > +
> > +if [ -f "$SCRIPT_STATUS_FILE" ]; then
> > +	status_text="<status_text>$(cat
> "$SCRIPT_STATUS_FILE")</status_text>"
> > +fi
> > +
> > +# Checks if fastd is running
> > +if pidof fastd >/dev/null ; then
> > +	vpn_active="<vpn_active>1</vpn_active>"
> > +else
> > +	vpn_active="<vpn_active>0</vpn_active>"
> > +fi
> > +
> > +# example for /etc/openwrt_release:
> > +#DISTRIB_ID="OpenWrt"
> > +#DISTRIB_RELEASE="Attitude Adjustment"
> > +#DISTRIB_REVISION="r35298"
> > +#DISTRIB_CODENAME="attitude_adjustment"
> > +#DISTRIB_TARGET="atheros/generic"
> > +#DISTRIB_DESCRIPTION="OpenWrt Attitude Adjustment 12.09-rc1"
> > +. /etc/openwrt_release
> > +distname=$DISTRIB_ID
> > +distversion=$DISTRIB_RELEASE
> > +
> > +# example for /etc/firmware_release:
> > +#FIRMWARE_VERSION="95f36685e7b6cbf423f02cf5c7f1e785fd4ccdae-dirty"
> > +#BUILD_DATE="build date: Di 29. Jan 19:33:34 CET 2013"
> > +#OPENWRT_CORE_REVISION="35298"
> > +#OPENWRT_FEEDS_PACKAGES_REVISION="35298"
> > +. /etc/firmware_release
> > +
> > +SYSTEM_DATA="<status>online</status>"
> > +SYSTEM_DATA=$SYSTEM_DATA"$status_text"
> > +SYSTEM_DATA=$SYSTEM_DATA"<hostname>$hostname</hostname>"
> > +SYSTEM_DATA=$SYSTEM_DATA"${description}"
> > +SYSTEM_DATA=$SYSTEM_DATA"${geo}"
> > +SYSTEM_DATA=$SYSTEM_DATA"${position_comment}"
> > +SYSTEM_DATA=$SYSTEM_DATA"${contact}"
> > +SYSTEM_DATA=$SYSTEM_DATA"<hood>$(uci -q get
> "system.@system[0].hood")</hood>"
> > +SYSTEM_DATA=$SYSTEM_DATA"<hoodid>$(uci -q get
> "system.@system[0].hoodid")</hoodid>"
> > +SYSTEM_DATA=$SYSTEM_DATA"<distname>$distname</distname>"
> > +SYSTEM_DATA=$SYSTEM_DATA"<distversion>$distversion</distversion>"
> > +SYSTEM_DATA=$SYSTEM_DATA"$cpu"
> > +SYSTEM_DATA=$SYSTEM_DATA"$model"
> > +SYSTEM_DATA=$SYSTEM_DATA"$memory"
> > +SYSTEM_DATA=$SYSTEM_DATA"$load"
> > +SYSTEM_DATA=$SYSTEM_DATA"$uptime"
> > +SYSTEM_DATA=$SYSTEM_DATA"<local_time>$local_time</local_time>"
> >
> +SYSTEM_DATA=$SYSTEM_DATA"<batman_advanced_version>$batman_adv_v
> ersion</batman_advanced_version>"
> >
> +SYSTEM_DATA=$SYSTEM_DATA"<kernel_version>$kernel_version</kernel_ve
> rsion>"
> > +SYSTEM_DATA=$SYSTEM_DATA"$fastd_version"
> >
> +SYSTEM_DATA=$SYSTEM_DATA"<nodewatcher_version>$nodewatcher_versio
> n</nodewatcher_version>"
> > +SYSTEM_DATA=$SYSTEM_DATA"$babel_version"
> >
> +SYSTEM_DATA=$SYSTEM_DATA"<firmware_version>$FIRMWARE_VERSION</fi
> rmware_version>"
> >
> +SYSTEM_DATA=$SYSTEM_DATA"<firmware_revision>$BUILD_DATE</firmware
> _revision>"
> >
> +SYSTEM_DATA=$SYSTEM_DATA"<openwrt_core_revision>$OPENWRT_CORE_R
> EVISION</openwrt_core_revision>"
> >
> +SYSTEM_DATA=$SYSTEM_DATA"<openwrt_feeds_packages_revision>$OPENW
> RT_FEEDS_PACKAGES_REVISION</openwrt_feeds_packages_revision>"
> > +SYSTEM_DATA=$SYSTEM_DATA"$vpn_active"
> > +
> > +echo -n "<system_data>$SYSTEM_DATA</system_data>"
> > +
> > +exit 0
> > diff --git a/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
> b/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
> > index 42e5ce8f..21880fbe 100755
> > --- a/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
> > +++ b/src/packages/fff/fff-nodewatcher/files/usr/sbin/nodewatcher
> > @@ -7,327 +7,65 @@ test -f /tmp/started || exit
> >  # Allow only one instance
> >  lockfile="/var/lock/${0##*/}.lock"
> >  if ! lock -n "$lockfile"; then
> > -        echo "Only one instance of $0 allowed."
> > -        exit 1
> > +	echo "Only one instance of $0 allowed."
> > +	exit 1
> >  fi
> >  trap "lock -u \"$lockfile\"" INT TERM EXIT
> >
> > -SCRIPT_VERSION="55"
> > +[ -s /etc/config/nodewatcher ] || exit 1
> >
> > -#Get the configuration from the uci configuration file
> > -#If it does not exists, then get it from a normal bash file with variables.
> > -if [ -f /etc/config/nodewatcher ];then
> > -    SCRIPT_ERROR_LEVEL=$(uci get nodewatcher.@script[0].error_level)
> > -    SCRIPT_LOGFILE=$(uci get nodewatcher.@script[0].logfile)
> > -    SCRIPT_DATA_FILE=$(uci get nodewatcher.@script[0].data_file)
> > -    MESH_INTERFACE=$(uci get nodewatcher.@network[0].mesh_interface)
> > -    IFACEBLACKLIST=$(uci get nodewatcher.@network[0].iface_blacklist)
> > -    IPWHITELIST=$(uci get nodewatcher.@network[0].ip_whitelist)
> > -    SCRIPT_STATUS_FILE=$(uci get nodewatcher.@script[0].status_text_file)
> > -else
> > -    . "$(dirname "$0")/nodewatcher_config"
> > -fi
> > +SCRIPT_ERROR_LEVEL=$(uci get nodewatcher.@script[0].error_level)
> > +SCRIPT_LOGFILE=$(uci get nodewatcher.@script[0].logfile)
> > +SCRIPT_DATA_FILE=$(uci get nodewatcher.@script[0].data_file)
> >
> >  if [ "$SCRIPT_ERROR_LEVEL" -gt "1" ]; then
> > -    err() {
> > -        echo "$1" >> "$SCRIPT_LOGFILE"
> > -    }
> > +	debug() {
> > +		echo "$1" >> "$SCRIPT_LOGFILE"
> > +	}
> >  else
> > -    err() {
> > -        :
> > -    }
> > +	debug() {
> > +		:
> > +	}
> >  fi
> >
> >  #This method checks if the log file has become too big and deletes the first X
> lines
> >  delete_log() {
> > -    if [ -f "$SCRIPT_LOGFILE" ]; then
> > -        if [ "$(find "$SCRIPT_LOGFILE" -printf "%s")" -gt "6000" ]; then
> > -            sed -i '1,60d' "$SCRIPT_LOGFILE"
> > -            err "$(date): Logfile has been made smaller"
> > -        fi
> > -    fi
> > -}
> > -
> > -inArray() {
> > -    local value
> > -    for value in $1; do
> > -        if [ "$value" = "$2" ]; then
> > -            return 0
> > -        fi
> > -    done
> > -    return 1
> > +	if [ -f "$SCRIPT_LOGFILE" ]; then
> > +		if [ "$(find "$SCRIPT_LOGFILE" -printf "%s")" -gt "6000" ]; then
> > +			sed -i '1,60d' "$SCRIPT_LOGFILE"
> > +			debug "$(date): Logfile has been made smaller"
> > +		fi
> > +	fi
> >  }
> >
> >  #This method generates the crawl data XML file that is being fetched by
> netmon
> >  #and provided by a small local httpd
> >  crawl() {
> > -    #Get system data from other locations
> > -    err "$(date): Collecting basic system status data"
> > -    hostname="$(cat /proc/sys/kernel/hostname)"
> > -    mac=$(awk '{ mac=toupper($1); gsub(":", "", mac); print mac }'
> /sys/class/net/br-mesh/address 2>/dev/null)
> > -    [ "$hostname" = "OpenWrt" ] && hostname="$mac"
> > -    [ "$hostname" = "FFF" ] && hostname="$mac"
> > -    description="$(uci -q get fff.system.description)"
> > -    if [ -n "$description" ]; then
> > -        description="<description><![CDATA[$description]]></description>"
> > -    fi
> > -    latitude="$(uci -q get fff.system.latitude)"
> > -    longitude="$(uci -q get fff.system.longitude)"
> > -    if [ -n "$longitude" -a -n "$latitude" ]; then
> > -        geo="<geo><lat>$latitude</lat><lng>$longitude</lng></geo>";
> > -    fi
> > -    position_comment="$(uci -q get fff.system.position_comment)"
> > -    if [ -n "$position_comment" ]; then
> > -
> position_comment="<position_comment><![CDATA[$position_comment]]></p
> osition_comment>"
> > -    fi
> > -    contact="$(uci -q get fff.system.contact)"
> > -    if [ -n "$contact" ]; then
> > -        contact="<contact>$contact</contact>"
> > -    fi
> > -    uptime=$(awk '{ printf "<uptime>"$1"</uptime><idletime>"$2"</idletime>"
> }' /proc/uptime)
> > -
> > -    memory=$(awk '
> > -        /^MemTotal/ { printf "<memory_total>"$2"</memory_total>" }
> > -        /^Cached:/ { printf "<memory_caching>"$2"</memory_caching>" }
> > -        /^Buffers/ { printf "<memory_buffering>"$2"</memory_buffering>" }
> > -        /^MemFree/ { printf "<memory_free>"$2"</memory_free>" }
> > -    ' /proc/meminfo)
> > -    cpu=$(awk -F': ' '
> > -        /model/ { printf "<cpu>"$2"</cpu>" }
> > -        /system type/ { printf "<chipset>"$2"</chipset>" }
> > -        /platform/ { printf "<chipset>"$2"</chipset>" }
> > -    ' /proc/cpuinfo)
> > -    model="<model>$(cat /var/sysinfo/model)</model>"
> > -    local_time="$(date +%s)"
> > -    load=$(awk '{ printf
> "<loadavg>"$3"</loadavg><processes>"$4"</processes>" }' /proc/loadavg)
> > -
> > -    err "$(date): Collecting version information"
> > -
> > -    batman_adv_version=$(cat /sys/module/batman_adv/version)
> > -    kernel_version=$(uname -r)
> > -    if [ -x /usr/bin/fastd ]; then
> > -        fastd_version="<fastd_version>$(/usr/bin/fastd -v | awk '{ print $2
> }')</fastd_version>"
> > -    fi
> > -    nodewatcher_version=$SCRIPT_VERSION
> > -    if [ -x /usr/sbin/babeld ]; then
> > -        babel_version="<babel_version>$(/usr/sbin/babeld -V
> 2>&1)</babel_version>"
> > -    fi
> > -
> > -    if [ -f "$SCRIPT_STATUS_FILE" ]; then
> > -        status_text="<status_text>$(cat "$SCRIPT_STATUS_FILE")</status_text>"
> > -    fi
> > -
> > -    # Checks if fastd is running
> > -    if pidof fastd >/dev/null ; then
> > -        vpn_active="<vpn_active>1</vpn_active>"
> > -    else
> > -        vpn_active="<vpn_active>0</vpn_active>"
> > -    fi
> > -
> > -    # example for /etc/openwrt_release:
> > -    #DISTRIB_ID="OpenWrt"
> > -    #DISTRIB_RELEASE="Attitude Adjustment"
> > -    #DISTRIB_REVISION="r35298"
> > -    #DISTRIB_CODENAME="attitude_adjustment"
> > -    #DISTRIB_TARGET="atheros/generic"
> > -    #DISTRIB_DESCRIPTION="OpenWrt Attitude Adjustment 12.09-rc1"
> > -    . /etc/openwrt_release
> > -    distname=$DISTRIB_ID
> > -    distversion=$DISTRIB_RELEASE
> > -
> > -    # example for /etc/firmware_release:
> > -    #FIRMWARE_VERSION="95f36685e7b6cbf423f02cf5c7f1e785fd4ccdae-dirty"
> > -    #BUILD_DATE="build date: Di 29. Jan 19:33:34 CET 2013"
> > -    #OPENWRT_CORE_REVISION="35298"
> > -    #OPENWRT_FEEDS_PACKAGES_REVISION="35298"
> > -    . /etc/firmware_release
> > -
> > -    SYSTEM_DATA="<status>online</status>"
> > -    SYSTEM_DATA=$SYSTEM_DATA"$status_text"
> > -    SYSTEM_DATA=$SYSTEM_DATA"<hostname>$hostname</hostname>"
> > -    SYSTEM_DATA=$SYSTEM_DATA"${description}"
> > -    SYSTEM_DATA=$SYSTEM_DATA"${geo}"
> > -    SYSTEM_DATA=$SYSTEM_DATA"${position_comment}"
> > -    SYSTEM_DATA=$SYSTEM_DATA"${contact}"
> > -    SYSTEM_DATA=$SYSTEM_DATA"<hood>$(uci -q get
> "system.@system[0].hood")</hood>"
> > -    SYSTEM_DATA=$SYSTEM_DATA"<hoodid>$(uci -q get
> "system.@system[0].hoodid")</hoodid>"
> > -    SYSTEM_DATA=$SYSTEM_DATA"<distname>$distname</distname>"
> > -    SYSTEM_DATA=$SYSTEM_DATA"<distversion>$distversion</distversion>"
> > -    SYSTEM_DATA=$SYSTEM_DATA"$cpu"
> > -    SYSTEM_DATA=$SYSTEM_DATA"$model"
> > -    SYSTEM_DATA=$SYSTEM_DATA"$memory"
> > -    SYSTEM_DATA=$SYSTEM_DATA"$load"
> > -    SYSTEM_DATA=$SYSTEM_DATA"$uptime"
> > -    SYSTEM_DATA=$SYSTEM_DATA"<local_time>$local_time</local_time>"
> > -
> SYSTEM_DATA=$SYSTEM_DATA"<batman_advanced_version>$batman_adv_ver
> sion</batman_advanced_version>"
> > -
> SYSTEM_DATA=$SYSTEM_DATA"<kernel_version>$kernel_version</kernel_vers
> ion>"
> > -    SYSTEM_DATA=$SYSTEM_DATA"$fastd_version"
> > -
> SYSTEM_DATA=$SYSTEM_DATA"<nodewatcher_version>$nodewatcher_version
> </nodewatcher_version>"
> > -    SYSTEM_DATA=$SYSTEM_DATA"$babel_version"
> > -
> SYSTEM_DATA=$SYSTEM_DATA"<firmware_version>$FIRMWARE_VERSION</fir
> mware_version>"
> > -
> SYSTEM_DATA=$SYSTEM_DATA"<firmware_revision>$BUILD_DATE</firmware_r
> evision>"
> > -
> SYSTEM_DATA=$SYSTEM_DATA"<openwrt_core_revision>$OPENWRT_CORE_RE
> VISION</openwrt_core_revision>"
> > -
> SYSTEM_DATA=$SYSTEM_DATA"<openwrt_feeds_packages_revision>$OPENWR
> T_FEEDS_PACKAGES_REVISION</openwrt_feeds_packages_revision>"
> > -    SYSTEM_DATA=$SYSTEM_DATA"$vpn_active"
> > -
> > -    err "$(date): Collecting information from network interfaces"
> > -
> > -    #Get interfaces
> > -    interface_data=""
> > -    #Loop interfaces
> > -    #for entry in $IFACES; do
> > -    for filename in $(grep 'up\|unknown' /sys/class/net/*/operstate); do
> > -        ifpath=${filename%/operstate*}
> > -        iface=${ifpath#/sys/class/net/}
> > -        if inArray "$IFACEBLACKLIST" "$iface"; then
> > -            continue
> > -        fi
> > -
> > -        #Get interface data for whitelisted interfaces
> > -        # shellcheck disable=SC2016
> > -        awkscript='
> > -            /ether/ { printf "<mac_addr>"$2"</mac_addr>" }
> > -            /mtu/ { printf "<mtu>"$5"</mtu>" }'
> > -        if inArray "$IPWHITELIST" "$iface"; then
> > -            # shellcheck disable=SC2016
> > -            awkscript=$awkscript'
> > -                /inet / { split($2, a, "/"); printf "<ipv4_addr>"a[1]"</ipv4_addr>" }
> > -                /inet6/ && /scope global/ { printf "<ipv6_addr>"$2"</ipv6_addr>" }
> > -                /inet6/ && /scope link/ { printf
> "<ipv6_link_local_addr>"$2"</ipv6_link_local_addr>"}'
> > -        fi
> > -        addrs=$(ip addr show dev "${iface}" | awk "$awkscript")
> > -
> > -        traffic_rx=$(cat "$ifpath/statistics/rx_bytes")
> > -        traffic_tx=$(cat "$ifpath/statistics/tx_bytes")
> > -
> > -
> interface_data=$interface_data"<$iface><name>$iface</name>$addrs<traffic_r
> x>$traffic_rx</traffic_rx><traffic_tx>$traffic_tx</traffic_tx>"
> > -
> > -        interface_data=$interface_data$(iwconfig "${iface}" 2>/dev/null | awk -
> F':' '
> > -            /Mode/{ split($2, m, " "); printf "<wlan_mode>"m[1]"</wlan_mode>" }
> > -            /Cell/{ split($0, c, " "); printf "<wlan_bssid>"c[5]"</wlan_bssid>" }
> > -            /ESSID/ { split($0, e, "\""); printf "<wlan_essid>"e[2]"</wlan_essid>" }
> > -            /Freq/{ split($3, f, " "); printf
> "<wlan_frequency>"f[1]f[2]"</wlan_frequency>" }
> > -            /Tx-Power/{ split($0, p, "="); sub(/[[:space:]]*$/, "", p[2]); printf
> "<wlan_tx_power>"p[2]"</wlan_tx_power>" }
> > -        ')
> > -
> > -        interface_data=$interface_data$(iw dev "${iface}" info 2>/dev/null | awk '
> > -            /ssid/{ split($0, s, " "); printf "<wlan_ssid>"s[2]"</wlan_ssid>" }
> > -            /type/ { split($0, t, " "); printf "<wlan_type>"t[2]"</wlan_type>" }
> > -            /channel/{ split($0, c, " "); printf
> "<wlan_channel>"c[2]"</wlan_channel>" }
> > -            /width/{ split($0, w, ": "); sub(/ .*/, "", w[2]); printf
> "<wlan_width>"w[2]"</wlan_width>" }
> > -        ')
> > -
> > -        interface_data=$interface_data"</$iface>"
> > -    done
> > -
> > -    err "$(date): Collecting information from batman advanced and its
> interfaces"
> > -    #B.A.T.M.A.N. advanced
> > -    if [ -f /sys/module/batman_adv/version ]; then
> > -        for iface in $(batctl if | sed 's/ //'); do
> > -            status=${iface##*:}
> > -            iface=${iface%%:*}
> > -
> BATMAN_ADV_INTERFACES=$BATMAN_ADV_INTERFACES"<$iface><name>$ifa
> ce</name><status>$status</status></$iface>"
> > -        done
> > -
> > -        # Build a list of direct neighbors
> > -        batman_adv_originators=$(/usr/sbin/batctl o -H | awk \
> > -            'BEGIN { FS=" "; i=0 } # set the delimiter to " "
> > -            {   sub("\\(", "", $0) # remove parentheses
> > -                sub("\\)", "", $0)
> > -                sub("\\[", "", $0)
> > -                sub("\\]", "", $0)
> > -                sub("\\*", "", $0)
> > -                sub("  ", " ", $0)
> > -                o=$1".*"$1 # build a regex to find lines that contains the $1
> (=originator) twice
> > -                if ($0 ~ o) # filter for this regex (will remove entries without direct
> neighbor)
> > -                {
> > -                    printf
> "<originator_"i"><originator>"$1"</originator><link_quality>"$3"</link_quality>
> <nexthop>"$4"</nexthop><last_seen>"$2"</last_seen><outgoing_interface>"$
> 5"</outgoing_interface></originator_"i">"
> > -                    i++
> > -                }
> > -            }')
> > -
> > -        batman_adv_gateway_mode=$(/usr/sbin/batctl gw)
> > -
> > -        batman_adv_gateway_list=$(/usr/sbin/batctl gwl -H | awk \
> > -            'BEGIN { FS=" "; i=0 }
> > -            /No gateways/ { next }
> > -            {   sub("\\(", "", $0)
> > -                sub("\\)", "", $0)
> > -                sub("\\[ *", "", $0)
> > -                sub("\\]:", "", $0)
> > -                sub("\\* ", "true ", $0)
> > -                sub("  ", "false ", $0)
> > -                printf
> "<gateway_"i"><selected>"$1"</selected><gateway>"$2"</gateway><link_qual
> ity>"$3"</link_quality><nexthop>"$4"</nexthop><outgoing_interface>"$5"</o
> utgoing_interface><gw_class>"$6" "$7" "$8"</gw_class></gateway_"i">"
> > -                i++
> > -            }')
> > -    fi
> > -    err "$(date): Collecting information about conected clients"
> > -    #CLIENTS
> > -    client_count=0
> > -    dataclient=""
> > -    CLIENT_INTERFACES=$(ls "/sys/class/net/$MESH_INTERFACE/brif" | grep -v
> '^bat')
> > -    for clientif in ${CLIENT_INTERFACES}; do
> > -        local cc=$(bridge fdb show br "$MESH_INTERFACE" brport "$clientif" | grep
> -v self | grep -v permanent -c)
> > -        client_count=$((client_count + cc))
> > -        dataclient="$dataclient<$clientif>$cc</$clientif>"
> > -    done
> > -
> > -    dataair=""
> > -    w2dump="$(iw dev w2ap survey dump 2> /dev/null | sed '/Survey/,/\[in
> use\]/d')"
> > -    if [ -n "$w2dump" ] ; then
> > -        w2_ACT="$(ACTIVE=$(echo "$w2dump" | grep "active time:"); set
> ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
> > -        w2_BUS="$(BUSY=$(echo "$w2dump" | grep "busy time:"); set ${BUSY:-0
> 0 0 0 0}; echo -e "${4}")"
> > -
> dataair="$dataair<airtime2><active>$w2_ACT</active><busy>$w2_BUS</busy>
> </airtime2>"
> > -    fi
> > -    w5dump="$(iw dev w5ap survey dump 2> /dev/null | sed '/Survey/,/\[in
> use\]/d')"
> > -    if [ -n "$w5dump" ] ; then
> > -        w5_ACT="$(ACTIVE=$(echo "$w5dump" | grep "active time:"); set
> ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
> > -        w5_BUS="$(BUSY=$(echo "$w5dump" | grep "busy time:"); set ${BUSY:-0
> 0 0 0 0}; echo -e "${4}")"
> > -
> dataair="$dataair<airtime5><active>$w5_ACT</active><busy>$w5_BUS</busy>
> </airtime5>"
> > -    fi
> > +	debug "$(date): Putting all information into a XML-File and save it at
> $SCRIPT_DATA_FILE"
> >
> > -    if pgrep babeld >/dev/null; then
> > -        neighbours="$(echo dump | nc ::1 33123 | grep '^add neighbour' |
> > -            awk '{
> > -                   for (i=2; i < NF; i += 2) {
> > -                     vars[$i] = $(i+1)
> > -                   }
> > -                 }
> > -                 {
> > -                   printf
> "<neighbour><ip>%s</ip><outgoing_interface>%s</outgoing_interface><link_c
> ost>%s</link_cost></neighbour>", vars["address"], vars["if"], vars["cost"]
> > -                 }')"
> > -        BABELS="<babel_neighbours>$neighbours</babel_neighbours>"
> > -    fi
> > +	DATA="<?xml version='1.0' standalone='yes'?><data>"
> >
> > -    err "$(date): Putting all information into a XML-File and save it at
> $SCRIPT_DATA_FILE"
> > +	for f in /usr/lib/nodewatcher.d/*.sh; do
> > +		tmp="$($f)"
> > +		DATA="$DATA$tmp"
> > +	done
> >
> > -    DATA="<?xml version='1.0' standalone='yes'?><data>"
> > -    DATA=$DATA"<system_data>$SYSTEM_DATA</system_data>"
> > -    DATA=$DATA"<interface_data>$interface_data</interface_data>"
> > -
> DATA=$DATA"<batman_adv_interfaces>$BATMAN_ADV_INTERFACES</batman
> _adv_interfaces>"
> > -
> DATA=$DATA"<batman_adv_originators>$batman_adv_originators</batman_ad
> v_originators>"
> > -
> DATA=$DATA"<batman_adv_gateway_mode>$batman_adv_gateway_mode</b
> atman_adv_gateway_mode>"
> > -
> DATA=$DATA"<batman_adv_gateway_list>$batman_adv_gateway_list</batma
> n_adv_gateway_list>"
> > -    DATA=$DATA"$BABELS"
> > -    DATA=$DATA"<client_count>$client_count</client_count>"
> > -    DATA=$DATA"<clients>$dataclient</clients>"
> > -    DATA=$DATA"$dataair"
> > -    DATA=$DATA"</data>"
> > +	DATA="$DATA</data>"
> >
> > -    #write data to xml file that provides the data on httpd
> > -    SCRIPT_DATA_DIR=$(dirname "$SCRIPT_DATA_FILE")
> > -    test -d "$SCRIPT_DATA_DIR" || mkdir -p "$SCRIPT_DATA_DIR"
> > -    echo "$DATA" | gzip | tee "$SCRIPT_DATA_FILE" | alfred -s 64
> > +	#write data to xml file that provides the data on httpd
> > +	SCRIPT_DATA_DIR=$(dirname "$SCRIPT_DATA_FILE")
> > +	test -d "$SCRIPT_DATA_DIR" || mkdir -p "$SCRIPT_DATA_DIR"
> > +	echo "$DATA" | gzip | tee "$SCRIPT_DATA_FILE" | alfred -s 64
> >  }
> >
> >  LANG=C
> >
> >  #Prüft ob das logfile zu groß geworden ist
> > -err "$(date): Check logfile"
> > +debug "$(date): Check logfile"
> >  delete_log
> >
> >  #Erzeugt die statusdaten
> > -err "$(date): Generate actual status data"
> > +debug "$(date): Generate actual status data"
> >  crawl
> >
> >  exit 0
> > diff --git a/src/packages/fff/fff-wireless/Makefile b/src/packages/fff/fff-
> wireless/Makefile
> > index 00b1c7ca..e805ea22 100644
> > --- a/src/packages/fff/fff-wireless/Makefile
> > +++ b/src/packages/fff/fff-wireless/Makefile
> > @@ -1,7 +1,7 @@
> >  include $(TOPDIR)/rules.mk
> >
> >  PKG_NAME:=fff-wireless
> > -PKG_RELEASE:=13
> > +PKG_RELEASE:=14
> >
> >  PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
> >
> > diff --git a/src/packages/fff/fff-wireless/files/usr/lib/nodewatcher.d/60-
> airtime.sh b/src/packages/fff/fff-wireless/files/usr/lib/nodewatcher.d/60-
> airtime.sh
> > new file mode 100755
> > index 00000000..ca53d904
> > --- /dev/null
> > +++ b/src/packages/fff/fff-wireless/files/usr/lib/nodewatcher.d/60-airtime.sh
> > @@ -0,0 +1,18 @@
> > +#!/bin/sh
> > +# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg
> > +# License; GPL v3
> > +
> > +w2dump="$(iw dev w2ap survey dump 2> /dev/null | sed '/Survey/,/\[in
> use\]/d')"
> > +if [ -n "$w2dump" ] ; then
> > +	w2_ACT="$(ACTIVE=$(echo "$w2dump" | grep "active time:"); set
> ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
> > +	w2_BUS="$(BUSY=$(echo "$w2dump" | grep "busy time:"); set ${BUSY:-0
> 0 0 0 0}; echo -e "${4}")"
> > +	echo -n
> "$dataair<airtime2><active>$w2_ACT</active><busy>$w2_BUS</busy></airtim
> e2>"
> > +fi
> > +w5dump="$(iw dev w5ap survey dump 2> /dev/null | sed '/Survey/,/\[in
> use\]/d')"
> > +if [ -n "$w5dump" ] ; then
> > +	w5_ACT="$(ACTIVE=$(echo "$w5dump" | grep "active time:"); set
> ${ACTIVE:-0 0 0 0 0}; echo -e "${4}")"
> > +	w5_BUS="$(BUSY=$(echo "$w5dump" | grep "busy time:"); set ${BUSY:-0
> 0 0 0 0}; echo -e "${4}")"
> > +	echo -n
> "$dataair<airtime5><active>$w5_ACT</active><busy>$w5_BUS</busy></airtim
> e5>"
> > +fi
> > +
> > +exit 0
> >
Adrian Schmutzler Jan. 7, 2020, 10:41 p.m.
> a/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh
> b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-clients.sh
> new file mode 100755
> index 00000000..91d9b868
> --- /dev/null
> +++ b/src/packages/fff/fff-network/files/usr/lib/nodewatcher.d/50-client
> +++ s.sh
> @@ -0,0 +1,25 @@
> +#!/bin/sh
> +# Netmon Nodewatcher (C) 2010-2012 Freifunk Oldenburg # License; GPL
> v3
> +
> +MESH_INTERFACE=$(uci get nodewatcher.@network[0].mesh_interface)
> +
> +debug() {
> +	(>&2 echo "$1")
> +}
> +
> +debug "$(date): Collecting information about connected clients"
> +
> +client_count=0
> +dataclient=""
> +CLIENT_INTERFACES=$(ls "/sys/class/net/$MESH_INTERFACE/brif" | grep -v
> '^bat')
> +for clientif in ${CLIENT_INTERFACES}; do
> +	local cc=$(bridge fdb show br "$MESH_INTERFACE" brport "$clientif"

"local" needs to be removed here, as this is a script, no function.
Fabian Blaese April 18, 2020, 5:22 p.m.
Hallo Adrian,

Ich hätte $(date) noch mit in die debug Funktion mit rein genommen.
Unbedingt würde ich auch den Exitstatus der Sub-Skripte prüfen und ggf. abbrechen.
Außerdem ist mit deiner Version der timeout weg gefallen, das fand ich eigentlich gar nicht schlecht..

In den Sub-Skripten werden Debugausgaben auf stderr ausgegeben, im Hauptskript in eine Datei geschreiben, deren Länge irgendwie hingepfriemelt wird.
Ich bin hier ja fast dafür, alles auf stderr auszugeben und die Datei fallen zu lassen. Man könnte aber auch stderr der Subskripte mit in die Datei stecken.

Da wir uns an diesem Patch aber noch ewig aufhalten würden, bis jeder absolut zufrieden ist, würde ich diesen Patch so akzeptieren und dann lieber hinterher noch Dinge fixen.

Reviewed-by: Fabian Bläse <fabian@blaese.de>


Bitte folgendes noch beim applien anpassen:

On 07.01.20 14:40, Adrian Schmutzler wrote:
> Note that since the nodewatcher.d scripts are evaluated by using there
"using their"?

Gruß
Fabian
Fabian Blaese April 18, 2020, 5:25 p.m.
Hallo zusammen,

On 07.01.20 15:25, Adrian Schmutzler wrote:
>> grundlegende Frage, warum /usr/lib/nodewatcher.d? Die gateway.d  haben
>> wir in /etc liegen.
> 
> die Verzeichnisse habe ich ohne viel drüber nachzudenken von Tim übernommen. Ein grundsätzlicher Unterschied zu gateway.d besteht aber darin, dass nodewatcher.d ausführbare Skripte enthält (+x), während gateway.d nur gesourced wird (denke ich). Ist mir aber prinzipiell egal, wo das am Schluss liegt. (OpenWrt hat z.B. auch ausführbare Skripte in /etc/board.d/) Wenn es jemand woanders haben will, verschiebe ich das gerne dahin.
Nach /etc gehört eigentlich kein Code, gateway.d liegt dort eigentlich falsch.
Ich hatte das dort hin gelegt, weil OpenWrt das für uci-defaults auch so macht..

Gruß
Fabian
Adrian Schmutzler April 18, 2020, 11:22 p.m.
Hallo Fabian,

> Ich hätte $(date) noch mit in die debug Funktion mit rein genommen. 

Kann man machen. Würde ich aber auch separat tun, da hier ja die alte Funktion kopiert wird.

> Unbedingt würde ich auch den Exitstatus der Sub-Skripte prüfen und ggf. abbrechen. 
> Außerdem ist mit deiner Version der timeout weg gefallen, das fand ich eigentlich gar nicht schlecht.. 

Den Timeout mochte ich nicht, da es ja effektiv kein Timeout war, sondern eine fixe Wartezeit für jedes Subskript. Ich halte nichts davon, für jedes Subskript zwei Minuten zu warten, sodass dann der ganze nodewatcher 20-30 Sekunden dauert (im Moment). Und beim Exitstatus wurde es dann noch kompliziert.
So oder so waren aber ja der Exitstatus und der "Timeout" im Prinzip Zusatzfeatures, während meine Version aus einem Skript eine Aneinanderreihung von vielen Einzelskripten macht.
Ich würde das also separat diskutieren, aber es ist in meinen Augen keine Notwendigkeit für die Aufteilung an sich.

> In den Sub-Skripten werden Debugausgaben auf stderr ausgegeben, im Hauptskript in eine Datei geschreiben, deren Länge irgendwie hingepfriemelt wird.
> Ich bin hier ja fast dafür, alles auf stderr auszugeben und die Datei fallen zu lassen. Man könnte aber auch stderr der Subskripte mit in die Datei stecken.

Das habe ich ehrlich gesagt auch gar nicht durchdacht, sondern einfach nur als gegeben betrachtet. Das sollte man in der Tat mal diskutieren, ich habe hier überhaupt keine Meinung, was sinnvoll ist.
Auf jeden Fall ist die momentane Implementierung ziemlich verwirrend.

> Da wir uns an diesem Patch aber noch ewig aufhalten würden, bis jeder absolut zufrieden ist, würde ich diesen Patch so akzeptieren und dann lieber hinterher noch Dinge fixen.

Ich kriege frühestens am Dienstag ein neues Netzteil, und dann werde ich erstmal kucken, was an meinem Server noch geht. Bis dahin werde ich nichts ändern, schicken oder applien.
Falls du ein Release machen willst, also bitte selbst einwerfen.

> > Note that since the nodewatcher.d scripts are evaluated by using there 
> "using their"? 

In der Tat. Einer meiner häufigsten Typos im Englischen (neben it's<>its).

Grüße

Adrian
Fabian Blaese April 19, 2020, 8:18 a.m.
Hey Adrian,

On 19.04.20 01:22, mail@adrianschmutzler.de wrote:
> Ich kriege frühestens am Dienstag ein neues Netzteil, und dann werde ich erstmal kucken, was an meinem Server noch geht. Bis dahin werde ich nichts ändern, schicken oder applien.
> Falls du ein Release machen willst, also bitte selbst einwerfen.
Ouh, das klingt ja fies.
Wie gesagt: An diesem Dings würde ich jetzt nichts mehr ändern, das kann keiner nachvollziehen. Zumal die meisten meiner Anmerkungen eh neue "Features" sind, und daher in einem eigenen Patch eh besser aufgehoben sind.
Ich würde diese Wünsche aber gern noch vor der Beta drin haben, daher warte ich gerne auf deinen Server (außer du möchtest ohne Server trotzdem reviewen).

>> Unbedingt würde ich auch den Exitstatus der Sub-Skripte prüfen und ggf. abbrechen. 
>> Außerdem ist mit deiner Version der timeout weg gefallen, das fand ich eigentlich gar nicht schlecht.. 
> 
> Den Timeout mochte ich nicht, da es ja effektiv kein Timeout war, sondern eine fixe Wartezeit für jedes Subskript. Ich halte nichts davon, für jedes Subskript zwei Minuten zu warten, sodass dann der ganze nodewatcher 20-30 Sekunden dauert (im Moment). Und beim Exitstatus wurde es dann noch kompliziert.
> So oder so waren aber ja der Exitstatus und der "Timeout" im Prinzip Zusatzfeatures, während meine Version aus einem Skript eine Aneinanderreihung von vielen Einzelskripten macht.
> Ich würde das also separat diskutieren, aber es ist in meinen Augen keine Notwendigkeit für die Aufteilung an sich.
Was? Ne.
Der Timeout sollte eigentlich tatsächlich als Timeout funktioniert haben, getestet hab ichs aber nie..
Es gab dazu wohl mal etwas Diskussion mit Robert, die habe ich damals mangels Zeit nicht gelesen.

Aber wie gesagt: Extra Patches.

>>> Note that since the nodewatcher.d scripts are evaluated by using there 
>> "using their"? 
> 
> In der Tat. Einer meiner häufigsten Typos im Englischen (neben it's<>its).
Fixe ich beim applien.

Gruß
Fabian
Fabian Blaese April 19, 2020, 1:46 p.m.
alle 5 patches applied.
Adrian Schmutzler April 19, 2020, 1:54 p.m.
Hallo,

> > Ich kriege frühestens am Dienstag ein neues Netzteil, und dann werde ich erstmal kucken, was an meinem Server noch geht. Bis dahin werde ich nichts ändern, schicken oder applien.
> > Falls du ein Release machen willst, also bitte selbst einwerfen. 
> Ouh, das klingt ja fies. 
> Wie gesagt: An diesem Dings würde ich jetzt nichts mehr ändern, das kann keiner nachvollziehen. Zumal die meisten meiner Anmerkungen eh neue "Features" sind, und daher in einem eigenen Patch eh besser aufgehoben sind.
> Ich würde diese Wünsche aber gern noch vor der Beta drin haben, daher warte ich gerne auf deinen Server (außer du möchtest ohne Server trotzdem reviewen).

Mein Desktop funktioniert, ich komme halt nur an mein repo nicht ohne Weiteres ran. Ich werde mir die neuen Patches gleich anschauen.

> > Den Timeout mochte ich nicht, da es ja effektiv kein Timeout war, sondern eine fixe Wartezeit für jedes Subskript. Ich halte nichts davon, für jedes Subskript zwei Minuten zu warten, sodass dann der ganze nodewatcher 20-30 Sekunden dauert (im Moment). Und beim Exitstatus wurde es dann noch kompliziert.
> > So oder so waren aber ja der Exitstatus und der "Timeout" im Prinzip Zusatzfeatures, während meine Version aus einem Skript eine Aneinanderreihung von vielen Einzelskripten macht.
> > Ich würde das also separat diskutieren, aber es ist in meinen Augen keine Notwendigkeit für die Aufteilung an sich. 
> Was? Ne. 
> Der Timeout sollte eigentlich tatsächlich als Timeout funktioniert haben, getestet hab ichs aber nie.. 

Der Timeout funktioniert deshalb nicht, weil wir hinterher die Ausgabe abfangen mit $(). Sonst würde er funktionieren.

Grüße

Adrian
Fabian Blaese April 19, 2020, 2:04 p.m.
On 19.04.20 15:54, mail@adrianschmutzler.de wrote:
>>> Den Timeout mochte ich nicht, da es ja effektiv kein Timeout war, sondern eine fixe Wartezeit für jedes Subskript. Ich halte nichts davon, für jedes Subskript zwei Minuten zu warten, sodass dann der ganze nodewatcher 20-30 Sekunden dauert (im Moment). Und beim Exitstatus wurde es dann noch kompliziert.
>>> So oder so waren aber ja der Exitstatus und der "Timeout" im Prinzip Zusatzfeatures, während meine Version aus einem Skript eine Aneinanderreihung von vielen Einzelskripten macht.
>>> Ich würde das also separat diskutieren, aber es ist in meinen Augen keine Notwendigkeit für die Aufteilung an sich. 
>> Was? Ne. 
>> Der Timeout sollte eigentlich tatsächlich als Timeout funktioniert haben, getestet hab ichs aber nie.. 
> 
> Der Timeout funktioniert deshalb nicht, weil wir hinterher die Ausgabe abfangen mit $(). Sonst würde er funktionieren.
Doch, der funktioniert.
Einen kleinen Bug hatte er damals noch: Die Ausgabe der sleep,kill-Subshell wurde nicht nach /dev/null geleitet.
Daher werden die Ausgabedeskriptoren der Elternshell vererbt, womit $() erst fertig wird, wenn alle Prozesse fertig sind (also auch sleep, kill, ..).

Aber ich hab das mal in der reparierten Form getestet: Hilft leider nichts, weil es im OpenWrt scheinbar keinen einfachen Weg gibt, Prozess und alle Kindprozesse (die Shell startet ja jede Menge davon) zu killen.
Beispielsweise kann ein langes sleep in einem Subskript daher dennoch das ganze nodewatcher Konstrukt lange blockieren, weil nur der Shellprozess gekillt wird, nicht aber das Sleep. Und damit ergibt sich wieder (ungefähr) das gleiche Problem wie oben.

Gruß
Fabian
Adrian Schmutzler April 19, 2020, 3:57 p.m.
Hallo,

> > Der Timeout funktioniert deshalb nicht, weil wir hinterher die Ausgabe abfangen mit $(). Sonst würde er funktionieren.
> Doch, der funktioniert. 
> Einen kleinen Bug hatte er damals noch: Die Ausgabe der sleep,kill-Subshell wurde nicht nach /dev/null geleitet. 
> Daher werden die Ausgabedeskriptoren der Elternshell vererbt, womit $() erst fertig wird, wenn alle Prozesse fertig sind (also auch sleep, kill, ..).
> Aber ich hab das mal in der reparierten Form getestet: Hilft leider nichts, weil es im OpenWrt scheinbar keinen einfachen Weg gibt, Prozess und alle Kindprozesse (die Shell startet ja jede Menge davon) zu killen.
> Beispielsweise kann ein langes sleep in einem Subskript daher dennoch das ganze nodewatcher Konstrukt lange blockieren, weil nur der Shellprozess gekillt wird, nicht aber das Sleep. Und damit ergibt sich wieder (ungefähr) das gleiche Problem wie oben.

So oder so ist mir das zu kompliziert, und ich sehe eigentlich keinen Benefit (zumindest, wenn man ohnehin exit 1 macht). Da wäre es in meinen Augen sinnvoller, gleich beim nodewatcher executable selbst anzugreifen, und die dann nach einer festgelegten Zeit zu killen, anstatt das für die Subskripte zu machen, was viel komplizierter ist. Bei der executable bräuchte man sich dann auch nicht um irgendwelche Ausgaben zu scheren.
Wegen mir müsste man dieses Thema aber gar nicht anfassen.

Grüße

Adrian
Fabian Blaese April 19, 2020, 4:18 p.m.
On 19.04.20 17:57, mail@adrianschmutzler.de wrote:
> Hallo,
> 
>>> Der Timeout funktioniert deshalb nicht, weil wir hinterher die Ausgabe abfangen mit $(). Sonst würde er funktionieren.
>> Doch, der funktioniert. 
>> Einen kleinen Bug hatte er damals noch: Die Ausgabe der sleep,kill-Subshell wurde nicht nach /dev/null geleitet. 
>> Daher werden die Ausgabedeskriptoren der Elternshell vererbt, womit $() erst fertig wird, wenn alle Prozesse fertig sind (also auch sleep, kill, ..).
>> Aber ich hab das mal in der reparierten Form getestet: Hilft leider nichts, weil es im OpenWrt scheinbar keinen einfachen Weg gibt, Prozess und alle Kindprozesse (die Shell startet ja jede Menge davon) zu killen.
>> Beispielsweise kann ein langes sleep in einem Subskript daher dennoch das ganze nodewatcher Konstrukt lange blockieren, weil nur der Shellprozess gekillt wird, nicht aber das Sleep. Und damit ergibt sich wieder (ungefähr) das gleiche Problem wie oben.
> 
> So oder so ist mir das zu kompliziert, und ich sehe eigentlich keinen Benefit (zumindest, wenn man ohnehin exit 1 macht). Da wäre es in meinen Augen sinnvoller, gleich beim nodewatcher executable selbst anzugreifen, und die dann nach einer festgelegten Zeit zu killen, anstatt das für die Subskripte zu machen, was viel komplizierter ist. Bei der executable bräuchte man sich dann auch nicht um irgendwelche Ausgaben zu scheren.
> Wegen mir müsste man dieses Thema aber gar nicht anfassen.
Womit man leider auf das gleiche Problem stößt. Der hängende Kindprozess (und all dessen Kinder) wird dann dennoch hängen und gammelt dann weiterhin auf dem System rum.
Hat man auch nichts gewonnen.

Gruß
Fabian