Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env bash
- set -euo pipefail
- # -----------------------------------------------------------------------------
- # disable-lid-sleep-proxmox.sh
- #
- # Purpose:
- # Configure a Proxmox/Debian host (especially laptops) to ignore the lid switch
- # and prevent any suspend/hibernate when the lid is closed.
- #
- # What it does:
- # 1) Configures systemd-logind to ignore lid close events
- # 2) Masks sleep/suspend/hibernate targets (hard stop)
- # 3) Disables console blanking via GRUB (consoleblank=0)
- # 4) Installs a systemd oneshot service to disable setterm blanking/powersave
- #
- # Safe features:
- # - Makes backups before editing files
- # - Idempotent: re-running won't duplicate config
- # - Verifies systemd + grub tools exist
- #
- # Usage:
- # sudo ./disable-lid-sleep-proxmox.sh
- #
- # Optional:
- # sudo ./disable-lid-sleep-proxmox.sh --undo
- # -----------------------------------------------------------------------------
- SCRIPT_NAME="$(basename "$0")"
- STAMP="$(date +%Y%m%d-%H%M%S)"
- require_root() {
- if [[ "${EUID}" -ne 0 ]]; then
- echo "ERROR: Must be run as root. Use: sudo ./${SCRIPT_NAME}"
- exit 1
- fi
- }
- has_cmd() { command -v "$1" >/dev/null 2>&1; }
- backup_file() {
- local f="$1"
- if [[ -f "$f" ]]; then
- cp -a "$f" "${f}.bak.${STAMP}"
- echo "Backup created: ${f}.bak.${STAMP}"
- fi
- }
- ensure_line_in_file() {
- local file="$1"
- local line="$2"
- mkdir -p "$(dirname "$file")"
- touch "$file"
- if ! grep -Fxq "$line" "$file"; then
- echo "$line" >> "$file"
- echo "Added to $file: $line"
- else
- echo "Already present in $file: $line"
- fi
- }
- set_or_replace_keyvalue() {
- # Sets key=value in a config file (logind.conf style), uncommenting if needed.
- local file="$1"
- local key="$2"
- local value="$3"
- mkdir -p "$(dirname "$file")"
- touch "$file"
- if grep -Eq "^[#[:space:]]*${key}=" "$file"; then
- sed -i -E "s|^[#[:space:]]*(${key}=).*|\1${value}|" "$file"
- echo "Set $key=$value in $file"
- else
- echo "${key}=${value}" >> "$file"
- echo "Appended $key=$value to $file"
- fi
- }
- mask_sleep_targets() {
- local targets=(
- sleep.target
- suspend.target
- hibernate.target
- hybrid-sleep.target
- )
- for t in "${targets[@]}"; do
- systemctl mask "$t" >/dev/null 2>&1 || true
- echo "Masked: $t"
- done
- }
- unmask_sleep_targets() {
- local targets=(
- sleep.target
- suspend.target
- hibernate.target
- hybrid-sleep.target
- )
- for t in "${targets[@]}"; do
- systemctl unmask "$t" >/dev/null 2>&1 || true
- echo "Unmasked: $t"
- done
- }
- install_dpms_service() {
- local svc="/etc/systemd/system/disable-dpms.service"
- backup_file "$svc"
- cat > "$svc" <<'EOF'
- [Unit]
- Description=Disable monitor sleep / console blanking on boot
- [Service]
- Type=oneshot
- ExecStart=/usr/bin/setterm -blank 0 -powersave off -powerdown 0
- [Install]
- WantedBy=multi-user.target
- EOF
- systemctl daemon-reload
- systemctl enable --now disable-dpms.service
- echo "Installed & enabled: disable-dpms.service"
- }
- remove_dpms_service() {
- local svc="/etc/systemd/system/disable-dpms.service"
- if [[ -f "$svc" ]]; then
- systemctl disable --now disable-dpms.service >/dev/null 2>&1 || true
- rm -f "$svc"
- systemctl daemon-reload
- echo "Removed: disable-dpms.service"
- else
- echo "disable-dpms.service not found; skipping."
- fi
- }
- configure_logind() {
- local f="/etc/systemd/logind.conf"
- backup_file "$f"
- set_or_replace_keyvalue "$f" "HandleLidSwitch" "ignore"
- set_or_replace_keyvalue "$f" "HandleLidSwitchExternalPower" "ignore"
- set_or_replace_keyvalue "$f" "HandleLidSwitchDocked" "ignore"
- set_or_replace_keyvalue "$f" "LidSwitchIgnoreInhibited" "no"
- systemctl restart systemd-logind
- echo "Restarted: systemd-logind"
- }
- undo_logind() {
- # We don't "restore defaults" perfectly (depends on distro), but we do remove
- # the explicit settings by commenting them out if present.
- local f="/etc/systemd/logind.conf"
- if [[ -f "$f" ]]; then
- backup_file "$f"
- sed -i -E \
- -e 's|^(HandleLidSwitch=)|#\1|' \
- -e 's|^(HandleLidSwitchExternalPower=)|#\1|' \
- -e 's|^(HandleLidSwitchDocked=)|#\1|' \
- -e 's|^(LidSwitchIgnoreInhibited=)|#\1|' \
- "$f"
- systemctl restart systemd-logind
- echo "Commented out lid settings in $f and restarted logind."
- else
- echo "$f not found; skipping."
- fi
- }
- configure_grub_consoleblank() {
- if ! has_cmd update-grub && ! has_cmd grub-mkconfig; then
- echo "WARNING: Neither update-grub nor grub-mkconfig found; skipping GRUB step."
- return 0
- fi
- local f="/etc/default/grub.d/nolidsleep.cfg"
- mkdir -p /etc/default/grub.d
- backup_file "$f"
- # Ensure the commandline includes consoleblank=0 without duplicating.
- if [[ -f "$f" ]] && grep -q 'consoleblank=0' "$f"; then
- echo "GRUB consoleblank already configured in $f"
- else
- cat > "$f" <<'EOF'
- # Keep the local console from blanking (useful on laptop Proxmox installs)
- GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT consoleblank=0"
- EOF
- echo "Wrote GRUB config snippet: $f"
- fi
- if has_cmd update-grub; then
- update-grub
- echo "Ran: update-grub"
- else
- # Fallback (uncommon on Debian/Proxmox, but harmless)
- grub-mkconfig -o /boot/grub/grub.cfg
- echo "Ran: grub-mkconfig -o /boot/grub/grub.cfg"
- fi
- }
- undo_grub_consoleblank() {
- local f="/etc/default/grub.d/nolidsleep.cfg"
- if [[ -f "$f" ]]; then
- backup_file "$f"
- rm -f "$f"
- echo "Removed: $f"
- if has_cmd update-grub; then
- update-grub
- echo "Ran: update-grub"
- elif has_cmd grub-mkconfig; then
- grub-mkconfig -o /boot/grub/grub.cfg
- echo "Ran: grub-mkconfig -o /boot/grub/grub.cfg"
- else
- echo "WARNING: No grub update tool found; GRUB not regenerated."
- fi
- else
- echo "$f not found; skipping."
- fi
- }
- show_status() {
- echo
- echo "---- STATUS CHECKS ----"
- echo "logind.conf lid settings:"
- grep -E '^(#\s*)?(HandleLidSwitch|HandleLidSwitchExternalPower|HandleLidSwitchDocked|LidSwitchIgnoreInhibited)=' \
- /etc/systemd/logind.conf 2>/dev/null || echo "(no matching lines found)"
- echo
- echo "Masked sleep targets:"
- for t in sleep.target suspend.target hibernate.target hybrid-sleep.target; do
- systemctl is-enabled "$t" 2>/dev/null || true
- done
- echo
- echo "DPMS service:"
- systemctl status disable-dpms.service --no-pager -l 2>/dev/null || echo "(service not installed)"
- echo
- echo "GRUB snippet:"
- if [[ -f /etc/default/grub.d/nolidsleep.cfg ]]; then
- cat /etc/default/grub.d/nolidsleep.cfg
- else
- echo "(not present)"
- fi
- echo "-----------------------"
- echo
- }
- main() {
- require_root
- local mode="apply"
- if [[ "${1:-}" == "--undo" ]]; then
- mode="undo"
- fi
- if [[ "$mode" == "apply" ]]; then
- echo "Applying lid-close ignore + anti-sleep configuration..."
- configure_logind
- mask_sleep_targets
- configure_grub_consoleblank
- install_dpms_service
- show_status
- echo "DONE. Reboot recommended to ensure GRUB consoleblank=0 takes effect:"
- echo " reboot"
- else
- echo "Undoing configuration..."
- undo_logind
- unmask_sleep_targets
- undo_grub_consoleblank
- remove_dpms_service
- show_status
- echo "DONE. Reboot recommended:"
- echo " reboot"
- fi
- }
- main "$@"
Advertisement