mirror of
https://github.com/kuhyx/scripts.git
synced 2026-07-04 15:43:17 +02:00
feat: more restrictive midnight shutdown
This commit is contained in:
parent
29f6fa61dc
commit
4ebd6c52be
@ -1,57 +1,53 @@
|
||||
#!/bin/bash
|
||||
# Shutdown countdown status script for i3blocks
|
||||
# Shows time remaining until the next shutdown window
|
||||
# Dynamically reads shutdown times from the systemd check script
|
||||
# Reads shutdown times from shared config file written by setup_midnight_shutdown.sh
|
||||
|
||||
SHUTDOWN_CHECK_SCRIPT="/usr/local/bin/day-specific-shutdown-check.sh"
|
||||
SHUTDOWN_CONFIG="/etc/shutdown-schedule.conf"
|
||||
|
||||
# Function to extract shutdown hour from the check script
|
||||
# Parses lines like "if [[ $current_time_minutes -ge 1260 ]]" where 1260 = 21*60
|
||||
get_shutdown_hours() {
|
||||
if [[ ! -f "$SHUTDOWN_CHECK_SCRIPT" ]]; then
|
||||
# Fallback defaults if script not found
|
||||
echo "21 22"
|
||||
return
|
||||
fi
|
||||
|
||||
# Extract the minute thresholds from the script (e.g., 1260 for 21:00, 1320 for 22:00)
|
||||
# The script checks: if [[ $current_time_minutes -ge XXXX ]]
|
||||
# Get unique values - first is Mon-Wed (1260=21:00), second is Thu-Sun (1320=22:00)
|
||||
local thresholds
|
||||
thresholds=$(grep -oP 'current_time_minutes -ge \K\d{4}' "$SHUTDOWN_CHECK_SCRIPT" 2>/dev/null | sort -u)
|
||||
|
||||
if [[ -z "$thresholds" ]]; then
|
||||
echo "21 22"
|
||||
return
|
||||
fi
|
||||
|
||||
local mon_wed_minutes thu_sun_minutes
|
||||
mon_wed_minutes=$(echo "$thresholds" | head -1) # 1260 (smaller = earlier = Mon-Wed)
|
||||
thu_sun_minutes=$(echo "$thresholds" | tail -1) # 1320 (larger = later = Thu-Sun)
|
||||
|
||||
# Convert minutes to hours
|
||||
local mon_wed_hour=$((mon_wed_minutes / 60))
|
||||
local thu_sun_hour=$((thu_sun_minutes / 60))
|
||||
|
||||
echo "$mon_wed_hour $thu_sun_hour"
|
||||
# Function to show error state in i3blocks and exit
|
||||
show_error() {
|
||||
local message="$1"
|
||||
echo "⏻ $message"
|
||||
echo "⏻"
|
||||
echo "#FF79C6" # Pink/magenta for config errors
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Validate and load config file
|
||||
if [[ ! -f "$SHUTDOWN_CONFIG" ]]; then
|
||||
show_error "NO CONFIG"
|
||||
fi
|
||||
|
||||
# Source the config file to get MON_WED_HOUR and THU_SUN_HOUR
|
||||
# shellcheck source=/dev/null
|
||||
if ! source "$SHUTDOWN_CONFIG" 2>/dev/null; then
|
||||
show_error "BAD CONFIG"
|
||||
fi
|
||||
|
||||
# Validate that required variables are set
|
||||
if [[ -z "${MON_WED_HOUR:-}" ]] || [[ -z "${THU_SUN_HOUR:-}" ]]; then
|
||||
show_error "MISSING VARS"
|
||||
fi
|
||||
|
||||
# Validate that values are numbers
|
||||
if ! [[ "$MON_WED_HOUR" =~ ^[0-9]+$ ]] || ! [[ "$THU_SUN_HOUR" =~ ^[0-9]+$ ]]; then
|
||||
show_error "INVALID HOURS"
|
||||
fi
|
||||
|
||||
# Get current time info
|
||||
current_hour=$(date +%H)
|
||||
current_minute=$(date +%M)
|
||||
current_time_minutes=$((10#$current_hour * 60 + 10#$current_minute))
|
||||
day_of_week=$(date +%u) # 1=Monday, 7=Sunday
|
||||
|
||||
# Get shutdown hours dynamically
|
||||
read -r mon_wed_hour thu_sun_hour <<<"$(get_shutdown_hours)"
|
||||
|
||||
# Determine shutdown hour based on day of week
|
||||
if [[ $day_of_week -ge 1 ]] && [[ $day_of_week -le 3 ]]; then
|
||||
# Monday-Wednesday
|
||||
shutdown_hour=$mon_wed_hour
|
||||
shutdown_hour=$MON_WED_HOUR
|
||||
else
|
||||
# Thursday-Sunday
|
||||
shutdown_hour=$thu_sun_hour
|
||||
shutdown_hour=$THU_SUN_HOUR
|
||||
fi
|
||||
|
||||
shutdown_time_minutes=$((shutdown_hour * 60))
|
||||
|
||||
@ -11,6 +11,113 @@ SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||
# shellcheck source=../lib/common.sh
|
||||
source "$SCRIPT_DIR/../lib/common.sh"
|
||||
|
||||
# Schedule constants (single source of truth for this script)
|
||||
# These values are written to /etc/shutdown-schedule.conf during setup
|
||||
SCHEDULE_MON_WED_HOUR=21
|
||||
SCHEDULE_THU_SUN_HOUR=22
|
||||
SCHEDULE_MORNING_END_HOUR=5
|
||||
|
||||
# ============================================================================
|
||||
# SCHEDULE PROTECTION MECHANISM
|
||||
# ============================================================================
|
||||
# This prevents easy "cheating" by modifying the script values and re-running.
|
||||
# If a canonical config already exists, the script compares against it and
|
||||
# BLOCKS installation if the new values would make the schedule MORE LENIENT
|
||||
# (i.e., later shutdown hours or earlier morning end).
|
||||
# To legitimately change the schedule, use: sudo /usr/local/sbin/unlock-shutdown-schedule
|
||||
# ============================================================================
|
||||
|
||||
CANONICAL_CONFIG="/usr/local/share/locked-shutdown-schedule.conf"
|
||||
|
||||
# Check if trying to make schedule more lenient (later shutdown / earlier morning end)
|
||||
check_schedule_protection() {
|
||||
# Skip check if no canonical config exists (first install)
|
||||
if [[ ! -f "$CANONICAL_CONFIG" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Load canonical values
|
||||
local canonical_mon_wed canonical_thu_sun canonical_morning_end
|
||||
# shellcheck source=/dev/null
|
||||
source "$CANONICAL_CONFIG" 2>/dev/null || return 0
|
||||
canonical_mon_wed="${MON_WED_HOUR:-}"
|
||||
canonical_thu_sun="${THU_SUN_HOUR:-}"
|
||||
canonical_morning_end="${MORNING_END_HOUR:-}"
|
||||
|
||||
# If canonical values are empty, skip check
|
||||
if [[ -z "$canonical_mon_wed" ]] || [[ -z "$canonical_thu_sun" ]] || [[ -z "$canonical_morning_end" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
local violations=()
|
||||
|
||||
# Check if Mon-Wed hour is being made LATER (more lenient)
|
||||
if [[ $SCHEDULE_MON_WED_HOUR -gt $canonical_mon_wed ]]; then
|
||||
violations+=("Mon-Wed shutdown: ${canonical_mon_wed}:00 → ${SCHEDULE_MON_WED_HOUR}:00 (later)")
|
||||
fi
|
||||
|
||||
# Check if Thu-Sun hour is being made LATER (more lenient)
|
||||
if [[ $SCHEDULE_THU_SUN_HOUR -gt $canonical_thu_sun ]]; then
|
||||
violations+=("Thu-Sun shutdown: ${canonical_thu_sun}:00 → ${SCHEDULE_THU_SUN_HOUR}:00 (later)")
|
||||
fi
|
||||
|
||||
# Check if morning end is being made EARLIER (more lenient - shorter shutdown window)
|
||||
if [[ $SCHEDULE_MORNING_END_HOUR -lt $canonical_morning_end ]]; then
|
||||
violations+=("Morning end: 0${canonical_morning_end}:00 → 0${SCHEDULE_MORNING_END_HOUR}:00 (earlier)")
|
||||
fi
|
||||
|
||||
if [[ ${#violations[@]} -gt 0 ]]; then
|
||||
echo ""
|
||||
echo "╔══════════════════════════════════════════════════════════════════╗"
|
||||
echo "║ ❌ SCHEDULE MODIFICATION BLOCKED - CHEATING DETECTED! ❌ ║"
|
||||
echo "╚══════════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo "You modified the script to make the shutdown schedule MORE LENIENT:"
|
||||
echo ""
|
||||
for v in "${violations[@]}"; do
|
||||
echo " • $v"
|
||||
done
|
||||
echo ""
|
||||
echo "Current protected schedule:"
|
||||
echo " Monday-Wednesday: ${canonical_mon_wed}:00 - 0${canonical_morning_end}:00"
|
||||
echo " Thursday-Sunday: ${canonical_thu_sun}:00 - 0${canonical_morning_end}:00"
|
||||
echo ""
|
||||
echo "Nice try! But this is exactly the kind of late-night bargaining"
|
||||
echo "that this protection is designed to prevent. 😉"
|
||||
echo ""
|
||||
echo "If you REALLY need to change the schedule, use the proper unlock:"
|
||||
echo " sudo /usr/local/sbin/unlock-shutdown-schedule"
|
||||
echo ""
|
||||
echo "This requires waiting through a psychological delay to give you"
|
||||
echo "time to reconsider whether you actually need more screen time."
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Making schedule STRICTER is always allowed
|
||||
local stricter=()
|
||||
if [[ $SCHEDULE_MON_WED_HOUR -lt $canonical_mon_wed ]]; then
|
||||
stricter+=("Mon-Wed: ${canonical_mon_wed}:00 → ${SCHEDULE_MON_WED_HOUR}:00 (earlier)")
|
||||
fi
|
||||
if [[ $SCHEDULE_THU_SUN_HOUR -lt $canonical_thu_sun ]]; then
|
||||
stricter+=("Thu-Sun: ${canonical_thu_sun}:00 → ${SCHEDULE_THU_SUN_HOUR}:00 (earlier)")
|
||||
fi
|
||||
if [[ $SCHEDULE_MORNING_END_HOUR -gt $canonical_morning_end ]]; then
|
||||
stricter+=("Morning end: 0${canonical_morning_end}:00 → 0${SCHEDULE_MORNING_END_HOUR}:00 (later)")
|
||||
fi
|
||||
|
||||
if [[ ${#stricter[@]} -gt 0 ]]; then
|
||||
echo ""
|
||||
echo "ℹ️ Schedule is being made STRICTER (allowed without unlock):"
|
||||
for s in "${stricter[@]}"; do
|
||||
echo " • $s"
|
||||
done
|
||||
echo ""
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to show usage
|
||||
show_usage() {
|
||||
echo "Day-Specific Auto-Shutdown Setup for Arch Linux"
|
||||
@ -22,8 +129,8 @@ show_usage() {
|
||||
echo " status - Show current status"
|
||||
echo ""
|
||||
echo "Shutdown Schedule:"
|
||||
echo " Monday-Wednesday: 21:00-05:00"
|
||||
echo " Thursday-Sunday: 22:00-05:00"
|
||||
echo " Monday-Wednesday: ${SCHEDULE_MON_WED_HOUR}:00-0${SCHEDULE_MORNING_END_HOUR}:00"
|
||||
echo " Thursday-Sunday: ${SCHEDULE_THU_SUN_HOUR}:00-0${SCHEDULE_MORNING_END_HOUR}:00"
|
||||
echo ""
|
||||
echo "NOTE: There is no 'disable' option. This is intentional."
|
||||
echo " The shutdown timer is protected by a monitor service."
|
||||
@ -114,20 +221,328 @@ show_current_status() {
|
||||
echo "✗ Monitor is not enabled"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# Check config file protection status
|
||||
echo "Config File Protection Status:"
|
||||
local config_file="/etc/shutdown-schedule.conf"
|
||||
local canonical_file="/usr/local/share/locked-shutdown-schedule.conf"
|
||||
|
||||
if [[ -f "$config_file" ]]; then
|
||||
echo "✓ Config file exists"
|
||||
# Check immutable attribute
|
||||
if lsattr "$config_file" 2>/dev/null | grep -q '^....i'; then
|
||||
echo "✓ Config file is immutable (chattr +i)"
|
||||
else
|
||||
echo "✗ Config file is NOT immutable"
|
||||
fi
|
||||
else
|
||||
echo "✗ Config file missing"
|
||||
fi
|
||||
|
||||
if [[ -f "$canonical_file" ]]; then
|
||||
echo "✓ Canonical copy exists"
|
||||
else
|
||||
echo "✗ Canonical copy missing"
|
||||
fi
|
||||
|
||||
if systemctl is-enabled shutdown-schedule-guard.path &>/dev/null; then
|
||||
echo "✓ Config path watcher is enabled"
|
||||
if systemctl is-active shutdown-schedule-guard.path &>/dev/null; then
|
||||
echo "✓ Config path watcher is active"
|
||||
else
|
||||
echo "✗ Config path watcher is not active"
|
||||
fi
|
||||
else
|
||||
echo "✗ Config path watcher is not enabled"
|
||||
fi
|
||||
|
||||
if [[ -f "/usr/local/sbin/unlock-shutdown-schedule" ]]; then
|
||||
echo "✓ Unlock script exists"
|
||||
else
|
||||
echo "✗ Unlock script missing"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Shutdown Schedule:"
|
||||
echo " Monday-Wednesday: 21:00-05:00"
|
||||
echo " Thursday-Sunday: 22:00-05:00"
|
||||
echo " Monday-Wednesday: ${SCHEDULE_MON_WED_HOUR}:00-0${SCHEDULE_MORNING_END_HOUR}:00"
|
||||
echo " Thursday-Sunday: ${SCHEDULE_THU_SUN_HOUR}:00-0${SCHEDULE_MORNING_END_HOUR}: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 ""
|
||||
echo "NOTE: The config file is protected by:"
|
||||
echo " - Immutable attribute (chattr +i)"
|
||||
echo " - Canonical copy that auto-restores on modification"
|
||||
echo " - Path watcher service"
|
||||
echo " To modify: sudo /usr/local/sbin/unlock-shutdown-schedule"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Function to create shutdown schedule config file (shared with i3blocks countdown)
|
||||
# Also creates a canonical (protected) copy and sets immutable attribute
|
||||
create_shutdown_config() {
|
||||
echo ""
|
||||
echo "1. Creating Shutdown Schedule Config..."
|
||||
echo "======================================="
|
||||
|
||||
local config_file="/etc/shutdown-schedule.conf"
|
||||
local canonical_file="/usr/local/share/locked-shutdown-schedule.conf"
|
||||
|
||||
# Remove immutable attribute if it exists (to allow update)
|
||||
chattr -i "$config_file" 2>/dev/null || true
|
||||
chattr -i "$canonical_file" 2>/dev/null || true
|
||||
|
||||
cat >"$config_file" <<EOF
|
||||
# Shutdown schedule configuration
|
||||
# This file is managed by setup_midnight_shutdown.sh
|
||||
# Used by: day-specific-shutdown-check.sh, shutdown_countdown.sh (i3blocks)
|
||||
#
|
||||
# WARNING: This file is protected by:
|
||||
# 1. Immutable attribute (chattr +i)
|
||||
# 2. Canonical copy at /usr/local/share/locked-shutdown-schedule.conf
|
||||
# 3. Path watcher service that auto-restores if modified
|
||||
#
|
||||
# To modify this file, you need to:
|
||||
# 1. Run: sudo /usr/local/sbin/unlock-shutdown-schedule
|
||||
# 2. Wait through the psychological delay
|
||||
# 3. Edit the file during the brief unlock window
|
||||
# 4. The file will be re-locked automatically
|
||||
|
||||
# Shutdown hour for Monday-Wednesday (24-hour format)
|
||||
MON_WED_HOUR=${SCHEDULE_MON_WED_HOUR}
|
||||
|
||||
# Shutdown hour for Thursday-Sunday (24-hour format)
|
||||
THU_SUN_HOUR=${SCHEDULE_THU_SUN_HOUR}
|
||||
|
||||
# Morning end hour (shutdown window ends at this hour)
|
||||
MORNING_END_HOUR=${SCHEDULE_MORNING_END_HOUR}
|
||||
EOF
|
||||
|
||||
chmod 644 "$config_file"
|
||||
echo "✓ Created shutdown schedule config: $config_file"
|
||||
|
||||
# Create canonical (protected) copy
|
||||
install -m 644 -D "$config_file" "$canonical_file"
|
||||
echo "✓ Created canonical copy: $canonical_file"
|
||||
|
||||
# Set immutable attribute on both files
|
||||
chattr +i "$config_file" || echo "⚠ Warning: Could not set immutable attribute on $config_file"
|
||||
chattr +i "$canonical_file" || echo "⚠ Warning: Could not set immutable attribute on $canonical_file"
|
||||
echo "✓ Set immutable attribute (chattr +i) on config files"
|
||||
}
|
||||
|
||||
# Function to create config guard (path watcher + enforcement + unlock script)
|
||||
create_config_guard() {
|
||||
echo ""
|
||||
echo "2. Creating Config Guard (Path Watcher + Enforcement)..."
|
||||
echo "========================================================"
|
||||
|
||||
local enforce_script="/usr/local/sbin/enforce-shutdown-schedule.sh"
|
||||
local unlock_script="/usr/local/sbin/unlock-shutdown-schedule"
|
||||
local guard_service="/etc/systemd/system/shutdown-schedule-guard.service"
|
||||
local guard_path="/etc/systemd/system/shutdown-schedule-guard.path"
|
||||
|
||||
# Create enforcement script
|
||||
cat >"$enforce_script" <<'EOF'
|
||||
#!/bin/bash
|
||||
# Enforce canonical /etc/shutdown-schedule.conf contents
|
||||
# This script restores the config from canonical copy if tampered
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
CANONICAL_SOURCE="/usr/local/share/locked-shutdown-schedule.conf"
|
||||
TARGET="/etc/shutdown-schedule.conf"
|
||||
LOG_FILE="/var/log/shutdown-schedule-guard.log"
|
||||
|
||||
log() {
|
||||
printf '%s - %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" | tee -a "$LOG_FILE" >&2
|
||||
}
|
||||
|
||||
if [[ ! -f $CANONICAL_SOURCE ]]; then
|
||||
log "Canonical config not found at $CANONICAL_SOURCE; aborting enforcement"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Remove immutable attr to check/restore
|
||||
chattr -i -a "$TARGET" 2>/dev/null || true
|
||||
|
||||
if ! cmp -s "$CANONICAL_SOURCE" "$TARGET"; then
|
||||
log "CONFIG TAMPERING DETECTED – restoring $TARGET from canonical copy"
|
||||
cp "$CANONICAL_SOURCE" "$TARGET"
|
||||
chmod 644 "$TARGET"
|
||||
log "Config restored successfully"
|
||||
else
|
||||
log "No drift detected (contents identical)"
|
||||
fi
|
||||
|
||||
# Re-apply immutable attribute
|
||||
chattr +i "$TARGET" || log "Failed to set immutable attribute"
|
||||
|
||||
log "Enforcement complete"
|
||||
EOF
|
||||
|
||||
chmod +x "$enforce_script"
|
||||
echo "✓ Created enforcement script: $enforce_script"
|
||||
|
||||
# Create unlock script with psychological delay
|
||||
cat >"$unlock_script" <<'EOF'
|
||||
#!/bin/bash
|
||||
# Unlock shutdown schedule config for editing with psychological friction
|
||||
# This script:
|
||||
# 1. Makes you wait (psychological friction to discourage casual changes)
|
||||
# 2. Temporarily removes protection
|
||||
# 3. Opens the config in an editor
|
||||
# 4. Re-applies protection after editing
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
DELAY_SECONDS=45
|
||||
CONFIG_FILE="/etc/shutdown-schedule.conf"
|
||||
CANONICAL_FILE="/usr/local/share/locked-shutdown-schedule.conf"
|
||||
LOG_FILE="/var/log/shutdown-schedule-guard.log"
|
||||
EDITOR="${EDITOR:-nano}"
|
||||
|
||||
log() {
|
||||
printf '%s - %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" | tee -a "$LOG_FILE" >&2
|
||||
}
|
||||
|
||||
# Must be root
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root (sudo)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Log the unlock attempt
|
||||
log "=== UNLOCK ATTEMPT by $(logname 2>/dev/null || echo 'unknown') from TTY $(tty 2>/dev/null || echo 'unknown') ==="
|
||||
|
||||
echo ""
|
||||
echo "╔══════════════════════════════════════════════════════════════════╗"
|
||||
echo "║ SHUTDOWN SCHEDULE CONFIG UNLOCK - PSYCHOLOGICAL FRICTION ║"
|
||||
echo "╚══════════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo "You are about to modify the shutdown schedule configuration."
|
||||
echo "This file controls when your PC automatically shuts down for"
|
||||
echo "digital wellbeing purposes."
|
||||
echo ""
|
||||
echo "Current schedule:"
|
||||
if [[ -f "$CONFIG_FILE" ]]; then
|
||||
chattr -i "$CONFIG_FILE" 2>/dev/null || true
|
||||
source "$CONFIG_FILE" 2>/dev/null || true
|
||||
chattr +i "$CONFIG_FILE" 2>/dev/null || true
|
||||
echo " Monday-Wednesday: ${MON_WED_HOUR:-??}:00 - 0${MORNING_END_HOUR:-?}:00"
|
||||
echo " Thursday-Sunday: ${THU_SUN_HOUR:-??}:00 - 0${MORNING_END_HOUR:-?}:00"
|
||||
fi
|
||||
echo ""
|
||||
echo "Are you making this change for a good reason, or are you just"
|
||||
echo "trying to stay up later? Remember why you set these limits."
|
||||
echo ""
|
||||
echo "To proceed, you must wait $DELAY_SECONDS seconds..."
|
||||
echo ""
|
||||
|
||||
# Countdown with opportunity to cancel
|
||||
for ((i=DELAY_SECONDS; i>0; i--)); do
|
||||
printf "\r ⏳ Waiting: %2d seconds remaining... (Ctrl+C to cancel)" "$i"
|
||||
sleep 1
|
||||
done
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
log "User waited through delay, proceeding with unlock"
|
||||
|
||||
# Stop the path watcher temporarily
|
||||
systemctl stop shutdown-schedule-guard.path 2>/dev/null || true
|
||||
|
||||
# Remove immutable attributes
|
||||
chattr -i -a "$CONFIG_FILE" 2>/dev/null || true
|
||||
chattr -i -a "$CANONICAL_FILE" 2>/dev/null || true
|
||||
|
||||
echo "Config file unlocked. Opening editor..."
|
||||
echo "After saving, protection will be re-applied automatically."
|
||||
echo ""
|
||||
|
||||
# Open editor
|
||||
$EDITOR "$CONFIG_FILE"
|
||||
|
||||
echo ""
|
||||
echo "Re-applying protection..."
|
||||
|
||||
# Copy to canonical
|
||||
cp "$CONFIG_FILE" "$CANONICAL_FILE"
|
||||
chmod 644 "$CONFIG_FILE"
|
||||
chmod 644 "$CANONICAL_FILE"
|
||||
|
||||
# Re-apply immutable
|
||||
chattr +i "$CONFIG_FILE" || echo "Warning: Could not set immutable attribute"
|
||||
chattr +i "$CANONICAL_FILE" || echo "Warning: Could not set immutable attribute"
|
||||
|
||||
# Restart path watcher
|
||||
systemctl start shutdown-schedule-guard.path 2>/dev/null || true
|
||||
|
||||
log "Config updated and re-locked by user"
|
||||
|
||||
echo ""
|
||||
echo "✓ Config file updated and re-protected"
|
||||
echo "✓ Canonical copy updated"
|
||||
echo "✓ Path watcher re-enabled"
|
||||
echo ""
|
||||
echo "New schedule (will take effect on next timer check):"
|
||||
source "$CONFIG_FILE" 2>/dev/null || true
|
||||
echo " Monday-Wednesday: ${MON_WED_HOUR:-??}:00 - 0${MORNING_END_HOUR:-?}:00"
|
||||
echo " Thursday-Sunday: ${THU_SUN_HOUR:-??}:00 - 0${MORNING_END_HOUR:-?}:00"
|
||||
echo ""
|
||||
EOF
|
||||
|
||||
chmod +x "$unlock_script"
|
||||
echo "✓ Created unlock script: $unlock_script"
|
||||
|
||||
# Create path watcher unit
|
||||
cat >"$guard_path" <<'EOF'
|
||||
[Unit]
|
||||
Description=Watch /etc/shutdown-schedule.conf and trigger enforcement
|
||||
|
||||
[Path]
|
||||
PathChanged=/etc/shutdown-schedule.conf
|
||||
Unit=shutdown-schedule-guard.service
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
echo "✓ Created path watcher: $guard_path"
|
||||
|
||||
# Create enforcement service
|
||||
cat >"$guard_service" <<'EOF'
|
||||
[Unit]
|
||||
Description=Enforce canonical /etc/shutdown-schedule.conf contents
|
||||
After=local-fs.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/sbin/enforce-shutdown-schedule.sh
|
||||
Nice=10
|
||||
IOSchedulingClass=idle
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
echo "✓ Created guard service: $guard_service"
|
||||
|
||||
# Reload and enable
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now shutdown-schedule-guard.path
|
||||
echo "✓ Enabled and started shutdown-schedule-guard.path"
|
||||
|
||||
# Run initial enforcement
|
||||
"$enforce_script" || echo "⚠ Warning: Initial enforcement returned non-zero"
|
||||
echo "✓ Ran initial enforcement"
|
||||
}
|
||||
|
||||
# Function to create the shutdown service
|
||||
create_shutdown_service() {
|
||||
echo ""
|
||||
echo "1. Creating Systemd Shutdown Service..."
|
||||
echo "3. Creating Systemd Shutdown Service..."
|
||||
echo "======================================"
|
||||
|
||||
local service_file="/etc/systemd/system/day-specific-shutdown.service"
|
||||
@ -152,7 +567,7 @@ EOF
|
||||
# Function to create the shutdown timer
|
||||
create_shutdown_timer() {
|
||||
echo ""
|
||||
echo "2. Creating Systemd Shutdown Timer..."
|
||||
echo "4. Creating Systemd Shutdown Timer..."
|
||||
echo "==================================="
|
||||
|
||||
local timer_file="/etc/systemd/system/day-specific-shutdown.timer"
|
||||
@ -163,10 +578,6 @@ Description=Timer for automatic PC shutdown with day-specific windows
|
||||
Requires=day-specific-shutdown.service
|
||||
|
||||
[Timer]
|
||||
OnCalendar=*-*-* 21:00:00
|
||||
OnCalendar=*-*-* 21:30:00
|
||||
OnCalendar=*-*-* 22:00:00
|
||||
OnCalendar=*-*-* 22:30:00
|
||||
OnCalendar=*-*-* 23:00:00
|
||||
OnCalendar=*-*-* 23:30:00
|
||||
OnCalendar=*-*-* 00:00:00
|
||||
@ -195,7 +606,7 @@ EOF
|
||||
# Function to create management script
|
||||
create_management_script() {
|
||||
echo ""
|
||||
echo "3. Creating Management Script..."
|
||||
echo "5. Creating Management Script..."
|
||||
echo "=============================="
|
||||
|
||||
local script_file="/usr/local/bin/day-specific-shutdown-manager.sh"
|
||||
@ -207,6 +618,27 @@ create_management_script() {
|
||||
|
||||
TIMER_NAME="day-specific-shutdown.timer"
|
||||
SERVICE_NAME="day-specific-shutdown.service"
|
||||
CONFIG_FILE="/etc/shutdown-schedule.conf"
|
||||
|
||||
# Load config for schedule display
|
||||
load_config() {
|
||||
if [[ -f "$CONFIG_FILE" ]]; then
|
||||
# shellcheck source=/dev/null
|
||||
source "$CONFIG_FILE"
|
||||
else
|
||||
echo "Warning: Config file $CONFIG_FILE not found"
|
||||
MON_WED_HOUR="??"
|
||||
THU_SUN_HOUR="??"
|
||||
MORNING_END_HOUR="??"
|
||||
fi
|
||||
}
|
||||
|
||||
print_schedule() {
|
||||
load_config
|
||||
echo "Shutdown Schedule:"
|
||||
echo " Monday-Wednesday: ${MON_WED_HOUR}:00-0${MORNING_END_HOUR}:00"
|
||||
echo " Thursday-Sunday: ${THU_SUN_HOUR}:00-0${MORNING_END_HOUR}:00"
|
||||
}
|
||||
|
||||
show_status() {
|
||||
echo "Day-Specific Auto-Shutdown Status"
|
||||
@ -224,9 +656,7 @@ show_status() {
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Shutdown Schedule:"
|
||||
echo " Monday-Wednesday: 21:00-05:00"
|
||||
echo " Thursday-Sunday: 22:00-05:00"
|
||||
print_schedule
|
||||
|
||||
echo ""
|
||||
echo "Next scheduled checks:"
|
||||
@ -254,9 +684,7 @@ case "$1" in
|
||||
echo " status - Show current status and next shutdown checks"
|
||||
echo " logs - Show recent shutdown logs"
|
||||
echo ""
|
||||
echo "Shutdown Schedule:"
|
||||
echo " Monday-Wednesday: 21:00-05:00"
|
||||
echo " Thursday-Sunday: 22:00-05:00"
|
||||
print_schedule
|
||||
echo ""
|
||||
show_status
|
||||
;;
|
||||
@ -270,7 +698,7 @@ EOF
|
||||
# Function to create smart shutdown check script
|
||||
create_shutdown_check_script() {
|
||||
echo ""
|
||||
echo "4. Creating Smart Shutdown Check Script..."
|
||||
echo "6. Creating Smart Shutdown Check Script..."
|
||||
echo "========================================"
|
||||
|
||||
local check_script="/usr/local/bin/day-specific-shutdown-check.sh"
|
||||
@ -278,9 +706,23 @@ create_shutdown_check_script() {
|
||||
cat >"$check_script" <<'EOF'
|
||||
#!/bin/bash
|
||||
# Smart day-specific shutdown check script
|
||||
# Different shutdown windows based on day of week:
|
||||
# Monday-Wednesday: 21:00-05:00
|
||||
# Thursday-Sunday: 22:00-05:00
|
||||
# Reads shutdown windows from /etc/shutdown-schedule.conf
|
||||
|
||||
CONFIG_FILE="/etc/shutdown-schedule.conf"
|
||||
|
||||
# Load config
|
||||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||||
logger -t day-specific-shutdown "ERROR: Config file $CONFIG_FILE not found"
|
||||
exit 1
|
||||
fi
|
||||
# shellcheck source=/dev/null
|
||||
source "$CONFIG_FILE"
|
||||
|
||||
# Validate config
|
||||
if [[ -z "${MON_WED_HOUR:-}" ]] || [[ -z "${THU_SUN_HOUR:-}" ]] || [[ -z "${MORNING_END_HOUR:-}" ]]; then
|
||||
logger -t day-specific-shutdown "ERROR: Config file missing required variables"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get current time and day
|
||||
current_hour=$(date +%H)
|
||||
@ -289,9 +731,10 @@ current_time_minutes=$((10#$current_hour * 60 + 10#$current_minute))
|
||||
day_of_week=$(date +%u) # 1=Monday, 7=Sunday
|
||||
day_name=$(date +%A)
|
||||
|
||||
# Convert time to minutes for easier comparison
|
||||
# 21:00 = 1260 minutes, 22:00 = 1320 minutes, 05:00 = 300 minutes
|
||||
# 00:00 = 0 minutes, 05:00 = 300 minutes
|
||||
# Calculate minute thresholds from config
|
||||
mon_wed_minutes=$((MON_WED_HOUR * 60))
|
||||
thu_sun_minutes=$((THU_SUN_HOUR * 60))
|
||||
morning_end_minutes=$((MORNING_END_HOUR * 60))
|
||||
|
||||
logger -t day-specific-shutdown "Checking shutdown conditions at $(date) - Day: $day_name ($day_of_week), Time: $current_hour:$current_minute"
|
||||
|
||||
@ -299,36 +742,34 @@ logger -t day-specific-shutdown "Checking shutdown conditions at $(date) - Day:
|
||||
should_shutdown=false
|
||||
|
||||
if [[ $day_of_week -ge 1 ]] && [[ $day_of_week -le 3 ]]; then
|
||||
# Monday (1), Tuesday (2), Wednesday (3): shutdown window 21:00-05:00
|
||||
logger -t day-specific-shutdown "Today is $day_name - checking 21:00-05:00 window"
|
||||
# Monday (1), Tuesday (2), Wednesday (3)
|
||||
shutdown_start=$mon_wed_minutes
|
||||
logger -t day-specific-shutdown "Today is $day_name - checking ${MON_WED_HOUR}:00-0${MORNING_END_HOUR}:00 window"
|
||||
|
||||
# Check if time is between 21:00 (1260 minutes) and 23:59 (1439 minutes)
|
||||
# OR between 00:00 (0 minutes) and 05:00 (300 minutes)
|
||||
if [[ $current_time_minutes -ge 1260 ]] || [[ $current_time_minutes -le 300 ]]; then
|
||||
if [[ $current_time_minutes -ge $shutdown_start ]] || [[ $current_time_minutes -le $morning_end_minutes ]]; then
|
||||
should_shutdown=true
|
||||
if [[ $current_time_minutes -ge 1260 ]]; then
|
||||
logger -t day-specific-shutdown "Time $current_hour:$current_minute is within evening shutdown window (21:00-23:59)"
|
||||
if [[ $current_time_minutes -ge $shutdown_start ]]; then
|
||||
logger -t day-specific-shutdown "Time $current_hour:$current_minute is within evening shutdown window (${MON_WED_HOUR}:00-23:59)"
|
||||
else
|
||||
logger -t day-specific-shutdown "Time $current_hour:$current_minute is within morning shutdown window (00:00-05:00)"
|
||||
logger -t day-specific-shutdown "Time $current_hour:$current_minute is within morning shutdown window (00:00-0${MORNING_END_HOUR}:00)"
|
||||
fi
|
||||
else
|
||||
logger -t day-specific-shutdown "Time $current_hour:$current_minute is outside shutdown window (21:00-05:00)"
|
||||
logger -t day-specific-shutdown "Time $current_hour:$current_minute is outside shutdown window (${MON_WED_HOUR}:00-0${MORNING_END_HOUR}:00)"
|
||||
fi
|
||||
else
|
||||
# Thursday (4), Friday (5), Saturday (6), Sunday (7): shutdown window 22:00-05:00
|
||||
logger -t day-specific-shutdown "Today is $day_name - checking 22:00-05:00 window"
|
||||
# Thursday (4), Friday (5), Saturday (6), Sunday (7)
|
||||
shutdown_start=$thu_sun_minutes
|
||||
logger -t day-specific-shutdown "Today is $day_name - checking ${THU_SUN_HOUR}:00-0${MORNING_END_HOUR}:00 window"
|
||||
|
||||
# Check if time is between 22:00 (1320 minutes) and 23:59 (1439 minutes)
|
||||
# OR between 00:00 (0 minutes) and 05:00 (300 minutes)
|
||||
if [[ $current_time_minutes -ge 1320 ]] || [[ $current_time_minutes -le 300 ]]; then
|
||||
if [[ $current_time_minutes -ge $shutdown_start ]] || [[ $current_time_minutes -le $morning_end_minutes ]]; then
|
||||
should_shutdown=true
|
||||
if [[ $current_time_minutes -ge 1320 ]]; then
|
||||
logger -t day-specific-shutdown "Time $current_hour:$current_minute is within evening shutdown window (22:00-23:59)"
|
||||
if [[ $current_time_minutes -ge $shutdown_start ]]; then
|
||||
logger -t day-specific-shutdown "Time $current_hour:$current_minute is within evening shutdown window (${THU_SUN_HOUR}:00-23:59)"
|
||||
else
|
||||
logger -t day-specific-shutdown "Time $current_hour:$current_minute is within morning shutdown window (00:00-05:00)"
|
||||
logger -t day-specific-shutdown "Time $current_hour:$current_minute is within morning shutdown window (00:00-0${MORNING_END_HOUR}:00)"
|
||||
fi
|
||||
else
|
||||
logger -t day-specific-shutdown "Time $current_hour:$current_minute is outside shutdown window (22:00-05:00)"
|
||||
logger -t day-specific-shutdown "Time $current_hour:$current_minute is outside shutdown window (${THU_SUN_HOUR}:00-0${MORNING_END_HOUR}:00)"
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -368,7 +809,7 @@ enable_timer() {
|
||||
# Function to install the monitor service
|
||||
install_monitor_service() {
|
||||
echo ""
|
||||
echo "6. Installing Shutdown Timer Monitor Service..."
|
||||
echo "7. Installing Shutdown Timer Monitor Service..."
|
||||
echo "=============================================="
|
||||
|
||||
local monitor_script="/usr/local/bin/shutdown-timer-monitor.sh"
|
||||
@ -533,7 +974,7 @@ EOF
|
||||
# Function to test the setup
|
||||
test_setup() {
|
||||
echo ""
|
||||
echo "7. Testing Setup..."
|
||||
echo "8. Testing Setup..."
|
||||
echo "=================="
|
||||
|
||||
echo "Service files:"
|
||||
@ -597,6 +1038,46 @@ test_setup() {
|
||||
echo "✗ Watchdog timer is not active"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Config file protection status:"
|
||||
local config_file="/etc/shutdown-schedule.conf"
|
||||
local canonical_file="/usr/local/share/locked-shutdown-schedule.conf"
|
||||
|
||||
if [[ -f "$config_file" ]]; then
|
||||
echo "✓ Config file exists"
|
||||
if lsattr "$config_file" 2>/dev/null | grep -q '^....i'; then
|
||||
echo "✓ Config file is immutable"
|
||||
else
|
||||
echo "✗ Config file is NOT immutable"
|
||||
fi
|
||||
else
|
||||
echo "✗ Config file missing"
|
||||
fi
|
||||
|
||||
if [[ -f "$canonical_file" ]]; then
|
||||
echo "✓ Canonical copy exists"
|
||||
else
|
||||
echo "✗ Canonical copy missing"
|
||||
fi
|
||||
|
||||
if systemctl is-enabled shutdown-schedule-guard.path &>/dev/null; then
|
||||
echo "✓ Config guard path watcher is enabled"
|
||||
else
|
||||
echo "✗ Config guard path watcher is not enabled"
|
||||
fi
|
||||
|
||||
if systemctl is-active shutdown-schedule-guard.path &>/dev/null; then
|
||||
echo "✓ Config guard path watcher is active"
|
||||
else
|
||||
echo "✗ Config guard path watcher is not active"
|
||||
fi
|
||||
|
||||
if [[ -f "/usr/local/sbin/unlock-shutdown-schedule" ]]; then
|
||||
echo "✓ Unlock script exists"
|
||||
else
|
||||
echo "✗ Unlock script missing"
|
||||
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"
|
||||
@ -604,9 +1085,23 @@ test_setup() {
|
||||
|
||||
# Display the shutdown schedule (used in multiple places)
|
||||
print_shutdown_schedule() {
|
||||
# Convert 24h to 12h format for display
|
||||
local mon_wed_12h thu_sun_12h morning_12h
|
||||
if [[ $SCHEDULE_MON_WED_HOUR -gt 12 ]]; then
|
||||
mon_wed_12h="$((SCHEDULE_MON_WED_HOUR - 12)):00 PM"
|
||||
else
|
||||
mon_wed_12h="${SCHEDULE_MON_WED_HOUR}:00 AM"
|
||||
fi
|
||||
if [[ $SCHEDULE_THU_SUN_HOUR -gt 12 ]]; then
|
||||
thu_sun_12h="$((SCHEDULE_THU_SUN_HOUR - 12)):00 PM"
|
||||
else
|
||||
thu_sun_12h="${SCHEDULE_THU_SUN_HOUR}:00 AM"
|
||||
fi
|
||||
morning_12h="${SCHEDULE_MORNING_END_HOUR}:00 AM"
|
||||
|
||||
echo "Shutdown Schedule:"
|
||||
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 " Monday-Wednesday: ${SCHEDULE_MON_WED_HOUR}:00-0${SCHEDULE_MORNING_END_HOUR}:00 (${mon_wed_12h} to ${morning_12h})"
|
||||
echo " Thursday-Sunday: ${SCHEDULE_THU_SUN_HOUR}:00-0${SCHEDULE_MORNING_END_HOUR}:00 (${thu_sun_12h} to ${morning_12h})"
|
||||
}
|
||||
|
||||
# Function to show final instructions
|
||||
@ -623,6 +1118,7 @@ show_instructions() {
|
||||
echo "✓ Timer enabled and started"
|
||||
echo "✓ Monitor service installed (protects timer from being disabled)"
|
||||
echo "✓ Watchdog timer installed (restarts monitor if stopped)"
|
||||
echo "✓ Config file protected (immutable + path watcher + canonical copy)"
|
||||
echo ""
|
||||
print_shutdown_schedule
|
||||
echo ""
|
||||
@ -630,12 +1126,19 @@ show_instructions() {
|
||||
echo " sudo day-specific-shutdown-manager.sh status - Check status"
|
||||
echo " sudo day-specific-shutdown-manager.sh logs - View shutdown logs"
|
||||
echo ""
|
||||
echo "To modify shutdown hours (with psychological friction):"
|
||||
echo " sudo /usr/local/sbin/unlock-shutdown-schedule"
|
||||
echo ""
|
||||
echo "How it works:"
|
||||
echo "• Timer checks every 30 minutes during potential shutdown windows"
|
||||
echo "• Smart logic determines shutdown eligibility based on day and time"
|
||||
echo "• Monitor service watches the timer and re-enables it if disabled"
|
||||
echo "• Watchdog timer restarts the monitor every 60 seconds if stopped"
|
||||
echo "• Monitor has RefuseManualStop=true to prevent easy stopping"
|
||||
echo "• Config file is protected by:"
|
||||
echo " - Immutable attribute (chattr +i)"
|
||||
echo " - Canonical copy at /usr/local/share/locked-shutdown-schedule.conf"
|
||||
echo " - Path watcher that auto-restores if you modify the file"
|
||||
echo "• There is NO disable option - this is intentional for digital wellbeing"
|
||||
echo ""
|
||||
echo "WARNING: This will automatically shutdown your PC during designated hours."
|
||||
@ -683,9 +1186,18 @@ enable_midnight_shutdown() {
|
||||
echo "Target user: $ACTUAL_USER"
|
||||
echo "User home: $USER_HOME"
|
||||
|
||||
# Check if trying to cheat by making schedule more lenient
|
||||
check_schedule_protection
|
||||
|
||||
# Confirm setup
|
||||
confirm_setup
|
||||
|
||||
# Create config file (shared with i3blocks countdown script)
|
||||
create_shutdown_config
|
||||
|
||||
# Create config guard (path watcher, enforcement, unlock script)
|
||||
create_config_guard
|
||||
|
||||
# Create systemd files
|
||||
create_shutdown_service
|
||||
create_shutdown_timer
|
||||
|
||||
377
scripts/fixes/fix_thorium.sh
Executable file
377
scripts/fixes/fix_thorium.sh
Executable file
@ -0,0 +1,377 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Fix Thorium Browser crashes and startup issues
|
||||
#
|
||||
# Common causes addressed:
|
||||
# - Corrupted Local State file (most common)
|
||||
# - Stale singleton lock files
|
||||
# - Corrupted GPU/shader cache
|
||||
# - Profile database corruption
|
||||
#
|
||||
# Usage:
|
||||
# ./fix_thorium.sh # Auto-fix common issues
|
||||
# ./fix_thorium.sh --aggressive # Also clear more caches (may lose some settings)
|
||||
# ./fix_thorium.sh --test # Test if Thorium starts after fix
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
||||
# shellcheck source=../lib/common.sh
|
||||
source "$SCRIPT_DIR/../lib/common.sh"
|
||||
|
||||
# Configuration
|
||||
THORIUM_CONFIG_DIR="${HOME}/.config/thorium"
|
||||
BACKUP_SUFFIX=".bak.$(date +%Y%m%d_%H%M%S)"
|
||||
AGGRESSIVE=false
|
||||
TEST_AFTER=false
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
fix_thorium.sh - Fix Thorium Browser crashes and startup issues
|
||||
|
||||
Usage: $(basename "$0") [OPTIONS]
|
||||
|
||||
Options:
|
||||
--aggressive Clear additional caches (IndexedDB, Service Worker, etc.)
|
||||
May cause loss of some site data but more thorough fix
|
||||
--test Test if Thorium starts successfully after applying fixes
|
||||
--dry-run Show what would be done without making changes
|
||||
-h, --help Show this help message
|
||||
|
||||
Common issues fixed:
|
||||
- Corrupted 'Local State' file (causes immediate segfault)
|
||||
- Stale singleton lock files (prevents startup)
|
||||
- Corrupted GPU/shader cache
|
||||
- Crashpad errors
|
||||
|
||||
Examples:
|
||||
$(basename "$0") # Apply standard fixes
|
||||
$(basename "$0") --test # Fix and verify browser starts
|
||||
$(basename "$0") --aggressive # Deep clean (use if standard fix fails)
|
||||
EOF
|
||||
}
|
||||
|
||||
DRY_RUN=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--aggressive)
|
||||
AGGRESSIVE=true
|
||||
shift
|
||||
;;
|
||||
--test)
|
||||
TEST_AFTER=true
|
||||
shift
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=true
|
||||
shift
|
||||
;;
|
||||
-h | --help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown option: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Check if Thorium is installed
|
||||
check_thorium_installed() {
|
||||
if ! command -v thorium-browser &>/dev/null; then
|
||||
log_error "thorium-browser not found in PATH"
|
||||
echo -e "${YELLOW}Install with: yay -S thorium-browser-bin${NC}"
|
||||
exit 1
|
||||
fi
|
||||
log_info "Found Thorium: $(thorium-browser --version 2>/dev/null | head -1)"
|
||||
}
|
||||
|
||||
# Check if config directory exists
|
||||
check_config_exists() {
|
||||
if [[ ! -d "$THORIUM_CONFIG_DIR" ]]; then
|
||||
log_warn "Thorium config directory not found: $THORIUM_CONFIG_DIR"
|
||||
log_info "This may be a fresh install - try running thorium-browser directly"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Kill any running Thorium processes
|
||||
kill_thorium() {
|
||||
local count
|
||||
count=$(pgrep -c thorium 2>/dev/null || true)
|
||||
count=${count:-0}
|
||||
|
||||
if [[ $count -gt 0 ]]; then
|
||||
log_info "Stopping $count running Thorium process(es)..."
|
||||
if [[ $DRY_RUN == true ]]; then
|
||||
echo " [dry-run] Would kill thorium processes"
|
||||
else
|
||||
pkill -9 thorium 2>/dev/null || true
|
||||
sleep 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Backup a file/directory if it exists
|
||||
backup_if_exists() {
|
||||
local path="$1"
|
||||
local name
|
||||
name=$(basename "$path")
|
||||
|
||||
if [[ -e "$path" ]]; then
|
||||
local backup_path="${path}${BACKUP_SUFFIX}"
|
||||
if [[ $DRY_RUN == true ]]; then
|
||||
echo " [dry-run] Would backup: $name"
|
||||
else
|
||||
mv "$path" "$backup_path"
|
||||
log_ok "Backed up: $name -> $(basename "$backup_path")"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Remove file/directory if it exists
|
||||
remove_if_exists() {
|
||||
local path="$1"
|
||||
local name
|
||||
name=$(basename "$path")
|
||||
|
||||
if [[ -e "$path" ]]; then
|
||||
if [[ $DRY_RUN == true ]]; then
|
||||
echo " [dry-run] Would remove: $name"
|
||||
else
|
||||
rm -rf "$path"
|
||||
log_ok "Removed: $name"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Fix 1: Handle corrupted Local State file (most common crash cause)
|
||||
fix_local_state() {
|
||||
log_info "Checking Local State file..."
|
||||
local local_state="$THORIUM_CONFIG_DIR/Local State"
|
||||
|
||||
if [[ -f "$local_state" ]]; then
|
||||
# Check if it's valid JSON
|
||||
if ! python3 -c "import json; json.load(open('$local_state'))" 2>/dev/null; then
|
||||
log_warn "Local State file appears corrupted"
|
||||
backup_if_exists "$local_state"
|
||||
else
|
||||
# Even if valid JSON, back it up as it can still cause crashes
|
||||
log_info "Local State exists - backing up (common crash source)"
|
||||
backup_if_exists "$local_state"
|
||||
fi
|
||||
else
|
||||
log_info "No Local State file found (OK for fresh install)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Fix 2: Clear singleton lock files
|
||||
fix_singleton_locks() {
|
||||
log_info "Clearing singleton lock files..."
|
||||
local locks=(
|
||||
"$THORIUM_CONFIG_DIR/SingletonLock"
|
||||
"$THORIUM_CONFIG_DIR/SingletonSocket"
|
||||
"$THORIUM_CONFIG_DIR/SingletonCookie"
|
||||
)
|
||||
|
||||
local cleared=0
|
||||
for lock in "${locks[@]}"; do
|
||||
if remove_if_exists "$lock"; then
|
||||
((cleared++)) || true
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $cleared -eq 0 ]]; then
|
||||
log_info "No stale lock files found"
|
||||
fi
|
||||
}
|
||||
|
||||
# Fix 3: Clear GPU cache
|
||||
fix_gpu_cache() {
|
||||
log_info "Clearing GPU cache..."
|
||||
local gpu_paths=(
|
||||
"$THORIUM_CONFIG_DIR/GPUCache"
|
||||
"$THORIUM_CONFIG_DIR/Default/GPUCache"
|
||||
"$THORIUM_CONFIG_DIR/ShaderCache"
|
||||
"$THORIUM_CONFIG_DIR/Default/ShaderCache"
|
||||
)
|
||||
|
||||
local cleared=0
|
||||
for cache in "${gpu_paths[@]}"; do
|
||||
if remove_if_exists "$cache"; then
|
||||
((cleared++)) || true
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $cleared -eq 0 ]]; then
|
||||
log_info "No GPU cache to clear"
|
||||
fi
|
||||
}
|
||||
|
||||
# Fix 4: Clear crash reports (can accumulate and cause issues)
|
||||
fix_crash_reports() {
|
||||
log_info "Clearing old crash reports..."
|
||||
local crash_dir="$THORIUM_CONFIG_DIR/Crash Reports"
|
||||
|
||||
if [[ -d "$crash_dir" ]]; then
|
||||
local crash_count
|
||||
crash_count=$(find "$crash_dir" -type f 2>/dev/null | wc -l)
|
||||
if [[ $crash_count -gt 0 ]]; then
|
||||
if [[ $DRY_RUN == true ]]; then
|
||||
echo " [dry-run] Would clear $crash_count crash report(s)"
|
||||
else
|
||||
rm -rf "$crash_dir"
|
||||
log_ok "Cleared $crash_count crash report(s)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Fix 5: Aggressive cleaning (optional)
|
||||
fix_aggressive() {
|
||||
if [[ $AGGRESSIVE != true ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
log_warn "Applying aggressive fixes (may lose some site data)..."
|
||||
|
||||
local aggressive_paths=(
|
||||
"$THORIUM_CONFIG_DIR/Default/Service Worker"
|
||||
"$THORIUM_CONFIG_DIR/Default/Cache"
|
||||
"$THORIUM_CONFIG_DIR/Default/Code Cache"
|
||||
"$THORIUM_CONFIG_DIR/Default/IndexedDB"
|
||||
"$THORIUM_CONFIG_DIR/BrowserMetrics"
|
||||
"$THORIUM_CONFIG_DIR/component_crx_cache"
|
||||
)
|
||||
|
||||
for path in "${aggressive_paths[@]}"; do
|
||||
remove_if_exists "$path"
|
||||
done
|
||||
|
||||
# Backup potentially corrupted databases
|
||||
local db_files=(
|
||||
"$THORIUM_CONFIG_DIR/Default/Web Data"
|
||||
"$THORIUM_CONFIG_DIR/Default/History"
|
||||
)
|
||||
|
||||
for db in "${db_files[@]}"; do
|
||||
if [[ -f "$db" ]]; then
|
||||
log_info "Checking database: $(basename "$db")"
|
||||
# Simple corruption check - if sqlite3 can't open it, back it up
|
||||
if command -v sqlite3 &>/dev/null; then
|
||||
if ! sqlite3 "$db" "PRAGMA integrity_check;" &>/dev/null; then
|
||||
log_warn "Database may be corrupted: $(basename "$db")"
|
||||
backup_if_exists "$db"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Test if Thorium starts successfully
|
||||
test_thorium() {
|
||||
if [[ $TEST_AFTER != true ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
log_info "Testing Thorium startup..."
|
||||
|
||||
if [[ $DRY_RUN == true ]]; then
|
||||
echo " [dry-run] Would test thorium-browser startup"
|
||||
return
|
||||
fi
|
||||
|
||||
# Start Thorium in background
|
||||
thorium-browser &>/dev/null &
|
||||
local pid=$!
|
||||
|
||||
# Wait a few seconds and check if it's still running
|
||||
sleep 4
|
||||
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
log_ok "Thorium started successfully! (PID: $pid)"
|
||||
echo -e "${GREEN}Fix successful!${NC} Thorium is now running."
|
||||
|
||||
# Offer to keep it running or kill it
|
||||
read -r -p "Keep browser running? [Y/n] " response
|
||||
case "$response" in
|
||||
[nN]*)
|
||||
kill "$pid" 2>/dev/null || true
|
||||
log_info "Browser closed"
|
||||
;;
|
||||
*)
|
||||
log_info "Browser left running"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
log_error "Thorium still crashing after fixes"
|
||||
echo -e "${RED}Standard fixes did not resolve the issue.${NC}"
|
||||
echo ""
|
||||
echo "Try these additional steps:"
|
||||
echo " 1. Run with --aggressive flag for deeper cleaning"
|
||||
echo " 2. Test with fresh profile: thorium-browser --user-data-dir=/tmp/thorium-test"
|
||||
echo " 3. Reinstall: yay -S thorium-browser-bin"
|
||||
echo " 4. Check NVIDIA drivers: nvidia-smi"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
echo "========================================"
|
||||
echo " Thorium Browser Fix Script"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
if [[ $DRY_RUN == true ]]; then
|
||||
echo -e "${YELLOW}[DRY RUN MODE - no changes will be made]${NC}"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
check_thorium_installed
|
||||
check_config_exists
|
||||
|
||||
echo ""
|
||||
log_info "Applying fixes to: $THORIUM_CONFIG_DIR"
|
||||
echo ""
|
||||
|
||||
kill_thorium
|
||||
fix_local_state
|
||||
fix_singleton_locks
|
||||
fix_gpu_cache
|
||||
fix_crash_reports
|
||||
fix_aggressive
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
log_ok "Fixes applied!"
|
||||
echo "========================================"
|
||||
|
||||
if [[ $DRY_RUN != true ]]; then
|
||||
echo ""
|
||||
echo "Backups created with suffix: $BACKUP_SUFFIX"
|
||||
echo "To restore: mv ~/.config/thorium/Local\\ State${BACKUP_SUFFIX} ~/.config/thorium/Local\\ State"
|
||||
fi
|
||||
|
||||
test_thorium
|
||||
|
||||
if [[ $TEST_AFTER != true ]]; then
|
||||
echo ""
|
||||
echo "Run 'thorium-browser' to test, or use: $(basename "$0") --test"
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Loading…
Reference in New Issue
Block a user