#!/bin/sh
# Take over a hand-built tailscale installation (spec sec. 7, owner
# requirement 2026-09-06): stop it, rename its binaries on PATH to
# <file>.disabled, retire its init script, keep /var/lib/tailscale.
# Idempotent; silent when there is nothing to do (the normal case).
# The path prefix is DPKG_ROOT when dpkg sets one (a --root install), else
# TS_PREINST_ROOT (tests only); a real install on the running system has both
# empty. Ownership is decided with dpkg-query -S: a file dpkg owns is ours
# (or another package's) and is never touched.
set -e
case "$1" in install|upgrade) ;; *) exit 0 ;; esac
R=${DPKG_ROOT:-${TS_PREINST_ROOT:-}}
say() { echo "tailscale preinst: $*"; }
owned() { dpkg-query -S "$1" >/dev/null 2>&1; }
hand() { [ -e "$R$1" ] && ! owned "$1"; }

DIRS="/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin"
FOUND=""
for d in $DIRS; do for n in tailscale tailscaled; do
  hand "$d/$n" && FOUND="$FOUND $d/$n"
done; done
INIT=/etc/init.d/tailscaled
hand "$INIT" && FOUND="$FOUND $INIT"
[ -n "$FOUND" ] || exit 0

say "hand-installed tailscale found:$FOUND -- taking over"
OLDD=""
for d in $DIRS; do hand "$d/tailscaled" && { OLDD="$R$d/tailscaled"; break; }; done

# 1. stop the old daemon: its init script first, then whatever pidfile is left
if hand "$INIT"; then say "stopping via $INIT"; "$R$INIT" stop || true; fi
# /var/run/tailscale.pid and /run/tailscaled.pid are the two the spec names
# (sec. 7 point 2); /run/tailscale.pid is a defensive extra beyond those two.
for pf in /var/run/tailscale.pid /run/tailscaled.pid /run/tailscale.pid; do
  [ -s "$R$pf" ] || continue
  pid=$(cat "$R$pf")
  if kill -0 "$pid" 2>/dev/null; then
    # only act on this pid if it is actually running one of the UNOWNED
    # candidate binaries we are here to take over ($FOUND). A pidfile can
    # outlive the daemon and be reused by an unrelated process, and we must
    # never kill or claim to own that. Matching against $DIRS instead would
    # include /usr/sbin/tailscaled -- OUR OWN packaged daemon -- so a reinstall
    # or a re-run while the packaged daemon is running would kill it.
    exe=$(readlink "/proc/$pid/exe" 2>/dev/null)
    exe=${exe% (deleted)}
    match=""
    for f in $FOUND; do
      [ "$f" = "$INIT" ] && continue
      [ "$exe" = "$R$f" ] && match=1
    done
    if [ -n "$match" ]; then
      say "stopping pid $pid from $pf"
      kill "$pid" 2>/dev/null || true
      i=0; while kill -0 "$pid" 2>/dev/null && [ $i -lt 15 ]; do sleep 1; i=$((i+1)); done
      kill -0 "$pid" 2>/dev/null && { say "pid $pid still alive, KILL"; kill -9 "$pid" 2>/dev/null || true; }
    else
      say "$pf names pid $pid ($exe), not one of the hand-installed binaries being taken over -- leaving it alone"
    fi
  fi
  rm -f "$R$pf"
done
if [ -n "$OLDD" ] && [ -x "$OLDD" ]; then say "running $OLDD --cleanup"; "$OLDD" --cleanup || true; fi

# 2. rename the binaries (PATH order puts /usr/local first: a leftover client
#    would talk to the new daemon with a mismatched version)
for f in $FOUND; do
  [ "$f" = "$INIT" ] && continue
  say "renaming $f -> $f.disabled"; mv "$R$f" "$R$f.disabled"
done

# 3. retire the init script: drop its rc links, move it OUT of /etc/init.d
#    (insserv parses every file there; a .disabled copy with its own
#    Provides: would collide with ours), so dpkg installs our conffile fresh
if hand "$INIT"; then
  update-rc.d -f tailscaled remove >/dev/null 2>&1 || true
  B="$R/var/backups/tailscale-hand-install"; mkdir -p "$B"
  T="$B/init.d-tailscaled.$(date +%Y%m%dT%H%M%S)"
  say "moving $INIT -> ${T#$R}"; mv "$R$INIT" "$T"
fi
say "state in /var/lib/tailscale is kept; the packaged daemon starts after unpack"

#DEBHELPER#
exit 0
