testsAndMisc/linux_configuration/scripts/system-maintenance/bin/shutdown-timer-monitor.sh

145 lines
4.0 KiB
Bash
Executable File

#!/bin/bash
# Shutdown timer monitor script
# Watches the day-specific-shutdown timer and re-enables it if disabled
# This file is installed by setup_midnight_shutdown.sh
set -euo pipefail
LOG_FILE="/var/log/shutdown-timer-monitor.log"
TIMER_NAME="day-specific-shutdown.timer"
SERVICE_NAME="day-specific-shutdown.service"
CHECK_INTERVAL=30
# Log with timestamp (shutdown-timer-monitor specific)
log_message() {
local _ts
printf -v _ts '%(%Y-%m-%d %H:%M:%S)T' -1
printf '%s [shutdown-monitor] %s\n' "$_ts" "$1" | tee -a "$LOG_FILE" >&2
}
# Function to check if timer needs to be re-enabled
timer_needs_restoration() {
# Check if timer is enabled
if ! systemctl is-enabled "$TIMER_NAME" &>/dev/null; then
log_message "Timer $TIMER_NAME is not enabled"
return 0
fi
# Check if timer is active
if ! systemctl is-active "$TIMER_NAME" &>/dev/null; then
log_message "Timer $TIMER_NAME is not active"
return 0
fi
# Check if timer unit file exists
if [[ ! -f "/etc/systemd/system/$TIMER_NAME" ]]; then
log_message "Timer unit file missing: /etc/systemd/system/$TIMER_NAME"
return 0
fi
# Check if service unit file exists
if [[ ! -f "/etc/systemd/system/$SERVICE_NAME" ]]; then
log_message "Service unit file missing: /etc/systemd/system/$SERVICE_NAME"
return 0
fi
# Check if check script exists
if [[ ! -f "/usr/local/bin/day-specific-shutdown-check.sh" ]]; then
log_message "Check script missing: /usr/local/bin/day-specific-shutdown-check.sh"
return 0
fi
return 1 # Timer is properly configured
}
# Function to restore timer
restore_timer() {
log_message "Shutdown timer tampering detected - initiating restoration"
# Reload systemd daemon in case unit files were modified
systemctl daemon-reload
# Re-enable timer if disabled
if ! systemctl is-enabled "$TIMER_NAME" &>/dev/null; then
log_message "Re-enabling $TIMER_NAME"
systemctl enable "$TIMER_NAME" 2>/dev/null || true
fi
# Re-start timer if not active
if ! systemctl is-active "$TIMER_NAME" &>/dev/null; then
log_message "Re-starting $TIMER_NAME"
systemctl start "$TIMER_NAME" 2>/dev/null || true
fi
# Verify restoration
if systemctl is-active "$TIMER_NAME" &>/dev/null; then
log_message "Timer restoration completed successfully"
else
log_message "WARNING: Timer restoration may have failed"
fi
}
# Function to monitor timer with systemd events
monitor_with_dbus() {
log_message "Starting shutdown timer monitoring with D-Bus events"
# Use busctl to monitor systemd unit changes
# Fall back to polling if this fails.
if command -v busctl &>/dev/null; then
# Monitor for unit state changes
busctl monitor --system org.freedesktop.systemd1 2>/dev/null |
while read -r line; do
# Check if the line mentions our timer
if [[ $line == *"$TIMER_NAME"* || $line == *"$SERVICE_NAME"* ]]; then
log_message "Systemd event detected for shutdown timer"
sleep 2
if timer_needs_restoration; then
restore_timer
fi
fi
done
else
log_message "busctl not available, falling back to polling"
monitor_with_polling
fi
}
# Function to monitor with polling (primary method for reliability)
monitor_with_polling() {
log_message "Starting shutdown timer monitoring with polling (interval: ${CHECK_INTERVAL}s)"
while true; do
if timer_needs_restoration; then
restore_timer
fi
sleep "$CHECK_INTERVAL"
done
}
start_monitoring() {
log_message "=== Shutdown Timer Monitor Started ==="
log_message "Monitoring timer: $TIMER_NAME"
log_message "Monitoring service: $SERVICE_NAME"
# Initial check
if timer_needs_restoration; then
log_message "Initial check: Timer needs restoration"
restore_timer
else
log_message "Initial check: Timer is properly configured"
fi
# Prefer D-Bus monitoring, with polling as the fallback path.
if command -v busctl &>/dev/null; then
monitor_with_dbus
else
log_message "busctl not available, falling back to polling"
monitor_with_polling
fi
}
# Main execution
if [[ ${SHUTDOWN_TIMER_MONITOR_SKIP_MAIN:-0} -ne 1 ]]; then
start_monitoring
fi