diff --git a/linux-managements/setup.sh b/linux-managements/setup.sh index 0c71272..db30b60 100755 --- a/linux-managements/setup.sh +++ b/linux-managements/setup.sh @@ -521,6 +521,151 @@ disable_selinux() { esac } +# ─── Virtual Memory (Swap) ──────────────────────────────────────────────────── +# Read a numeric field from /proc/meminfo (value in kB). +meminfo_kb() { + local key="$1" + awk -v k="$key" '$1 == k":" { print $2; exit }' /proc/meminfo +} + +format_size_kb() { + local kb="${1:-0}" + if (( kb >= 1048576 )); then + awk -v n="$kb" 'BEGIN { printf "%.1f GiB", n / 1048576 }' + elif (( kb >= 1024 )); then + awk -v n="$kb" 'BEGIN { printf "%.0f MiB", n / 1024 }' + else + echo "${kb} KiB" + fi +} + +# Round up to the nearest 512 MiB (sensible swapfile size). +round_swap_kb() { + local kb="${1:-0}" + local unit=524288 + echo $(( (kb + unit - 1) / unit * unit )) +} + +# Recommended total swap (kB) from RAM — common server/desktop heuristics. +recommend_swap_kb() { + local ram_kb="${1:-0}" + local rec=0 + + if (( ram_kb < 2097152 )); then + rec=$(( ram_kb * 2 )) + elif (( ram_kb < 8388608 )); then + rec=$ram_kb + elif (( ram_kb < 67108864 )); then + rec=4194304 + else + rec=8388608 + fi + + round_swap_kb "$rec" +} + +setup_swap() { + step "Virtual Memory (Swap)" + + if [ ! -r /proc/meminfo ]; then + warn "Cannot read /proc/meminfo — skipping swap check" + return + fi + + local ram_kb swap_kb swap_free_kb recommended_kb deficit_kb add_kb + ram_kb="$(meminfo_kb MemTotal)" + swap_kb="$(meminfo_kb SwapTotal)" + swap_free_kb="$(meminfo_kb SwapFree)" + recommended_kb="$(recommend_swap_kb "$ram_kb")" + + info "Physical memory (RAM): $(format_size_kb "$ram_kb")" + info "Swap (total): $(format_size_kb "$swap_kb")" + if (( swap_kb > 0 )); then + info "Swap (free): $(format_size_kb "$swap_free_kb")" + fi + info "Recommended total swap: $(format_size_kb "$recommended_kb")" + + if [ -r /proc/sys/vm/swappiness ]; then + info "Swappiness: $(cat /proc/sys/vm/swappiness)" + fi + + if swapon --show=NAME 2>/dev/null | grep -q .; then + info "Active swap devices:" + swapon --show=NAME,TYPE,SIZE,USED,PRIO 2>/dev/null | while IFS= read -r line; do + echo " $line" + done + fi + + # Within ~5% of recommendation counts as adequate. + local threshold_kb=$(( recommended_kb * 95 / 100 )) + if (( swap_kb >= threshold_kb )); then + success "Swap is adequate (current ≥ recommended)" + return + fi + + deficit_kb=$(( recommended_kb - swap_kb )) + add_kb="$(round_swap_kb "$deficit_kb")" + if (( add_kb < 524288 )); then + add_kb=524288 + fi + + warn "Swap is below recommended — consider increasing virtual memory" + echo -e " Suggested ${BOLD}additional${NC} swap: $(format_size_kb "$add_kb")" + echo -e " (would bring total swap to about $(format_size_kb "$(( swap_kb + add_kb ))"))" + + prompt_read ans "Create a swap file now? [y/N] " + case "$ans" in + [Yy]*) + create_swapfile "$add_kb" + ;; + *) + info "Skipping swap creation — you can add swap manually later" + ;; + esac +} + +create_swapfile() { + local add_kb="${1:?swap size in kB required}" + local swapfile="/swapfile" + + if [ -f "$swapfile" ]; then + if swapon --show=NAME 2>/dev/null | grep -qF "$swapfile"; then + warn "$swapfile is already active — not creating a second file" + return + fi + warn "$swapfile exists but is not active — remove or enable it manually before re-running" + return 1 + fi + + local size_human + size_human="$(format_size_kb "$add_kb")" + info "Creating ${size_human} swap file at ${swapfile} ..." + + local size_bytes=$(( add_kb * 1024 )) + if psudo fallocate -l "$size_bytes" "$swapfile" 2>/dev/null; then + success "Allocated swap file with fallocate" + else + warn "fallocate failed — falling back to dd (this may take a while)" + local count_mib=$(( add_kb / 1024 )) + if ! psudo dd if=/dev/zero of="$swapfile" bs=1M count="$count_mib" status=progress 2>/dev/null; then + psudo dd if=/dev/zero of="$swapfile" bs=1M count="$count_mib" + fi + fi + + psudo chmod 600 "$swapfile" + psudo mkswap "$swapfile" >/dev/null + psudo swapon "$swapfile" + + if ! psudo grep -qF "$swapfile" /etc/fstab 2>/dev/null; then + echo "$swapfile none swap sw 0 0" | psudo tee -a /etc/fstab > /dev/null + success "Persisted swap in /etc/fstab" + fi + + local new_swap_kb + new_swap_kb="$(meminfo_kb SwapTotal)" + success "Swap enabled — total swap is now $(format_size_kb "$new_swap_kb")" +} + # ─── Sudo Privilege Check ───────────────────────────────────────────────────── ensure_sudo() { step "Sudo Privilege Check" @@ -618,6 +763,7 @@ main() { set_hostname disable_selinux + setup_swap setup_proxy setup_ssh_key