Add shutdown timer monitor service to prevent disabling

- Remove 'disable' option from setup_midnight_shutdown.sh
- Add shutdown-timer-monitor.sh that watches the timer every 30s
- Re-enables timer automatically if someone tries to disable it
- Monitor service installed alongside the timer
- Makes it significantly harder to bypass the shutdown schedule
- Similar pattern to hosts-file-monitor.service
This commit is contained in:
Krzysztof kuhy Rudnicki 2025-12-07 14:08:13 +01:00
parent 4cb3a62491
commit a1b9200d19
3 changed files with 559 additions and 337 deletions

View File

@ -8,186 +8,132 @@ set -e # Exit on any error
# Function to show usage # Function to show usage
show_usage() { show_usage() {
echo "Day-Specific Auto-Shutdown Setup for Arch Linux" echo "Day-Specific Auto-Shutdown Setup for Arch Linux"
echo "===============================================" echo "==============================================="
echo "Usage: $0 [enable|disable|status]" echo "Usage: $0 [enable|status]"
echo "" echo ""
echo "Commands:" echo "Commands:"
echo " enable - Set up automatic shutdown with day-specific windows (default)" echo " enable - Set up automatic shutdown with day-specific windows (default)"
echo " disable - Remove automatic shutdown" echo " status - Show current status"
echo " status - Show current status" echo ""
echo "" echo "Shutdown Schedule:"
echo "Shutdown Schedule:" echo " Monday-Wednesday: 21:00-05:00"
echo " Monday-Wednesday: 21:00-05:00" echo " Thursday-Sunday: 22:00-05:00"
echo " Thursday-Sunday: 22:00-05:00" echo ""
echo "" echo "NOTE: There is no 'disable' option. This is intentional."
echo " The shutdown timer is protected by a monitor service."
echo ""
} }
# Function to check and request sudo privileges # Function to check and request sudo privileges
check_sudo() { check_sudo() {
if [[ $EUID -ne 0 ]]; then if [[ $EUID -ne 0 ]]; then
echo "This script requires sudo privileges to manage systemd services." echo "This script requires sudo privileges to manage systemd services."
echo "Requesting sudo access..." echo "Requesting sudo access..."
exec sudo "$0" "$@" exec sudo "$0" "$@"
fi fi
} }
# Get the actual user (even when running with sudo) # Get the actual user (even when running with sudo)
if [[ -n $SUDO_USER ]]; then if [[ -n $SUDO_USER ]]; then
ACTUAL_USER="$SUDO_USER" ACTUAL_USER="$SUDO_USER"
USER_HOME="/home/$SUDO_USER" USER_HOME="/home/$SUDO_USER"
else else
ACTUAL_USER="$USER" ACTUAL_USER="$USER"
USER_HOME="$HOME" USER_HOME="$HOME"
fi fi
# Function to disable and remove midnight shutdown
disable_midnight_shutdown() {
echo "Disabling Day-Specific Auto-Shutdown"
echo "===================================="
echo "Current Date: $(date)"
echo "User: $ACTUAL_USER"
echo ""
local timer_file="/etc/systemd/system/day-specific-shutdown.timer"
local service_file="/etc/systemd/system/day-specific-shutdown.service"
local script_file="/usr/local/bin/day-specific-shutdown-manager.sh"
local check_script="/usr/local/bin/day-specific-shutdown-check.sh"
local removed_files=()
# Stop and disable timer if it exists
if systemctl is-active day-specific-shutdown.timer &> /dev/null; then
echo "Stopping day-specific-shutdown timer..."
systemctl stop day-specific-shutdown.timer
echo "✓ Timer stopped"
fi
if systemctl is-enabled day-specific-shutdown.timer &> /dev/null; then
echo "Disabling day-specific-shutdown timer..."
systemctl disable day-specific-shutdown.timer
echo "✓ Timer disabled"
fi
# Remove timer file
if [[ -f $timer_file ]]; then
rm -f "$timer_file"
removed_files+=("$timer_file")
echo "✓ Removed timer file: $timer_file"
fi
# Remove service file
if [[ -f $service_file ]]; then
rm -f "$service_file"
removed_files+=("$service_file")
echo "✓ Removed service file: $service_file"
fi
# Remove management script
if [[ -f $script_file ]]; then
rm -f "$script_file"
removed_files+=("$script_file")
echo "✓ Removed management script: $script_file"
fi
# Remove check script
if [[ -f $check_script ]]; then
rm -f "$check_script"
removed_files+=("$check_script")
echo "✓ Removed check script: $check_script"
fi
# Reload systemd daemon
if [[ ${#removed_files[@]} -gt 0 ]]; then
echo "Reloading systemd daemon..."
systemctl daemon-reload
echo "✓ Systemd daemon reloaded"
fi
echo ""
echo "============================================="
echo "Day-Specific Auto-Shutdown Removal Complete"
echo "============================================="
if [[ ${#removed_files[@]} -gt 0 ]]; then
echo "Removed files:"
printf " %s\n" "${removed_files[@]}"
echo ""
echo "✓ Automatic day-specific shutdown has been completely disabled"
echo "✓ Your PC will no longer shutdown automatically"
else
echo "No day-specific shutdown configuration was found to remove."
fi
echo ""
}
# Function to show current status # Function to show current status
show_current_status() { show_current_status() {
echo "Day-Specific Auto-Shutdown Status" echo "Day-Specific Auto-Shutdown Status"
echo "=================================" echo "================================="
echo "Current Date: $(date)" echo "Current Date: $(date)"
echo "User: $ACTUAL_USER" echo "User: $ACTUAL_USER"
echo "" echo ""
local timer_exists=false local timer_exists=false
# Check if files exist # Check if files exist
if [[ -f "/etc/systemd/system/day-specific-shutdown.timer" ]]; then if [[ -f "/etc/systemd/system/day-specific-shutdown.timer" ]]; then
timer_exists=true timer_exists=true
echo "✓ Timer file exists" echo "✓ Timer file exists"
else else
echo "✗ Timer file missing" echo "✗ Timer file missing"
fi fi
if [[ -f "/etc/systemd/system/day-specific-shutdown.service" ]]; then if [[ -f "/etc/systemd/system/day-specific-shutdown.service" ]]; then
echo "✓ Service file exists" echo "✓ Service file exists"
else else
echo "✗ Service file missing" echo "✗ Service file missing"
fi fi
if [[ -f "/usr/local/bin/day-specific-shutdown-manager.sh" ]]; then if [[ -f "/usr/local/bin/day-specific-shutdown-manager.sh" ]]; then
echo "✓ Management script exists" echo "✓ Management script exists"
else else
echo "✗ Management script missing" echo "✗ Management script missing"
fi fi
echo "" if [[ -f "/usr/local/bin/shutdown-timer-monitor.sh" ]]; then
echo "✓ Monitor script exists"
else
echo "✗ Monitor script missing"
fi
# Check systemd status echo ""
if $timer_exists; then
if systemctl is-enabled day-specific-shutdown.timer &> /dev/null; then
echo "✓ Timer is enabled"
if systemctl is-active day-specific-shutdown.timer &> /dev/null; then
echo "✓ Timer is active"
echo ""
echo "Next scheduled shutdown check:"
systemctl list-timers day-specific-shutdown.timer --no-pager 2> /dev/null | grep day-specific-shutdown || echo "Timer information not available"
else
echo "✗ Timer is not active"
fi
else
echo "✗ Timer is not enabled"
fi
else
echo "Status: NOT CONFIGURED"
fi
echo "" # Check systemd status
echo "Shutdown Schedule:" if $timer_exists; then
echo " Monday-Wednesday: 21:00-05:00" if systemctl is-enabled day-specific-shutdown.timer &>/dev/null; then
echo " Thursday-Sunday: 22:00-05:00" echo "✓ Timer is enabled"
echo "" if systemctl is-active day-specific-shutdown.timer &>/dev/null; then
echo "✓ Timer is active"
echo ""
echo "Next scheduled shutdown check:"
systemctl list-timers day-specific-shutdown.timer --no-pager 2>/dev/null | grep day-specific-shutdown || echo "Timer information not available"
else
echo "✗ Timer is not active"
fi
else
echo "✗ Timer is not enabled"
fi
else
echo "Status: NOT CONFIGURED"
fi
echo ""
# Check monitor service status
echo "Monitor Service Status:"
if systemctl is-enabled shutdown-timer-monitor.service &>/dev/null; then
echo "✓ Monitor is enabled"
if systemctl is-active shutdown-timer-monitor.service &>/dev/null; then
echo "✓ Monitor is active (will re-enable timer if disabled)"
else
echo "✗ Monitor is not active"
fi
else
echo "✗ Monitor is not enabled"
fi
echo ""
echo "Shutdown Schedule:"
echo " Monday-Wednesday: 21:00-05:00"
echo " Thursday-Sunday: 22:00-05:00"
echo ""
echo "NOTE: The shutdown timer is protected by a monitor service."
echo " If you try to disable the timer, it will be automatically re-enabled."
echo ""
} }
# Function to create the shutdown service # Function to create the shutdown service
create_shutdown_service() { create_shutdown_service() {
echo "" echo ""
echo "1. Creating Systemd Shutdown Service..." echo "1. Creating Systemd Shutdown Service..."
echo "======================================" echo "======================================"
local service_file="/etc/systemd/system/day-specific-shutdown.service" local service_file="/etc/systemd/system/day-specific-shutdown.service"
cat > "$service_file" << 'EOF' cat >"$service_file" <<'EOF'
[Unit] [Unit]
Description=Automatic PC shutdown with day-specific time windows Description=Automatic PC shutdown with day-specific time windows
DefaultDependencies=false DefaultDependencies=false
@ -201,18 +147,18 @@ StandardOutput=journal
StandardError=journal StandardError=journal
EOF EOF
echo "✓ Created systemd service: $service_file" echo "✓ Created systemd service: $service_file"
} }
# Function to create the shutdown timer # Function to create the shutdown timer
create_shutdown_timer() { create_shutdown_timer() {
echo "" echo ""
echo "2. Creating Systemd Shutdown Timer..." echo "2. Creating Systemd Shutdown Timer..."
echo "===================================" echo "==================================="
local timer_file="/etc/systemd/system/day-specific-shutdown.timer" local timer_file="/etc/systemd/system/day-specific-shutdown.timer"
cat > "$timer_file" << 'EOF' cat >"$timer_file" <<'EOF'
[Unit] [Unit]
Description=Timer for automatic PC shutdown with day-specific windows Description=Timer for automatic PC shutdown with day-specific windows
Requires=day-specific-shutdown.service Requires=day-specific-shutdown.service
@ -244,18 +190,18 @@ RandomizedDelaySec=0
WantedBy=timers.target WantedBy=timers.target
EOF EOF
echo "✓ Created systemd timer: $timer_file" echo "✓ Created systemd timer: $timer_file"
} }
# Function to create management script # Function to create management script
create_management_script() { create_management_script() {
echo "" echo ""
echo "3. Creating Management Script..." echo "3. Creating Management Script..."
echo "==============================" echo "=============================="
local script_file="/usr/local/bin/day-specific-shutdown-manager.sh" local script_file="/usr/local/bin/day-specific-shutdown-manager.sh"
cat > "$script_file" << 'EOF' cat >"$script_file" <<'EOF'
#!/bin/bash #!/bin/bash
# Day-Specific Auto-Shutdown Manager # Day-Specific Auto-Shutdown Manager
# Provides easy management of the day-specific shutdown feature # Provides easy management of the day-specific shutdown feature
@ -318,19 +264,19 @@ case "$1" in
esac esac
EOF EOF
chmod +x "$script_file" chmod +x "$script_file"
echo "✓ Created management script: $script_file" echo "✓ Created management script: $script_file"
} }
# Function to create smart shutdown check script # Function to create smart shutdown check script
create_shutdown_check_script() { create_shutdown_check_script() {
echo "" echo ""
echo "4. Creating Smart Shutdown Check Script..." echo "4. Creating Smart Shutdown Check Script..."
echo "========================================" echo "========================================"
local check_script="/usr/local/bin/day-specific-shutdown-check.sh" local check_script="/usr/local/bin/day-specific-shutdown-check.sh"
cat > "$check_script" << 'EOF' cat >"$check_script" <<'EOF'
#!/bin/bash #!/bin/bash
# Smart day-specific shutdown check script # Smart day-specific shutdown check script
# Different shutdown windows based on day of week: # Different shutdown windows based on day of week:
@ -397,206 +343,324 @@ else
fi fi
EOF EOF
chmod +x "$check_script" chmod +x "$check_script"
echo "✓ Created smart shutdown check script: $check_script" echo "✓ Created smart shutdown check script: $check_script"
} }
# Function to enable the timer # Function to enable the timer
enable_timer() { enable_timer() {
echo "" echo ""
echo "5. Enabling Shutdown Timer..." echo "5. Enabling Shutdown Timer..."
echo "============================" echo "============================"
# Reload systemd daemon # Reload systemd daemon
systemctl daemon-reload systemctl daemon-reload
echo "✓ Reloaded systemd daemon" echo "✓ Reloaded systemd daemon"
# Enable the timer # Enable the timer
systemctl enable day-specific-shutdown.timer systemctl enable day-specific-shutdown.timer
echo "✓ Enabled day-specific-shutdown timer" echo "✓ Enabled day-specific-shutdown timer"
# Start the timer # Start the timer
systemctl start day-specific-shutdown.timer systemctl start day-specific-shutdown.timer
echo "✓ Started day-specific-shutdown timer" echo "✓ Started day-specific-shutdown timer"
}
# Function to install the monitor service
install_monitor_service() {
echo ""
echo "6. Installing Shutdown Timer Monitor Service..."
echo "=============================================="
local monitor_script="/usr/local/bin/shutdown-timer-monitor.sh"
local monitor_service="/etc/systemd/system/shutdown-timer-monitor.service"
# Create the monitor script
cat >"$monitor_script" <<'EOF'
#!/bin/bash
# Shutdown timer monitor script
# Watches the day-specific-shutdown timer and re-enables it if disabled
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_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE" >&2
}
timer_needs_restoration() {
if ! systemctl is-enabled "$TIMER_NAME" &>/dev/null; then
log_message "Timer $TIMER_NAME is not enabled"
return 0
fi
if ! systemctl is-active "$TIMER_NAME" &>/dev/null; then
log_message "Timer $TIMER_NAME is not active"
return 0
fi
if [[ ! -f "/etc/systemd/system/$TIMER_NAME" ]]; then
log_message "Timer unit file missing"
return 0
fi
if [[ ! -f "/etc/systemd/system/$SERVICE_NAME" ]]; then
log_message "Service unit file missing"
return 0
fi
if [[ ! -f "/usr/local/bin/day-specific-shutdown-check.sh" ]]; then
log_message "Check script missing"
return 0
fi
return 1
}
restore_timer() {
log_message "Shutdown timer tampering detected - initiating restoration"
systemctl daemon-reload
if ! systemctl is-enabled "$TIMER_NAME" &>/dev/null; then
log_message "Re-enabling $TIMER_NAME"
systemctl enable "$TIMER_NAME" 2>/dev/null || true
fi
if ! systemctl is-active "$TIMER_NAME" &>/dev/null; then
log_message "Re-starting $TIMER_NAME"
systemctl start "$TIMER_NAME" 2>/dev/null || true
fi
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
}
log_message "=== Shutdown Timer Monitor Started ==="
log_message "Monitoring timer: $TIMER_NAME"
if timer_needs_restoration; then
log_message "Initial check: Timer needs restoration"
restore_timer
else
log_message "Initial check: Timer is properly configured"
fi
while true; do
if timer_needs_restoration; then
restore_timer
fi
sleep "$CHECK_INTERVAL"
done
EOF
chmod +x "$monitor_script"
echo "✓ Created monitor script: $monitor_script"
# Create the monitor service
cat >"$monitor_service" <<'EOF'
[Unit]
Description=Shutdown Timer Monitor and Auto-Restore Service
After=network-online.target day-specific-shutdown.timer
Wants=network-online.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/shutdown-timer-monitor.sh
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
NoNewPrivileges=false
PrivateTmp=true
MemoryMax=50M
CPUQuota=10%
[Install]
WantedBy=multi-user.target
EOF
echo "✓ Created monitor service: $monitor_service"
# Reload and enable monitor
systemctl daemon-reload
systemctl enable shutdown-timer-monitor.service
systemctl start shutdown-timer-monitor.service
echo "✓ Enabled and started shutdown-timer-monitor.service"
} }
# Function to test the setup # Function to test the setup
test_setup() { test_setup() {
echo "" echo ""
echo "6. Testing Setup..." echo "7. Testing Setup..."
echo "==================" echo "=================="
echo "Service files:" echo "Service files:"
if [[ -f "/etc/systemd/system/day-specific-shutdown.service" ]]; then if [[ -f "/etc/systemd/system/day-specific-shutdown.service" ]]; then
echo "✓ Service file exists" echo "✓ Service file exists"
else else
echo "✗ Service file missing" echo "✗ Service file missing"
fi fi
if [[ -f "/etc/systemd/system/day-specific-shutdown.timer" ]]; then if [[ -f "/etc/systemd/system/day-specific-shutdown.timer" ]]; then
echo "✓ Timer file exists" echo "✓ Timer file exists"
else else
echo "✗ Timer file missing" echo "✗ Timer file missing"
fi fi
echo "" if [[ -f "/etc/systemd/system/shutdown-timer-monitor.service" ]]; then
echo "Timer status:" echo "✓ Monitor service file exists"
if systemctl is-enabled day-specific-shutdown.timer &> /dev/null; then else
echo "✓ Timer is enabled" echo "✗ Monitor service file missing"
else fi
echo "✗ Timer is not enabled"
fi
if systemctl is-active day-specific-shutdown.timer &> /dev/null; then echo ""
echo "✓ Timer is active" echo "Timer status:"
else if systemctl is-enabled day-specific-shutdown.timer &>/dev/null; then
echo "✗ Timer is not active" echo "✓ Timer is enabled"
fi else
echo "✗ Timer is not enabled"
fi
echo "" if systemctl is-active day-specific-shutdown.timer &>/dev/null; then
echo "Next scheduled checks:" echo "✓ Timer is active"
systemctl list-timers day-specific-shutdown.timer --no-pager 2> /dev/null | head -5 | grep day-specific-shutdown || echo "Timer information not available" else
echo "✗ Timer is not active"
fi
echo ""
echo "Monitor status:"
if systemctl is-enabled shutdown-timer-monitor.service &>/dev/null; then
echo "✓ Monitor is enabled"
else
echo "✗ Monitor is not enabled"
fi
if systemctl is-active shutdown-timer-monitor.service &>/dev/null; then
echo "✓ Monitor is active"
else
echo "✗ Monitor is not active"
fi
echo ""
echo "Next scheduled checks:"
systemctl list-timers day-specific-shutdown.timer --no-pager 2>/dev/null | head -5 | grep day-specific-shutdown || echo "Timer information not available"
} }
# Function to show final instructions # Function to show final instructions
show_instructions() { show_instructions() {
echo "" echo ""
echo "=================================================" echo "================================================="
echo "Day-Specific Auto-Shutdown Setup Complete" echo "Day-Specific Auto-Shutdown Setup Complete"
echo "=================================================" echo "================================================="
echo "Summary:" echo "Summary:"
echo "✓ Systemd service created (/etc/systemd/system/day-specific-shutdown.service)" echo "✓ Systemd service created (/etc/systemd/system/day-specific-shutdown.service)"
echo "✓ Systemd timer created (/etc/systemd/system/day-specific-shutdown.timer)" echo "✓ Systemd timer created (/etc/systemd/system/day-specific-shutdown.timer)"
echo "✓ Management script created (/usr/local/bin/day-specific-shutdown-manager.sh)" echo "✓ Management script created (/usr/local/bin/day-specific-shutdown-manager.sh)"
echo "✓ Smart check script created (/usr/local/bin/day-specific-shutdown-check.sh)" echo "✓ Smart check script created (/usr/local/bin/day-specific-shutdown-check.sh)"
echo "✓ Timer enabled and started" echo "✓ Timer enabled and started"
echo "" echo "✓ Monitor service installed and started (protects timer from being disabled)"
echo "Shutdown Schedule:" echo ""
echo " Monday-Wednesday: 21:00-05:00 (9:00 PM to 5:00 AM)" echo "Shutdown Schedule:"
echo " Thursday-Sunday: 22:00-05:00 (10:00 PM to 5:00 AM)" echo " Monday-Wednesday: 21:00-05:00 (9:00 PM to 5:00 AM)"
echo "" echo " Thursday-Sunday: 22:00-05:00 (10:00 PM to 5:00 AM)"
echo "Management commands:" echo ""
echo " sudo day-specific-shutdown-manager.sh status - Check status" echo "Management commands:"
echo " sudo day-specific-shutdown-manager.sh logs - View shutdown logs" echo " sudo day-specific-shutdown-manager.sh status - Check status"
echo "" echo " sudo day-specific-shutdown-manager.sh logs - View shutdown logs"
echo "How it works:" echo ""
echo "• Timer checks every 30 minutes during potential shutdown windows" echo "How it works:"
echo "• Smart logic determines shutdown eligibility based on day and time" echo "• Timer checks every 30 minutes during potential shutdown windows"
echo "• Prevents accidental shutdowns outside designated time windows" echo "• Smart logic determines shutdown eligibility based on day and time"
echo "" echo "• Monitor service watches the timer and re-enables it if disabled"
echo "WARNING: This will automatically shutdown your PC during designated hours." echo "• There is NO disable option - this is intentional for digital wellbeing"
echo "Make sure to save your work before the shutdown windows!" echo ""
echo "" echo "WARNING: This will automatically shutdown your PC during designated hours."
echo "Make sure to save your work before the shutdown windows!"
echo ""
} }
# Function to prompt for confirmation # Function to prompt for confirmation
confirm_setup() { confirm_setup() {
echo "" echo ""
echo "WARNING: Day-Specific Auto-Shutdown Confirmation" echo "WARNING: Day-Specific Auto-Shutdown Confirmation"
echo "===============================================" echo "==============================================="
echo "This will set up your PC to automatically shutdown during specific time windows." echo "This will set up your PC to automatically shutdown during specific time windows."
echo "" echo ""
echo "Shutdown Schedule:" echo "Shutdown Schedule:"
echo " Monday-Wednesday: 21:00-05:00 (9:00 PM to 5:00 AM)" echo " Monday-Wednesday: 21:00-05:00 (9:00 PM to 5:00 AM)"
echo " Thursday-Sunday: 22:00-05:00 (10:00 PM to 5:00 AM)" echo " Thursday-Sunday: 22:00-05:00 (10:00 PM to 5:00 AM)"
echo "" echo ""
echo "Important considerations:" echo "Important considerations:"
echo "- Any unsaved work will be lost during shutdown windows" echo "- Any unsaved work will be lost during shutdown windows"
echo "- Running processes will be terminated" echo "- Running processes will be terminated"
echo "- Downloads/uploads in progress will be interrupted" echo "- Downloads/uploads in progress will be interrupted"
echo "- You'll need to manually power on your PC each day" echo "- You'll need to manually power on your PC each day"
echo "- Timer checks every 30 minutes during potential shutdown windows" echo "- Timer checks every 30 minutes during potential shutdown windows"
echo "" echo "- There is NO disable option - this is protected by a monitor service"
read -r -p "Do you want to proceed? (y/N): " confirm echo ""
read -r -p "Do you want to proceed? (y/N): " confirm
case "$confirm" in case "$confirm" in
[yY] | [yY][eE][sS]) [yY] | [yY][eE][sS])
echo "Proceeding with setup..." echo "Proceeding with setup..."
return 0 return 0
;; ;;
*) *)
echo "Setup cancelled." echo "Setup cancelled."
exit 0 exit 0
;; ;;
esac esac
}
# Function to confirm disable
confirm_disable() {
echo ""
echo "Disable Day-Specific Auto-Shutdown Confirmation"
echo "==============================================="
echo "This will completely remove the automatic day-specific shutdown configuration."
echo ""
echo "After disabling:"
echo "- Your PC will no longer shutdown automatically during any time windows"
echo "- All related systemd services and timers will be removed"
echo "- The management and check scripts will be deleted"
echo ""
read -r -p "Do you want to proceed with disabling? (y/N): " confirm
case "$confirm" in
[yY] | [yY][eE][sS])
echo "Proceeding with disable..."
return 0
;;
*)
echo "Disable cancelled."
exit 0
;;
esac
} }
# Main execution flow for enable # Main execution flow for enable
enable_midnight_shutdown() { enable_midnight_shutdown() {
echo "Day-Specific Auto-Shutdown Setup for Arch Linux" echo "Day-Specific Auto-Shutdown Setup for Arch Linux"
echo "===============================================" echo "==============================================="
echo "Current Date: $(date)" echo "Current Date: $(date)"
echo "User: $ACTUAL_USER" echo "User: $ACTUAL_USER"
echo "Target user: $ACTUAL_USER" echo "Target user: $ACTUAL_USER"
echo "User home: $USER_HOME" echo "User home: $USER_HOME"
# Confirm setup # Confirm setup
confirm_setup confirm_setup
# Create systemd files # Create systemd files
create_shutdown_service create_shutdown_service
create_shutdown_timer create_shutdown_timer
create_management_script create_management_script
create_shutdown_check_script create_shutdown_check_script
# Enable and start timer # Enable and start timer
enable_timer enable_timer
# Test setup # Install monitor service (protects timer from being disabled)
test_setup install_monitor_service
# Show instructions # Test setup
show_instructions test_setup
# Show instructions
show_instructions
} }
# Parse command line arguments # Parse command line arguments
case "${1:-enable}" in case "${1:-enable}" in
"enable") "enable")
check_sudo "$@" check_sudo "$@"
enable_midnight_shutdown enable_midnight_shutdown
;; ;;
"disable") "status")
check_sudo "$@" check_sudo "$@"
confirm_disable show_current_status
disable_midnight_shutdown ;;
;; "help" | "-h" | "--help")
"status") show_usage
check_sudo "$@" ;;
show_current_status *)
;; echo "Error: Unknown command '$1'"
"help" | "-h" | "--help") echo ""
show_usage show_usage
;; exit 1
*) ;;
echo "Error: Unknown command '$1'"
echo ""
show_usage
exit 1
;;
esac esac

View File

@ -0,0 +1,131 @@
#!/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
# Function to log with timestamp
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $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 echo "$line" | grep -q "$TIMER_NAME\|$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
}
# Main execution
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
# Use polling for reliability (D-Bus monitoring can miss events)
monitor_with_polling

View File

@ -0,0 +1,27 @@
[Unit]
Description=Shutdown Timer Monitor and Auto-Restore Service
After=network-online.target day-specific-shutdown.timer
Wants=network-online.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/shutdown-timer-monitor.sh
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
# Environment
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Security settings
NoNewPrivileges=false
PrivateTmp=true
# Resource limits
MemoryMax=50M
CPUQuota=10%
[Install]
WantedBy=multi-user.target