etherwake: wait for the interface to come up before transmitting etherwake-wait-for-iface
authorGeorgios Kontaxis <redacted>
Mon, 22 Jun 2026 15:43:09 +0000 (15:43 +0000)
committerGeorgios Kontaxis <redacted>
Tue, 23 Jun 2026 18:05:26 +0000 (18:05 +0000)
Signed-off-by: Georgios Kontaxis <redacted>
net/etherwake/files/etherwake.config
net/etherwake/files/etherwake.init

index cf025dcad91374a649f2fd52bab1775e923b67c0..4847aa1d139e86b68a49e531389aa2d2ea26d78f 100644 (file)
@@ -1,17 +1,27 @@
 config 'etherwake' 'setup'
        # interface to use, defaults to 'eth0'
        #option 'interface' 'eth0'
+
+       # maximum wait during system boot for the interface to be up
+       # - defaults to 10 seconds
+       # - 0 seconds means no wait or check that the interface is up
+       #option 'interface_timeout' '10'
+
        # send wake-up packet to the broadcast address, defaults to off
        #option 'broadcast' 'off'
 
 config 'target'
        # name for the target
        #option 'name' 'example'
+
        # mac address of the machine to wake up
        #option 'mac' '00:11:22:33:44:55'
+
        # (optional) 6-byte secureOn password in ethernet hex format
        #option 'secureon' 'aa:bb:cc:dd:ee:ff'
+
        # (optional) 4-byte secureOn password in dotted decimal format
        #option 'secureon' '170.187.204.221'
+
        # wake up on system start, defaults to off
        #option 'wakeonboot' 'off'
index 43396e5ebd660e588cb2319ae1d95c8781243c3e..b3b091f1b81da7ee1968c0033223486ad5072a8b 100644 (file)
 # Copyright (C) 2009 OpenWrt.org
 
 NAME='etherwake'
-START=60
+START=99
 PROGRAM='/usr/bin/etherwake'
 
-start()
-{
-       local value=''
+boot() {
+       etherwake_boot &
+}
+
+etherwake_boot() {
+       etherwake_load_config_setup
+
+       local iface="${ETHERWAKE_CONFIG_SETUP_IFACE}"
+       local timeout="${ETHERWAKE_CONFIG_SETUP_TIMEOUT}"
+
+       if [ "${timeout}" != "0" ] &&
+               ! etherwake_wait_for_iface "${iface}" "${timeout}"; then
+               logger -t "${NAME}" \
+                       "Interface '${iface}' did not come up within ${timeout} seconds"
+               return 1
+       fi
+
+       start
+}
+
+ETHERWAKE_CONFIG_LOADED='0'
+ETHERWAKE_CONFIG_SETUP_IFACE=''
+ETHERWAKE_CONFIG_SETUP_TIMEOUT=1
+ETHERWAKE_CONFIG_SETUP_BROADCAST='0'
+
+etherwake_load_config_setup() {
+       [ "${ETHERWAKE_CONFIG_LOADED}" != "0" ] && return
 
        config_load "${NAME}"
 
-       # interface
-       config_get value 'setup' 'interface' 'eth0'
-       append PROGRAM "-i ${value}"
+       config_get ETHERWAKE_CONFIG_SETUP_IFACE 'setup' 'interface' 'eth0'
 
-       # broadcast
-       config_get_bool value 'setup' 'broadcast' '0'
-       [ "${value}" -ne 0 ] && append PROGRAM '-b'
+       config_get ETHERWAKE_CONFIG_SETUP_TIMEOUT 'setup' 'interface_timeout'
+       case "${ETHERWAKE_CONFIG_SETUP_TIMEOUT}" in
+               ''|*[!0-9]*)
+                       ETHERWAKE_CONFIG_SETUP_TIMEOUT=10
+                       ;;
+       esac
 
-       # wake up targets
-       config_foreach etherwake_start target $*
+       config_get_bool ETHERWAKE_CONFIG_SETUP_BROADCAST 'setup' 'broadcast' '0'
+
+       ETHERWAKE_CONFIG_LOADED=1
 }
 
