watchcat: resolve interface resolution race

- Add interface trigger handling in watchcat.init
- Log when raw interface trigger is activated by any interface coming up
- Move helper functions to separate file
- Update Makefile to install new functions file

Closes: #30463

Signed-off-by: Daniel F. Dickinson <dfdpublic@wildtechgarden.ca>
This commit is contained in:
Daniel F. Dickinson authored and Hannu Nyman committed 2026-10-02 07:56:11 +03:00
1 parent e8f3c850a6
commit 88019052fa
4 files changed
+136 -75

No files matched your search

+3 -1
View File
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=watchcat
PKG_VERSION:=1
PKG_RELEASE:=25
PKG_RELEASE:=26
PKG_MAINTAINER:=Daniel F. Dickinson <dfdpublic@wildtechgarden.ca>, Dharmik Parmar <dharmikparmar2004@yahoo.com>
PKG_LICENSE:=GPL-2.0
@@ -43,6 +43,8 @@ define Package/watchcat/install
$(INSTALL_DATA) ./files/watchcat.config $(1)/etc/config/watchcat
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(INSTALL_BIN) ./files/migrate-watchcat $(1)/etc/uci-defaults/migrate-watchcat
$(INSTALL_DIR) $(1)/lib/functions
$(INSTALL_DATA) ./files/watchcat.sh.functions $(1)/lib/functions/watchcat.sh
endef
$(eval $(call BuildPackage,watchcat))
+50 -2
View File
@@ -9,6 +9,9 @@ USE_PROCD=1
START=97
STOP=01
# shellcheck source=/dev/null
. /lib/functions/watchcat.sh
append_string() {
varname="$1"
add="$2"
@@ -142,10 +145,55 @@ config_watchcat() {
}
start_service() {
# procd expects $1 to be a specific instance
if [ "$2" = "ifup-any" ]; then
logger -p daemon.notice -t "watchcat[$$]" "Restarting due to an interface up with any unresolved interface."
fi
config_load watchcat
config_foreach config_watchcat watchcat
}
service_triggers() {
procd_add_reload_trigger "watchcat"
# Setup trigger in procd for changes to specified network interface
add_interface_trigger() {
local section="$1"
local ret=1
local interface mode logical
config_get mode "$section" mode "ping_reboot"
config_get interface "$section" interface
# Fix potential typo in mode and provide backward compatibility.
[ "$mode" = "allways" ] && mode="periodic_reboot"
[ "$mode" = "always" ] && mode="periodic_reboot"
[ "$mode" = "ping" ] && mode="ping_reboot"
# ping_reboot mode and restart_iface mode specific checks
if [ "$mode" = "ping_reboot" ] || [ "$mode" = "restart_iface" ] || [ "$mode" = "run_script" ]; then
[ -n "$interface" ] || return
logical="$(watchcat_resolve_restart_iface "$interface")"
ret=$?
if [ -n "$logical" ] && [ "$ret" -eq 0 ]; then
procd_add_interface_trigger "interface.*.up" "$logical" "/etc/init.d/watchcat" "restart"
else
has_failed_interface_resolve="true"
fi
fi
}
service_triggers() {
local has_failed_interface_resolve="false"
procd_add_reload_trigger "watchcat"
config_load watchcat
config_foreach add_interface_trigger watchcat
if [ "$has_failed_interface_resolve" = "true" ]; then
# PROCD_RELOAD_DELAY is defined in /lib/functions/procd.sh, sourced by /etc/rc.common on the live device
# procd expects parameter after script action (here, restart) to be a specific instance
procd_add_raw_trigger "interface.*.up" "$PROCD_RELOAD_DELAY" "/etc/init.d/watchcat" "restart" "" "ifup-any"
fi
}
+1 -72
View File
@@ -10,78 +10,7 @@
# shellcheck shell=busybox
# shellcheck source=/dev/null
. /lib/network/config.sh
. /lib/functions/network.sh
# Accept the historical real-device input while also handling @logical
# interface references used by other OpenWrt configs.
watchcat_resolve_ping_iface() {
local iface="$1"
local logical device network
[ -n "$iface" ] || return 1
case "$iface" in
@*)
logical="${iface#@}"
[ -n "$logical" ] || return 1
if network_get_device device "$logical"; then
printf '%s\n' "$device"
return 0
fi
printf '%s\n' "$iface"
return 1
;;
esac
network="$(find_config "$iface")"
if [ -n "$network" ]; then
printf '%s\n' "$iface"
return 0
fi
if network_get_device device "$iface"; then
printf '%s\n' "$device"
return 0
fi
printf '%s\n' "$iface"
return 1
}
watchcat_resolve_restart_iface() {
local iface="$1"
local network device
[ -n "$iface" ] || return 1
case "$iface" in
@*)
network="${iface#@}"
[ -n "$network" ] || return 1
if ! network_get_device device "$network"; then
printf '%s\n' "$network"
return 1
fi
printf '%s\n' "$network"
return 0
;;
esac
network="$(find_config "$iface")"
if [ -n "$network" ]; then
printf '%s\n' "$network"
return 0
fi
if network_get_device device "$iface"; then
printf '%s\n' "$iface"
return 0
fi
printf '%s\n' "$iface"
return 1
}
. /lib/functions/watchcat.sh
get_ping_size() {
ps=$1
@@ -0,0 +1,82 @@
#!/bin/sh
# Shebang line included so editors and shellcheck/shfmt know this contains
# shell code
# In recent (relevant) versions of shellcheck busybox is a valid shell type
# shellcheck shell=busybox
# Helper functions for watchcat
# shellcheck source=/dev/null
. /lib/network/config.sh
. /lib/functions/network.sh
# Accept the historical real-device input while also handling @logical
# interface references used by other OpenWrt configs.
watchcat_resolve_ping_iface() {
local iface="$1"
local logical device network
[ -n "$iface" ] || return 1
case "$iface" in
@*)
logical="${iface#@}"
[ -n "$logical" ] || return 1
if network_get_device device "$logical"; then
printf '%s\n' "$device"
return 0
fi
printf '%s\n' "$iface"
return 1
;;
esac
network="$(find_config "$iface")"
if [ -n "$network" ]; then
printf '%s\n' "$iface"
return 0
fi
if network_get_device device "$iface"; then
printf '%s\n' "$device"
return 0
fi
printf '%s\n' "$iface"
return 1
}
watchcat_resolve_restart_iface() {
local iface="$1"
local network device
[ -n "$iface" ] || return 1
case "$iface" in
@*)
network="${iface#@}"
[ -n "$network" ] || return 1
if ! network_get_device device "$network"; then
printf '%s\n' "$network"
return 1
fi
printf '%s\n' "$network"
return 0
;;
esac
network="$(find_config "$iface")"
if [ -n "$network" ]; then
printf '%s\n' "$network"
return 0
fi
if network_get_device device "$iface"; then
printf '%s\n' "$iface"
return 0
fi
printf '%s\n' "$iface"
return 1
}