Ctrl K
ComunidadGuías…

uninstall.sh

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env sh
# marbor uninstaller
# Usage: sh uninstall.sh   (run from the directory install.sh was run in, so
#                           it can find marbor.db / the pidfile)
#
# Env vars:
#   INSTALL_DIR   binary location to remove (default /usr/local/bin, must
#                 match whatever install.sh used)
#   KEEP_DB=1     keep marbor.db without prompting
#   KEEP_DB=0     remove marbor.db without prompting
#
# When run non-interactively (e.g. piped via curl, where stdin isn't a
# terminal) marbor.db is kept by default unless the env var above says
# otherwise - an uninstall should never silently destroy data.

set -e

INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}"
BIN_NAME="marbor"
BIN_PATH="$INSTALL_DIR/$BIN_NAME"
WORKDIR="$(pwd)"
PIDFILE="$WORKDIR/marbor.pid"
UNIT_PATH="/etc/systemd/system/marbor.service"
DB_FILE="$WORKDIR/marbor.db"
LOG_FILE="$WORKDIR/marbor.log"

echo "marbor uninstaller"
echo "------------------------"

# 1. Remove the systemd service, if one was installed.
if [ -f "$UNIT_PATH" ]; then
  if command -v systemctl >/dev/null 2>&1; then
    echo "Removing systemd service ($UNIT_PATH)..."
    if [ "$(id -u)" = "0" ]; then
      systemctl stop marbor >/dev/null 2>&1 || true
      systemctl disable marbor >/dev/null 2>&1 || true
      rm -f "$UNIT_PATH"
      systemctl daemon-reload || true
    elif command -v sudo >/dev/null 2>&1; then
      sudo systemctl stop marbor >/dev/null 2>&1 || true
      sudo systemctl disable marbor >/dev/null 2>&1 || true
      sudo rm -f "$UNIT_PATH"
      sudo systemctl daemon-reload || true
    else
      echo "  [!] Removing $UNIT_PATH requires root, and sudo is not available. Remove it manually."
    fi
  else
    echo "  [!] Found $UNIT_PATH but systemctl is unavailable; remove the unit file manually."
  fi
fi

# 2. Stop a plain background (nohup) instance, if one is tracked.
if [ -f "$PIDFILE" ]; then
  PID=$(cat "$PIDFILE" 2>/dev/null || true)
  if [ -n "$PID" ] && kill -0 "$PID" 2>/dev/null; then
    # PID-reuse hazard: on a long-lived host, the PID this pidfile named can
    # have since been recycled by the OS for an unrelated process. Check
    # /proc/<pid>/cmdline (Linux only - no /proc at all on macOS, where this
    # check is skipped and the kill proceeds unconditionally, same as before
    # this fix) before signaling anything. Fail CLOSED, not open: if /proc
    # exists on this host but this PID's cmdline can't be read (e.g. a
    # hidepid=2 mount restricting /proc/<pid>/* to its own user + root - the
    # exact privilege boundary this check exists to respect), that must NOT
    # be treated the same as "no /proc at all" and default to "confirmed" -
    # it means identity genuinely can't be verified, so skip the kill.
    if [ -d /proc ]; then
      IDENTITY_OK=0
      if [ -r "/proc/$PID/cmdline" ] && tr '\0' '\n' < "/proc/$PID/cmdline" 2>/dev/null | head -1 | sed 's#.*/##' | grep -q marbor; then
        IDENTITY_OK=1
      fi
    else
      IDENTITY_OK=1
    fi
    if [ "$IDENTITY_OK" = "1" ]; then
      echo "Stopping background process (PID $PID)..."
      kill "$PID" 2>/dev/null || true
      i=0
      while [ "$i" -lt 10 ] && kill -0 "$PID" 2>/dev/null; do
        sleep 0.5
        i=$((i + 1))
      done
      if kill -0 "$PID" 2>/dev/null; then
        echo "  [!] PID $PID did not exit within 5s of SIGTERM - sending SIGKILL"
        kill -9 "$PID" 2>/dev/null || true
      fi
    else
      echo "  [!] $PIDFILE names PID $PID, but its identity could not be confirmed as marbor (stale pidfile + PID reuse?) - skipping kill to avoid killing an unrelated process."
    fi
  fi
  rm -f "$PIDFILE"
fi

# 3. Remove the binary.
if [ -f "$BIN_PATH" ]; then
  if [ -w "$INSTALL_DIR" ]; then
    rm -f "$BIN_PATH"
    echo "Removed binary: $BIN_PATH"
  elif command -v sudo >/dev/null 2>&1; then
    sudo rm -f "$BIN_PATH"
    echo "Removed binary: $BIN_PATH"
  else
    echo "  [!] Cannot remove $BIN_PATH (no write permission, no sudo). Remove it manually."
  fi