-etherwake_start()
-{
-       local section="$1"
-       shift
+# etherwake_wait_for_iface <interface> [<timeout>]
+#
+# wait up to 'timeout' seconds for interface 'iface' to come up.
+# - when 'timeout' is set to 0 the function returns immediately
+#   without checking the status of the interface
+# - default 'timeout' is 1
+etherwake_wait_for_iface() {
+       local iface="$1"
+       local timeout="${2:-1}"
+
+       [ -n "${iface}" ] || return 1
+
+       local interval=1
+       local elapsed=0
+
+       while [ "${elapsed}" -lt "${timeout}" ]; do
+               if [ "$(ubus call network.interface."${iface}" status 2> /dev/null |
+                       jsonfilter -e '@.up' 2> /dev/null)" = "true" ]; then
+                       logger -t "${NAME}" \
+                               "Interface '${iface}' is up after ${elapsed} seconds"
+                       return 0
+               fi
+
+               sleep "${interval}"
+               elapsed=$((elapsed + interval))
+       done
+
+       return 1
+}
+
+ETHERWAKE_LAST_ERROR=0
+
+start() {
+       etherwake_load_config_setup
+
+       ETHERWAKE_LAST_ERROR=0
 
-       local names="$*"
+       config_foreach etherwake_start target \
+               "${ETHERWAKE_CONFIG_SETUP_IFACE}" \
+               "${ETHERWAKE_CONFIG_SETUP_BROADCAST}" "$@"
+
+       return ${ETHERWAKE_LAST_ERROR}
+}
+
+# etherwake_start <section> <interface> <broadcast> [<names...>]
+etherwake_start() {
+       local section="$1"; shift
+       local iface="$1"; shift
+       local broadcast="$1"; shift
+       local names="$@"
 
        local value=''
-       local target=''
+       local filter=''
 
-       if [ -z "${names}" ]
-        then
-               # check if boot target
+       # are we focusing on all targets that should wake up when this script runs
+       # or specific names?
+       if [ -z "${names}" ]; then
                config_get_bool value "${section}" 'wakeonboot' '0'
                [ "${value}" -eq 0 ] && return 0
 
-               # wake up target
-               do_etherwake "${section}"
-               return $?
-       else
-               # name
-               config_get value "${section}" 'name'
-               [ -z "${value}" ] && return 0
-
-               for target in ${names}
-                do
-                       [ "${value}" != "${target}" ] && continue
-
-                       # wake up target
-                       do_etherwake "${section}"
-                       return $?
-               done
+               do_etherwake "${section}" "${iface}" "${broadcast}" || ETHERWAKE_LAST_ERROR=$?
+               return 0
        fi
+
+       config_get value "${section}" 'name'
+       [ -z "${value}" ] && return 0
+
+       for filter in ${names}; do
+               [ "${value}" != "${filter}" ] && continue
+
+               do_etherwake "${section}" "${iface}" "${broadcast}" || ETHERWAKE_LAST_ERROR=$?
+               break
+       done
+
+       return 0
 }
 
 # execute etherwake command for target
-do_etherwake()
-{
+do_etherwake() {
        local section="$1"
-       local value=''
-       local password=''
-       local args=''
+       local iface="$2"
+       local broadcast="$3"
+
        local section_name=''
+       local mac=''
+       local password=''
+       local secureon=''
+
+       config_get section_name "${section}" 'name' "${section}"
+
+       config_get mac "${section}" 'mac'
+       [ -z "${mac}" ] && {
+               logger -t "${NAME}" "Target '${section_name}' has no 'mac' address"
+               return 1
+       }
 
        # password (legacy option)
-       config_get value "${section}" 'password'
-       [ -n "${value}" ] && {
-               password=$(etherwake_password "${value}")
-               append args "-p ${password}"
+       config_get password "${section}" 'password'
+       [ -n "${password}" ] && {
+               password=$(etherwake_password "${password}")
        }
 
-       # secureOn password
-       config_get value "${section}" 'secureon'
-       [ -n "${value}" ] && append args "-p ${value}"
+       config_get secureon "${section}" 'secureon'
 
-       # name
-       config_get section_name "${section}" 'name'
-       [ -z "${section_name}" ] && section_name="${section}"
+       set --
+       [ -n "${iface}" ] && set -- "$@" -i "${iface}"
+       [ "${broadcast}" = "1" ] && set -- "$@" -b
+       [ -n "${password}" ] && set -- "$@" -p "${password}"
+       [ -n "${secureon}" ] && set -- "$@" -p "${secureon}"
+       set -- "$@" "${mac}"
 
-       # mac address
-       config_get value "${section}" 'mac'
-       [ -z "${value}" ] && {
-               echo "Target '${section_name}' has no 'mac' address"; return 1; }
-       append args "${value}"
+       logger -t "${NAME}" "Waking up '${section_name}' via ${PROGRAM} $*"
+
+       "${PROGRAM}" "$@"
 
-       # execute command
-       echo "Waking up '${section_name}' via ${PROGRAM}${args:+ ${args}}"
-       ${PROGRAM} ${args}
        return $?
 }
 
-
-# prepare hex password (support legacy option)
-etherwake_password()
-{
+# make string look like ethernet hex format (support legacy password option)
+etherwake_password() {
        local delimiter=':'
-       local password=`echo "$1" | sed "s/../&${delimiter}/g"`
+       local password=$(echo "$1" | sed "s/../&${delimiter}/g")
        echo "${password%${delimiter}}"
-       return
 }
git clone https://git.99rst.org/PROJECT