#!/bin/sh
#
# Powered by Arviol
# Ilya Vasilyev, vStack, 2026
#

set -u

MODE="${1:-check}"

TG_BIN=/usr/local/bin/telegraf
RC_SCRIPT=/usr/local/etc/rc.d/telegraf
CONF=/usr/local/etc/telegraf.conf
LIBEXEC=/usr/local/libexec/telegraf
LOG=/var/log/telegraf/telegraf.log
ROTCONF=/usr/local/etc/newsyslog.conf.d/telegraf.conf
WRAPPER=$LIBEXEC/newsyslog-restart.sh
ROTLINE="/var/log/telegraf/telegraf.log  telegraf:telegraf  640  3     10240 *     JCR   $WRAPPER"

case "$MODE" in
    check|apply) ;;
    *) echo "usage: $0 [check|apply]" >&2; exit 1 ;;
esac

[ "$(id -u)" -eq 0 ] || { echo "ERROR: must run as root" >&2; exit 1; }

echo "== telegraf-fix on $(hostname), mode: $MODE =="

if [ ! -x "$TG_BIN" ]; then
    echo "telegraf is not installed: fixes are not applicable, nothing changed"
    exit 0
fi

VERSION=$(pkg query '%v' telegraf 2>/dev/null) || VERSION=unknown
echo "telegraf package:   $VERSION"

if ! grep -q 'telegraf_user' "$RC_SCRIPT" 2>/dev/null; then
    echo "rc script runs telegraf as root (old package, not upgraded on 2.2 -> 3.0):"
    echo "fixes are not applicable, nothing changed"
    exit 0
fi
echo "service user:       telegraf"

if [ ! -f "$CONF" ]; then
    echo "ERROR: $CONF not found, broken installation" >&2
    exit 1
fi

ENABLED=$(sysrc -n telegraf_enable 2>/dev/null || echo NO)
SUP=$(pgrep -f 'daemon: /usr/local/bin/telegraf' | head -1)
CHILD=$(pgrep -x telegraf | head -1)
NEED_SVC=no
if [ -n "$SUP" ] && [ -n "$CHILD" ]; then
    echo "service state:      running (supervisor $SUP, telegraf $CHILD)"
elif [ -n "$CHILD" ]; then
    NEED_SVC=yes
    echo "service state:      DEGRADED, telegraf $CHILD lost its daemon(8) supervisor"
else
    case "$ENABLED" in
        [Yy][Ee][Ss])
            NEED_SVC=yes
            echo "service state:      NOT RUNNING while telegraf_enable=$ENABLED"
            ;;
        *)
            echo "service state:      not running, telegraf_enable=$ENABLED, left as is"
            ;;
    esac
fi