else
  echo "No binary found at $BIN_PATH (already removed, or INSTALL_DIR differs from install)."
fi

# 3b. Remove man pages installed by install.sh (docs/man/*.1, fetched from
# the release into /usr/local/share/man/man1 - see install.sh's
# install_man_pages). Same write-permission/sudo fallback as the binary
# above; a missing man dir or missing pages is not an error, just a no-op.
#
# install_man_pages drops a
# local marker file, .marbor-installed-manifest, listing exactly which
# filenames IT placed in MAN_DIR - uninstall.sh has no source tree and no
# release manifest of its own, so that marker is the only place this exact
# list is ever recorded. Prefer it when present (removes exactly what a
# Fix-4-or-later install created); the wildcard below survives only as a
# fallback for an install that predates this fix and never wrote a marker.
MAN_DIR="/usr/local/share/man/man1"
MAN_MANIFEST="$MAN_DIR/.marbor-installed-manifest"
# is_safe_manpage_name rejects anything but a plain filename (no path
# separators, no leading dash that could be misread as an rm option, only
# alnum/dot/dash/underscore) - the manifest is currently only ever written
# by install.sh's own fixed-name man-page install step, but this validates
# it as untrusted content anyway rather than assuming that always holds.
is_safe_manpage_name() {
  case "$1" in
    ""|*/*|-*) return 1 ;;
    *[!A-Za-z0-9._-]*) return 1 ;;
    *) return 0 ;;
  esac
}
if [ -f "$MAN_MANIFEST" ]; then
  MAN_PAGES_TO_REMOVE="$(cat "$MAN_MANIFEST" 2>/dev/null || true)"
  if [ -n "$MAN_PAGES_TO_REMOVE" ]; then
    if [ -w "$MAN_DIR" ]; then
      for page in $MAN_PAGES_TO_REMOVE; do
        if is_safe_manpage_name "$page"; then
          rm -f "$MAN_DIR/$page"
        else
          echo "  [!] Skipping suspicious manifest entry: $page"
        fi
      done
      rm -f "$MAN_MANIFEST"
      echo "Removed man pages listed in $MAN_MANIFEST"
    elif command -v sudo >/dev/null 2>&1; then
      for page in $MAN_PAGES_TO_REMOVE; do
        if is_safe_manpage_name "$page"; then
          sudo rm -f "$MAN_DIR/$page"
        else
          echo "  [!] Skipping suspicious manifest entry: $page"
        fi
      done
      sudo rm -f "$MAN_MANIFEST"
      echo "Removed man pages listed in $MAN_MANIFEST"
    else
      echo "  [!] Cannot remove man pages in $MAN_DIR (no write permission, no sudo). Remove them manually."
    fi
  fi
elif ls "$MAN_DIR"/marbor*.1 >/dev/null 2>&1; then
  if [ -w "$MAN_DIR" ]; then
    rm -f "$MAN_DIR"/marbor*.1
    echo "Removed man pages: $MAN_DIR/marbor*.1"
  elif command -v sudo >/dev/null 2>&1; then
    sudo rm -f "$MAN_DIR"/marbor*.1
    echo "Removed man pages: $MAN_DIR/marbor*.1"
  else
    echo "  [!] Cannot remove man pages in $MAN_DIR (no write permission, no sudo). Remove them manually."
  fi
fi

# 4. marbor.db holds real state (nodes, API keys, warm-state history) - ask
# before deleting, and default to keeping it when not on a terminal.
ask_keep() {
  # ask_keep <label> <file> <env override>  -> prints "yes" or "no"
  LABEL="$1"
  FILE="$2"
  OVERRIDE="$3"
  if [ "$OVERRIDE" = "0" ]; then
    echo "no"
    return
  fi
  if [ "$OVERRIDE" = "1" ]; then
    echo "yes"
    return
  fi
  if [ -t 0 ] && [ -f "$FILE" ]; then
    printf "Keep %s (%s)? [Y/n] " "$LABEL" "$FILE" >&2
    read -r ans || ans=""
    case "$ans" in
      [nN]*) echo "no" ;;
      *) echo "yes" ;;
    esac
    return
  fi
  echo "yes"
}

if [ -f "$DB_FILE" ]; then
  if [ "$(ask_keep "the SQLite database" "$DB_FILE" "$KEEP_DB")" = "no" ]; then
    rm -f "$DB_FILE" "$DB_FILE.key"
    echo "Removed $DB_FILE"
  else
    echo "Kept $DB_FILE"
  fi
fi

if [ -f "$LOG_FILE" ]; then
  rm -f "$LOG_FILE"
  echo "Removed $LOG_FILE"
fi

echo ""
echo "marbor has been uninstalled."