#!/bin/sh
### BEGIN INIT INFO
# Provides:          netrestarter
# Required-Start:
# Required-Stop:
# Default-Start:
# Default-Stop:
# Short-Description: Restart networking for active ethX/wlanX interfaces
### END INIT INFO

set -eu

PATH="/sbin:/bin:/usr/sbin:/usr/bin"
LOGFILE="/tmp/restart.log"

log() {
  echo "[net-restart] $*" >> "$LOGFILE"
}

on_remote_rootfs() {
  if [ -r /proc/cmdline ]; then
    if grep -q 'root=/dev/nfs' /proc/cmdline 2>/dev/null; then
      return 0
    fi
    if grep -q 'nfsroot=' /proc/cmdline 2>/dev/null; then
      return 0
    fi
  fi

  if [ -r /proc/mounts ]; then
    fstype="$(awk '$2=="/" {print $3; exit}' /proc/mounts 2>/dev/null || true)"
    case "$fstype" in
      nfs|nfs4|cifs|smbfs|sshfs|9p|fuse.sshfs)
        return 0
        ;;
    esac
  fi

  return 1
}

list_target_ifaces() {
  if command -v ip >/dev/null 2>&1; then
    ip -o link show 2>/dev/null \
      | awk -F': ' '{print $2}' \
      | cut -d'@' -f1 \
      | grep -E '^(eth[0-9]+|wlan[0-9]+)$' \
      || true
  else
    if [ -d /sys/class/net ]; then
      ls -1 /sys/class/net 2>/dev/null \
        | grep -E '^(eth[0-9]+|wlan[0-9]+)$' \
        || true
    fi
  fi
}

iface_exists() {
  iface="$1"
  if command -v ip >/dev/null 2>&1; then
    ip link show dev "$iface" >/dev/null 2>&1
  else
    [ -d "/sys/class/net/$iface" ]
  fi
}

is_iface_up() {
  iface="$1"
  if command -v ip >/dev/null 2>&1; then
    ip link show dev "$iface" 2>/dev/null | grep -q 'state UP'
  else
    if [ -r "/sys/class/net/$iface/operstate" ]; then
      st="$(cat "/sys/class/net/$iface/operstate" 2>/dev/null || true)"
      [ "$st" = "up" ]
    else
      return 1
    fi
  fi
}

do_ifdown() {
  iface="$1"
  if [ -x /sbin/ifdown ]; then
    /sbin/ifdown "$iface" 2>/dev/null || true
  elif command -v ifdown >/dev/null 2>&1; then
    ifdown "$iface" 2>/dev/null || true
  elif command -v ip >/dev/null 2>&1; then
    ip link set dev "$iface" down 2>/dev/null || true
  fi
}

do_ifup() {
  iface="$1"
  if [ -x /sbin/ifup ]; then
    /sbin/ifup "$iface" 2>/dev/null || true
  elif command -v ifup >/dev/null 2>&1; then
    ifup "$iface" 2>/dev/null || true
  elif command -v ip >/dev/null 2>&1; then
    ip link set dev "$iface" up 2>/dev/null || true
  fi
}

flush_global_addrs() {
  iface="$1"
  if command -v ip >/dev/null 2>&1; then
    ip addr flush dev "$iface" scope global 2>/dev/null || true
  fi
}

stop_service() {
  svc="$1"
  if [ -x "$svc" ]; then
    "$svc" stop 2>/dev/null || true
  fi
}

start_service() {
  svc="$1"
  if [ -x "$svc" ]; then
    "$svc" start 2>/dev/null || true
  fi
}

kill_udhcpc() {
  if command -v killall >/dev/null 2>&1; then
    killall -9 udhcpc 2>/dev/null || true
  elif command -v pkill >/dev/null 2>&1; then
    pkill -9 udhcpc 2>/dev/null || true
  else
    for f in /var/run/udhcpc*.pid /var/run/udhcpc*.pidfile; do
      [ -r "$f" ] || continue
      pid="$(cat "$f" 2>/dev/null || true)"
      case "$pid" in
        ''|*[!0-9]*)
          ;;
        *)
          kill -9 "$pid" 2>/dev/null || true
          ;;
      esac
    done
  fi
}

restart_dnscrypt_if_present() {
  if [ -x /usr/bin/dnscrypt-proxy ] && [ -x /etc/init.d/dnscrypt-proxy ]; then
    log "Restarting dnscrypt-proxy"
    /etc/init.d/dnscrypt-proxy restart 2>/dev/null || true
  fi
}

# Determine which interfaces to act on:
# - no arg: all active ethX/wlanX
# - "all": all active ethX/wlanX
# - "eth1"/"wlan0": that interface only (must match pattern)
select_ifaces() {
  want="${1:-}"

  if [ -z "$want" ] || [ "$want" = "all" ]; then
    ACTIVE_IFACES=""
    for iface in $(list_target_ifaces); do
      if is_iface_up "$iface"; then
        ACTIVE_IFACES="$ACTIVE_IFACES $iface"
      fi
    done
    echo "$ACTIVE_IFACES"
    return 0
  fi

  # Only allow ethX/wlanX by design
  case "$want" in
    eth[0-9]*|wlan[0-9]*)
      ;;
    *)
      echo "Invalid interface '$want' (allowed: ethX or wlanX) or use 'all'." >&2
      exit 2
      ;;
  esac

  if ! iface_exists "$want"; then
    echo "Interface '$want' does not exist." >&2
    exit 1
  fi

  if is_iface_up "$want"; then
    echo " $want"
  else
    log "Requested interface '$want' is not UP; proceeding with service restart only."
    echo ""
  fi
}

do_restart() {
  TARGET_IFACE="${1:-}"

  REMOTE_ROOT=0
  if on_remote_rootfs; then
    REMOTE_ROOT=1
    log "Remote rootfs detected. eth0 will not be brought down."
  fi

  ACTIVE_IFACES="$(select_ifaces "$TARGET_IFACE")"

  if [ -z "$ACTIVE_IFACES" ]; then
    log "No active target interfaces selected. Proceeding with service restart only."
  else
    log "Selected active interfaces:$ACTIVE_IFACES"
  fi

  stop_service /etc/init.d/avahi-daemon

  for iface in $ACTIVE_IFACES; do
    if [ "$iface" = "eth0" ] && [ "$REMOTE_ROOT" -eq 1 ]; then
      log "Skipping ifdown/flush for eth0 (remote rootfs)."
      continue
    fi

    log "ifdown $iface"
    do_ifdown "$iface"

    log "ip addr flush (scope global) on $iface"
    flush_global_addrs "$iface"
  done

  stop_service /etc/init.d/networking

  log "Killing udhcpc and removing pidfiles"
  kill_udhcpc
  rm -f /var/run/udhcpc* 2>/dev/null || true

  start_service /etc/init.d/networking

  for iface in $ACTIVE_IFACES; do
    if [ "$iface" = "eth0" ] && [ "$REMOTE_ROOT" -eq 1 ]; then
      continue
    fi
    do_ifup "$iface"
  done

  start_service /etc/init.d/avahi-daemon
  restart_dnscrypt_if_present
  log "Done."
}

case "${1:-}" in
  restart)
    do_restart "${2:-}"
    ;;
  *)
    echo "Usage: $0 restart [all|ethX|wlanX]" >&2
    exit 2
    ;;
esac

exit 0