NEED_MOVE=no
MISSING=""
REFS=$(grep -o '"/root/bin/[^"]*"' "$CONF" | tr -d '"' | sort -u)
if [ -n "$REFS" ]; then
    NEED_MOVE=yes
    echo "conf references to /root/bin:"
    for src in $REFS; do
        name=${src##*/}
        if [ -f "$src" ]; then
            state=present
        elif [ -f "$LIBEXEC/$name" ]; then
            state="already in $LIBEXEC"
        else
            state=MISSING
            MISSING="$MISSING $src"
        fi
        printf '  %-45s %s\n' "$src" "$state"
    done
else
    echo "conf references to /root/bin: none"
fi

NEED_CHOWN=no
if [ -f "$LOG" ]; then
    OWNER=$(stat -f '%Su:%Sg' "$LOG")
    [ "$OWNER" = "telegraf:telegraf" ] || NEED_CHOWN=yes
    echo "log owner:          $OWNER"
else
    echo "log owner:          no log file yet"
fi

NEED_ROTATE=no
ROT_FOREIGN=""
ROTCUR=$(grep -hs '^/var/log/telegraf/telegraf\.log' \
    /etc/newsyslog.conf /etc/newsyslog.conf.d/*.conf \
    /usr/local/etc/newsyslog.conf.d/*.conf 2>/dev/null | head -1)
if [ -z "$ROTCUR" ]; then
    NEED_ROTATE=yes
    echo "log rotation:       missing"
elif printf '%s' "$ROTCUR" | grep -q "$WRAPPER"; then
    echo "log rotation:       ok, restart wrapper"
else
    NEED_ROTATE=yes
    echo "log rotation:       UNSAFE signal-based entry, kills telegraf at rotation:"
    echo "  $ROTCUR"
    ROT_FOREIGN=$(grep -ls '^/var/log/telegraf/telegraf\.log' \
        /etc/newsyslog.conf /etc/newsyslog.conf.d/*.conf \
        /usr/local/etc/newsyslog.conf.d/*.conf 2>/dev/null | grep -v "^$ROTCONF\$" || true)
fi

TODO=""
[ "$NEED_MOVE" = yes ] && TODO="$TODO move-scripts"
[ "$NEED_CHOWN" = yes ] && TODO="$TODO chown-log"
[ "$NEED_ROTATE" = yes ] && TODO="$TODO fix-rotation"
[ "$NEED_SVC" = yes ] && TODO="$TODO restart-service"

if [ -z "$TODO" ]; then
    echo "verdict: everything is in order, nothing to do"
    exit 0
fi
echo "verdict: fixes needed:$TODO"

if [ -n "$MISSING" ]; then
    echo "ERROR: scripts referenced by config do not exist:$MISSING" >&2
    echo "restore them by hand, then re-run" >&2
    exit 1
fi

if [ -n "$ROT_FOREIGN" ]; then
    echo "ERROR: unsafe rotation entry lives outside $ROTCONF:" >&2
    echo "  $ROT_FOREIGN" >&2
    echo "remove it by hand, then re-run" >&2
    exit 1
fi

if [ "$MODE" = check ]; then
    echo "run '$0 apply' to apply the fixes above"
    exit 3
fi

BACKUP="${CONF}.bak-$(date +%Y%m%d-%H%M%S)"
MOVED=""
RESTART=$NEED_SVC

if [ "$NEED_MOVE" = yes ]; then
    mkdir -p "$LIBEXEC"
    for src in $REFS; do
        name=${src##*/}
        dst="$LIBEXEC/$name"
        if [ -f "$src" ]; then
            mv "$src" "$dst"
            MOVED="$MOVED $name"
        fi
        chown root:wheel "$dst"
        chmod 755 "$dst"
    done
    cp -p "$CONF" "$BACKUP"
    sed -i '' 's|/root/bin/|/usr/local/libexec/telegraf/|g' "$CONF"
    echo "applied: move-scripts, config backup: $BACKUP"
    RESTART=yes
fi

if [ "$NEED_CHOWN" = yes ]; then
    chown telegraf:telegraf "$LOG"
    chmod 640 "$LOG"
    echo "applied: chown-log"
    RESTART=yes
fi

if [ "$NEED_ROTATE" = yes ]; then
    mkdir -p "$LIBEXEC" "${ROTCONF%/*}"
    printf '#!/bin/sh\nservice telegraf restart\n' > "$WRAPPER"
    chmod 755 "$WRAPPER"
    echo "$ROTLINE" > "$ROTCONF"
    echo "applied: fix-rotation, $ROTCONF"
fi

if [ "$RESTART" = no ]; then
    echo "result: OK, applied without touching the running service"
    exit 0
fi

OFFSET=0
[ -f "$LOG" ] && OFFSET=$(wc -c < "$LOG")
if pgrep -x telegraf >/dev/null; then
    pkill -x telegraf
    n=0
    while pgrep -x telegraf >/dev/null && [ "$n" -lt 10 ]; do sleep 1; n=$((n + 1)); done
fi
pkill -f 'daemon: /usr/local/bin/telegraf' 2>/dev/null || true
service telegraf start >/dev/null 2>&1
sleep 20

FRESH=$(tail -c "+$((OFFSET + 1))" "$LOG" 2>/dev/null || true)
if pgrep -x telegraf >/dev/null && pgrep -qf 'daemon: /usr/local/bin/telegraf' \
    && ! printf '%s' "$FRESH" | grep -q 'loading config file .* failed\|Error running agent'; then
    ERR=$(printf '%s' "$FRESH" | grep -c 'E!')
    echo "result: OK, telegraf is running, error lines in fresh log: $ERR"
    [ "$ERR" -gt 0 ] && printf '%s\n' "$FRESH" | grep 'E!' | head -3
    exit 0
fi

echo "result: telegraf failed to start, rolling back" >&2
[ -f "$BACKUP" ] && cp -p "$BACKUP" "$CONF"
for name in $MOVED; do
    mv "$LIBEXEC/$name" "/root/bin/$name"
done
pkill -x telegraf 2>/dev/null || true
service telegraf start >/dev/null 2>&1
sleep 5
if pgrep -x telegraf >/dev/null; then
    echo "rollback done, telegraf is running with the original config" >&2
else
    echo "rollback done, telegraf is still not running: manual intervention required" >&2
fi
exit 1
