Files
linux-scripts/create_swap.sh
T
chiefgeek a1a17e81a1 Sync all scripts from website downloads — 352 scripts total
Includes updated JS challenge scripts with Claude-User whitelist,
same-site referer bypass, Blackbox-Exporter allowed bot, and all
new exporters, cheat sheets, and automation scripts.
2026-05-25 03:31:08 +02:00

304 lines
9.3 KiB
Bash

#!/bin/bash
##############################################
#### Create Swap for all Linux Servers ####
#### ####
#### Author: Phil Connor ####
#### Contact: pconnor@ara.com ####
#### Version 3.51.20250729 ####
#### ####
#### Created 06/01/2023 ####
##############################################
# v3.51 changes:
# - Fixed: grep in pipeline crashes under set -euo pipefail when no matches found. Added || true guard
##############################################
# Exit on any error, undefined variables, and pipe failures
set -euo pipefail
# Script configuration constants
readonly SCRIPT_NAME="$(basename "$0")"
readonly SWAPFILE_PATH="/.swapfile" # Standard location for swap file
readonly SWAPPINESS_VALUE=80 # How aggressively to use swap (0-100)
# Logging function - outputs to stderr with script name prefix
log() {
echo "[$SCRIPT_NAME] $*" >&2
}
# Error function - logs error message and exits with status 1
error() {
log "ERROR: $*"
exit 1
}
# Display usage information
usage() {
cat <<EOF
Usage: $SCRIPT_NAME [-h|--help]
Creates and configures a swap file sized 1:1 with system RAM.
Handles creation, resizing, and removal of existing swap files.
Options:
-h, --help Show this help message and exit
Must be run as root.
EOF
exit 0
}
# Clean up partial swap file on unexpected failure
cleanup_on_error() {
log "Error detected, cleaning up partial swap file"
swapoff "$SWAPFILE_PATH" 2>/dev/null || true
rm -f "$SWAPFILE_PATH"
}
# Detect the operating system distribution (ubuntu, centos, etc.)
detect_os() {
if command -v lsb_release >/dev/null 2>&1; then
# Use lsb_release if available (most reliable)
lsb_release -i | awk '{print $3}' | tr '[:upper:]' '[:lower:]'
else
# Fallback to parsing /etc/os-release
# shellcheck source=/dev/null
. /etc/os-release 2>/dev/null && echo "${ID:-unknown}" | tr '[:upper:]' '[:lower:]'
fi
}
# Get total system memory in GB, rounded to nearest whole number
get_memory_gb() {
local mem_kb
# Extract memory from /proc/meminfo (in KB)
mem_kb=$({ grep MemTotal /proc/meminfo || true; } | awk '{print $2}')
if [[ -z "$mem_kb" || "$mem_kb" -eq 0 ]]; then
error "Unable to determine system memory"
fi
local mem_gb
# Convert KB to GB and round to nearest whole number
mem_gb=$(awk "BEGIN {printf \"%.0f\", ($mem_kb/1024/1024)}")
# Ensure minimum of 1GB to avoid division by zero issues
[[ "$mem_gb" -eq 0 ]] && mem_gb=1
echo "$mem_gb"
}
# Calculate swap size needed in MB (1:1 ratio with RAM)
get_swap_needed_mb() {
local mem_gb="$1"
echo $((mem_gb * 1024))
}
# Get the current swap file size in MB, or 0 if no swap file exists
get_current_swap_size() {
if [[ -f "$SWAPFILE_PATH" ]]; then
local size_bytes
size_bytes=$(stat -c%s "$SWAPFILE_PATH" 2>/dev/null || echo 0)
echo $((size_bytes / 1024 / 1024))
else
echo 0
fi
}
# Check if our swap file is currently active
is_swap_active() {
swapon --show=NAME --noheadings 2>/dev/null | grep -q "^${SWAPFILE_PATH}$"
}
# Check if there's enough disk space for the swap file (with 10% buffer)
check_disk_space() {
local needed_mb="$1"
local filesystem="/"
log "Checking available disk space for ${needed_mb}MB swap file"
local available_kb
# Get available space in KB from df command
available_kb=$(df --output=avail "$filesystem" | tail -n 1)
local available_mb=$((available_kb / 1024))
# Add 10% buffer for safety
local required_mb=$((needed_mb + (needed_mb / 10)))
if [[ "$available_mb" -lt "$required_mb" ]]; then
error "Insufficient disk space. Need ${required_mb}MB (${needed_mb}MB + 10% buffer), but only ${available_mb}MB available on $filesystem"
fi
log "Disk space check passed: ${available_mb}MB available, ${required_mb}MB required"
}
# Verify script is running with root privileges
check_permissions() {
if [[ $EUID -ne 0 ]]; then
error "This script must be run as root! Login as root, or use sudo."
fi
}
# Configure system swappiness (how aggressively to use swap)
setup_swappiness() {
local sysconf="/etc/sysctl.conf"
local procswap="/proc/sys/vm/swappiness"
log "Configuring swappiness to $SWAPPINESS_VALUE"
# If no swappiness setting exists, add it
if ! grep -q "vm.swappiness" "$sysconf"; then
echo "$SWAPPINESS_VALUE" > "$procswap"
echo "vm.swappiness = $SWAPPINESS_VALUE" >> "$sysconf"
# If setting exists but with different value, update it
elif ! grep -q "vm.swappiness = $SWAPPINESS_VALUE" "$sysconf"; then
sed -i "/vm.swappiness/d" "$sysconf"
echo "$SWAPPINESS_VALUE" > "$procswap"
echo "vm.swappiness = $SWAPPINESS_VALUE" >> "$sysconf"
fi
}
# Set up automated cache clearing cron job (every 5 minutes)
setup_cache_clearing() {
local os="$1"
local ctab
# Different crontab locations for different distributions
if [[ "$os" == "ubuntu" ]]; then
ctab="/var/spool/cron/crontabs/root"
else
ctab="/var/spool/cron/root"
fi
log "Setting up cache clearing cron job"
# Remove any existing cache clearing jobs that use 'echo 3' (more aggressive)
if crontab -l 2>/dev/null | grep -q '/usr/bin/sync; echo 3'; then
sed -i "/\/usr\/bin\/sync.*echo 3/d" "$ctab" 2>/dev/null || true
fi
# Add cache clearing job if it doesn't exist (echo 1 = page cache only)
if ! crontab -l 2>/dev/null | grep -q '/usr/bin/sync; echo 1'; then
(crontab -u root -l 2>/dev/null; echo "*/5 * * * * /usr/bin/sync; echo 1 > /proc/sys/vm/drop_caches") | crontab -u root -
fi
}
# Remove existing swap file and clean up fstab entries
remove_swap() {
local backup_time
# Create timestamp for backup file
backup_time=$(date +%y-%m-%d--%H-%M-%S)
log "Removing existing swap file: $SWAPFILE_PATH"
# Disable swap file (ignore errors if already disabled)
swapoff "$SWAPFILE_PATH" 2>/dev/null || true
# Backup fstab before modifying
cp /etc/fstab "/etc/fstab.$backup_time"
# Remove swap entries from fstab
sed -i "\|${SWAPFILE_PATH}|d" /etc/fstab
# Delete the swap file
rm -f "$SWAPFILE_PATH"
}
# Create and configure a new swap file
create_swap() {
local swap_mb="$1"
if [[ "$swap_mb" -eq 0 ]]; then
error "Cannot create swap: swap size cannot be 0 MB"
fi
log "Creating swap file of size ${swap_mb}MB at $SWAPFILE_PATH"
# Set trap to clean up partial swap file on failure
trap cleanup_on_error ERR
# Create swap file using dd with progress display (oflag=direct avoids polluting page cache)
dd if=/dev/zero of="$SWAPFILE_PATH" bs=1M count="$swap_mb" oflag=direct status=progress
# Set proper permissions (only root can read/write)
chmod 600 "$SWAPFILE_PATH"
# Format the file as swap space
mkswap "$SWAPFILE_PATH"
# Enable the swap file
swapon "$SWAPFILE_PATH"
# Add to fstab for persistent mounting if not already present
if ! grep -q "$SWAPFILE_PATH" /etc/fstab; then
echo "$SWAPFILE_PATH swap swap defaults 0 0" >> /etc/fstab
fi
# Clear the error trap now that swap is fully created
trap - ERR
log "Swap file created and enabled successfully"
}
# Main function - orchestrates the entire swap setup process
main() {
# Handle --help flag
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
fi
# Ensure script is run with root privileges
check_permissions
# Detect operating system for distribution-specific configurations
local os
os=$(detect_os)
# Get system memory information
local mem_gb
mem_gb=$(get_memory_gb)
# Calculate required swap size
local needed_mb
needed_mb=$(get_swap_needed_mb "$mem_gb")
# Check current swap configuration
local current_size
current_size=$(get_current_swap_size)
# Configure system settings
setup_swappiness
setup_cache_clearing "$os"
# If swap file exists at the correct size and is active, nothing to do
if [[ "$current_size" -eq "$needed_mb" ]] && is_swap_active; then
log "Swap size is already correct and active"
log "Swap setup completed successfully"
return 0
fi
# If swap file exists but wrong size, remove first so disk space check is accurate
if [[ "$current_size" -ne 0 && "$needed_mb" -ne "$current_size" ]]; then
remove_swap
fi
# Verify system has enough disk space (after potential removal)
if [[ "$needed_mb" -ne "$current_size" ]]; then
check_disk_space "$needed_mb"
create_swap "$needed_mb"
else
# File is the right size but not active, re-enable it
log "Swap file exists at correct size but is not active, enabling"
chmod 600 "$SWAPFILE_PATH"
mkswap "$SWAPFILE_PATH"
swapon "$SWAPFILE_PATH"
if ! grep -q "$SWAPFILE_PATH" /etc/fstab; then
echo "$SWAPFILE_PATH swap swap defaults 0 0" >> /etc/fstab
fi
fi
log "Swap setup completed successfully"
}
# Execute main function with all script arguments
main "$@"