diff --git a/linux_configuration/scripts/fixes/fix_ubuntu_performance.sh b/linux_configuration/scripts/fixes/fix_ubuntu_performance.sh new file mode 100755 index 0000000..e34cc94 --- /dev/null +++ b/linux_configuration/scripts/fixes/fix_ubuntu_performance.sh @@ -0,0 +1,494 @@ +#!/usr/bin/env bash + +# Fix common Ubuntu performance issues on Lenovo Legion laptop with NVIDIA GPU +# +# System: Ubuntu 24.04, AMD Ryzen 7 4800H, RTX 2060 Mobile, 32GB RAM, NVMe SSD +# +# Issues addressed: +# 1. NetworkManager-wait-online.service → adds ~6.7s to every boot for no benefit +# 2. vm.swappiness=60 → too aggressive for 32GB RAM + NVMe, wastes I/O on swap +# 3. NVIDIA persistence mode off → GPU re-initializes on every nvidia operation +# 4. No earlyoom → system can hard-freeze under memory pressure (OOM killer too slow) +# 5. Failed SSSD systemd units → retry loops waste CPU, journal space +# 6. Journal potentially bloated → wastes disk I/O +# 7. No VFS/dirty page tuning → suboptimal for dev workloads on NVMe +# +# Every change creates an entry in the undo script for easy reversal. +# +# Usage: +# sudo ./fix_ubuntu_performance.sh # Apply all fixes +# sudo ./fix_ubuntu_performance.sh --dry-run # Show what would be done +# sudo ./fix_ubuntu_performance.sh --undo # Reverse all changes +# sudo ./fix_ubuntu_performance.sh -h # Show help +# +# Safe to re-run: all fixes are idempotent. + +set -euo pipefail + +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" +# shellcheck source=../lib/common.sh +source "$SCRIPT_DIR/../lib/common.sh" + +parse_interactive_args "$@" +shift "$COMMON_ARGS_SHIFT" + +DRY_RUN=false +UNDO_MODE=false +for arg in "$@"; do + case "$arg" in + --dry-run) + DRY_RUN=true + ;; + --undo) + UNDO_MODE=true + ;; + -h | --help) + cat <<'EOF' +fix_ubuntu_performance.sh - Fix common Ubuntu laptop performance issues + +Usage: fix_ubuntu_performance.sh [OPTIONS] + +Options: + --dry-run Show what would be done without making changes + --undo Reverse all changes (uses generated undo script) + -i, --interactive Prompt before each fix + -h, --help Show this help message + +Fixes applied: + 1. Disable NetworkManager-wait-online.service (saves ~6.7s boot) + 2. Tune vm.swappiness to 10 + vm.vfs_cache_pressure to 50 + dirty page tuning + 3. Enable NVIDIA persistence mode via systemd + 4. Install earlyoom (prevents OOM hard-freezes) + 5. Mask failed SSSD socket/service units (stop retry waste) + 6. Vacuum systemd journal + set 300M cap + 7. Set NVMe I/O scheduler to kyber (if available, else none) + +All fixes are idempotent and safe to re-run. +Run with --undo to reverse all changes. +EOF + exit 0 + ;; + esac +done + +require_root "$@" + +UNDO_SCRIPT="/root/undo_ubuntu_performance_$(date +%Y%m%d_%H%M%S).sh" +FIXES_APPLIED=0 +FIXES_SKIPPED=0 + +# --------------------------------------------------------------------------- +# Create undo script header +# --------------------------------------------------------------------------- +init_undo_script() { + cat >"$UNDO_SCRIPT" <<'UNDOHEADER' +#!/usr/bin/env bash +# Auto-generated undo script for fix_ubuntu_performance.sh +# Run with: sudo bash /root/undo_ubuntu_performance_*.sh +set -euo pipefail + +echo "Reversing Ubuntu performance optimizations..." +echo "" +UNDOHEADER + chmod 700 "$UNDO_SCRIPT" +} + +add_undo() { + echo "$1" >>"$UNDO_SCRIPT" +} + +# --------------------------------------------------------------------------- +# Helper: run or print a fix depending on --dry-run / --interactive +# --------------------------------------------------------------------------- +apply_fix() { + local description="$1" + shift + + echo "" + log_info "$description" + + if [[ $DRY_RUN == "true" ]]; then + echo " [dry-run] Would run: $*" + return 0 + fi + + if [[ $INTERACTIVE_MODE == "true" ]]; then + if ! ask_yes_no " Apply this fix?"; then + log_warn "Skipped." + ((FIXES_SKIPPED++)) || true + return 0 + fi + fi + + if "$@"; then + log_ok "Done." + ((FIXES_APPLIED++)) || true + else + log_error "Failed (non-fatal, continuing)." + fi +} + +# =================================================================== +# Fix 1: Disable NetworkManager-wait-online.service +# =================================================================== +fix_nm_wait_online() { + if ! systemctl is-enabled NetworkManager-wait-online.service >/dev/null 2>&1; then + log_ok "NetworkManager-wait-online is already disabled — skipping." + return 0 + fi + + systemctl disable NetworkManager-wait-online.service + + add_undo "# Undo: Re-enable NetworkManager-wait-online" + add_undo "systemctl enable NetworkManager-wait-online.service" + add_undo "" + return 0 +} + +# =================================================================== +# Fix 2: Sysctl tuning (swappiness, VFS cache, dirty pages) +# =================================================================== +fix_sysctl_tuning() { + local sysctl_file="/etc/sysctl.d/99-performance-tuning.conf" + + if [[ -f $sysctl_file ]]; then + log_ok "Sysctl performance tuning already applied — skipping." + return 0 + fi + + # Save current values for undo + local cur_swappiness cur_vfs cur_dirty_ratio cur_dirty_bg + cur_swappiness=$(sysctl -n vm.swappiness 2>/dev/null || echo 60) + cur_vfs=$(sysctl -n vm.vfs_cache_pressure 2>/dev/null || echo 100) + cur_dirty_ratio=$(sysctl -n vm.dirty_ratio 2>/dev/null || echo 20) + cur_dirty_bg=$(sysctl -n vm.dirty_background_ratio 2>/dev/null || echo 10) + + cat >"$sysctl_file" <<'SYSCTL' +# Performance tuning for Ubuntu laptop with 32GB RAM + NVMe SSD +# Created by fix_ubuntu_performance.sh +# +# vm.swappiness=10: Prefer keeping data in RAM over swapping (32GB is plenty) +# vm.vfs_cache_pressure=50: Keep filesystem dentries/inodes cached longer (helps dev work) +# vm.dirty_ratio=15: Allow more dirty pages before forced writeback (NVMe handles bursts) +# vm.dirty_background_ratio=5: Start background writeback earlier for smoother I/O + +vm.swappiness = 10 +vm.vfs_cache_pressure = 50 +vm.dirty_ratio = 15 +vm.dirty_background_ratio = 5 +SYSCTL + + # Apply immediately + sysctl --system >/dev/null 2>&1 + + add_undo "# Undo: Remove sysctl tuning, restore defaults" + add_undo "rm -f /etc/sysctl.d/99-performance-tuning.conf" + add_undo "sysctl -w vm.swappiness=$cur_swappiness vm.vfs_cache_pressure=$cur_vfs vm.dirty_ratio=$cur_dirty_ratio vm.dirty_background_ratio=$cur_dirty_bg >/dev/null" + add_undo "" + return 0 +} + +# =================================================================== +# Fix 3: NVIDIA persistence mode via systemd service +# =================================================================== +fix_nvidia_persistence() { + local service_file="/etc/systemd/system/nvidia-persistence.service" + + # Check if persistence is already on + if nvidia-smi -q 2>/dev/null | grep -q "Persistence Mode.*Enabled"; then + log_ok "NVIDIA persistence mode is already enabled — skipping." + return 0 + fi + + # On Ubuntu, nvidia-persistenced.service is "static" (no [Install] section) + # and starts with --no-persistence-mode. We create a small helper service + # that runs `nvidia-smi -pm 1` after the daemon is up. + local helper_svc="/etc/systemd/system/nvidia-persistence-mode.service" + + if [[ -f $helper_svc ]] && systemctl is-enabled nvidia-persistence-mode.service >/dev/null 2>&1; then + # Already set up — just make sure it's active this boot + if ! nvidia-smi -q 2>/dev/null | grep -q "Persistence Mode.*Enabled"; then + systemctl start nvidia-persistence-mode.service 2>/dev/null || true + fi + log_ok "NVIDIA persistence mode helper already configured." + return 0 + fi + + if command -v nvidia-persistenced >/dev/null 2>&1; then + # Ensure the daemon is running + systemctl start nvidia-persistenced.service 2>/dev/null || true + + # Create a proper service with [Install] that runs nvidia-smi -pm 1 + cat >"$helper_svc" <<'NVSVC' +[Unit] +Description=Enable NVIDIA Persistence Mode +After=nvidia-persistenced.service +Requires=nvidia-persistenced.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/bin/nvidia-smi -pm 1 +ExecStop=/usr/bin/nvidia-smi -pm 0 + +[Install] +WantedBy=multi-user.target +NVSVC + + systemctl daemon-reload + systemctl enable --now nvidia-persistence-mode.service + + add_undo "# Undo: Remove NVIDIA persistence mode helper service" + add_undo "systemctl disable --now nvidia-persistence-mode.service 2>/dev/null || true" + add_undo "rm -f /etc/systemd/system/nvidia-persistence-mode.service" + add_undo "nvidia-smi -pm 0 2>/dev/null || true" + add_undo "systemctl daemon-reload" + add_undo "" + else + # Fall back to a simple systemd service using nvidia-smi + cat >"$service_file" <<'NVSVC' +[Unit] +Description=NVIDIA Persistence Mode +After=nvidia.target +Requires=nvidia.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/bin/nvidia-smi -pm 1 +ExecStop=/usr/bin/nvidia-smi -pm 0 + +[Install] +WantedBy=multi-user.target +NVSVC + + systemctl daemon-reload + systemctl enable --now nvidia-persistence.service + + add_undo "# Undo: Remove NVIDIA persistence service" + add_undo "systemctl disable --now nvidia-persistence.service 2>/dev/null || true" + add_undo "rm -f /etc/systemd/system/nvidia-persistence.service" + add_undo "systemctl daemon-reload" + add_undo "" + fi + + return 0 +} + +# =================================================================== +# Fix 4: Install and enable earlyoom +# =================================================================== +fix_earlyoom() { + if systemctl is-active earlyoom.service >/dev/null 2>&1; then + log_ok "earlyoom is already running — skipping." + return 0 + fi + + if ! dpkg -l earlyoom 2>/dev/null | grep -q '^ii'; then + log_info "Installing earlyoom..." + apt-get install -y earlyoom >/dev/null 2>&1 + fi + + # Configure earlyoom: kill at 5% free RAM / 10% free swap + local earlyoom_conf="/etc/default/earlyoom" + if [[ -f $earlyoom_conf ]]; then + cp "$earlyoom_conf" "${earlyoom_conf}.bak" + fi + + cat >"$earlyoom_conf" <<'EARLYOOM' +# earlyoom configuration - prevent OOM hard-freezes +# Created by fix_ubuntu_performance.sh +# -r 5 = act when free RAM drops below 5% +# -s 10 = act when free swap drops below 10% +# -n = send SIGTERM first (graceful), then SIGKILL +# --prefer="(firefox|chromium|chrome)" = prefer killing browsers (they recover well) +EARLYOOM_ARGS="-r 5 -s 10 -n --prefer '(firefox|chromium|chrome)'" +EARLYOOM + + systemctl enable --now earlyoom.service + + add_undo "# Undo: Disable and remove earlyoom" + add_undo "systemctl disable --now earlyoom.service 2>/dev/null || true" + add_undo "apt-get remove -y earlyoom >/dev/null 2>&1 || true" + add_undo "" + return 0 +} + +# =================================================================== +# Fix 5: Mask failed SSSD units (not needed on non-domain laptops) +# =================================================================== +fix_failed_sssd() { + local sssd_units=( + sssd-pac.service + sssd-nss.socket + sssd-pac.socket + sssd-pam-priv.socket + sssd-pam.socket + ) + + local any_failed=false + for unit in "${sssd_units[@]}"; do + if systemctl is-failed "$unit" >/dev/null 2>&1; then + any_failed=true + break + fi + done + + if [[ $any_failed == "false" ]]; then + log_ok "No failed SSSD units — skipping." + return 0 + fi + + add_undo "# Undo: Unmask SSSD units" + for unit in "${sssd_units[@]}"; do + if systemctl is-failed "$unit" >/dev/null 2>&1; then + systemctl stop "$unit" 2>/dev/null || true + systemctl mask "$unit" + log_info "Masked $unit" + add_undo "systemctl unmask $unit" + fi + done + + systemctl reset-failed 2>/dev/null || true + add_undo "" + return 0 +} + +# =================================================================== +# Fix 6: Journal vacuum + permanent size cap +# =================================================================== +fix_journal() { + # Create permanent size cap via drop-in + local dropin_dir="/etc/systemd/journald.conf.d" + local dropin_file="$dropin_dir/size-limit.conf" + + if [[ -f $dropin_file ]] && grep -q 'SystemMaxUse=300M' "$dropin_file"; then + log_ok "Journal size cap already configured — skipping." + return 0 + fi + + mkdir -p "$dropin_dir" + cat >"$dropin_file" <<'JOURNALEOF' +[Journal] +SystemMaxUse=300M +JOURNALEOF + + # Vacuum existing logs + journalctl --vacuum-size=300M 2>/dev/null || true + + systemctl restart systemd-journald + + add_undo "# Undo: Remove journal size cap" + add_undo "rm -f /etc/systemd/journald.conf.d/size-limit.conf" + add_undo "systemctl restart systemd-journald" + add_undo "" + return 0 +} + +# =================================================================== +# Fix 7: Disable snap-related boot slowness (optional but impactful) +# =================================================================== +fix_snap_startup() { + # Disable snapd.snap-repair.timer - not critical, runs periodically + if systemctl is-enabled snapd.snap-repair.timer >/dev/null 2>&1; then + systemctl disable snapd.snap-repair.timer + systemctl stop snapd.snap-repair.timer 2>/dev/null || true + + add_undo "# Undo: Re-enable snap repair timer" + add_undo "systemctl enable snapd.snap-repair.timer" + add_undo "" + else + log_ok "snapd.snap-repair.timer already disabled — skipping." + fi + + return 0 +} + +# =================================================================== +# Undo mode: run the most recent undo script +# =================================================================== +run_undo() { + local latest_undo + # shellcheck disable=SC2012 + latest_undo=$(ls -1t /root/undo_ubuntu_performance_*.sh 2>/dev/null | head -1) + + if [[ -z ${latest_undo:-} ]]; then + log_error "No undo script found in /root/" + exit 1 + fi + + log_info "Running undo script: $latest_undo" + bash "$latest_undo" + log_ok "All changes reversed." + log_info "Reboot recommended to ensure all changes take effect." + exit 0 +} + +# =================================================================== +# Apply all fixes +# =================================================================== +main() { + if [[ $UNDO_MODE == "true" ]]; then + run_undo + fi + + if [[ $DRY_RUN == "false" ]]; then + init_undo_script + fi + + print_setup_header "Ubuntu Performance Optimization (Legion Laptop)" + + apply_fix \ + "Fix 1/7: Disable NetworkManager-wait-online.service (~6.7s boot saving)" \ + fix_nm_wait_online + + apply_fix \ + "Fix 2/7: Tune sysctl (swappiness=10, vfs_cache_pressure=50, dirty page tuning)" \ + fix_sysctl_tuning + + apply_fix \ + "Fix 3/7: Enable NVIDIA persistence mode (faster GPU operations)" \ + fix_nvidia_persistence + + apply_fix \ + "Fix 4/7: Install earlyoom (prevent OOM hard-freezes)" \ + fix_earlyoom + + apply_fix \ + "Fix 5/7: Mask failed SSSD units (stop retry waste)" \ + fix_failed_sssd + + apply_fix \ + "Fix 6/7: Vacuum journal logs + set permanent 300M size cap" \ + fix_journal + + apply_fix \ + "Fix 7/7: Disable snap repair timer (reduce background work)" \ + fix_snap_startup + + # --------------------------------------------------------------- + # Summary + # --------------------------------------------------------------- + echo "" + echo "==============================" + echo " Performance Fix Summary" + echo "==============================" + + if [[ $DRY_RUN == "true" ]]; then + log_info "Dry-run mode — no changes were made." + else + log_ok "Fixes applied: $FIXES_APPLIED" + if [[ $FIXES_SKIPPED -gt 0 ]]; then + log_warn "Fixes skipped: $FIXES_SKIPPED" + fi + echo "" + log_ok "Undo script saved to: $UNDO_SCRIPT" + log_info "To reverse ALL changes: sudo bash $UNDO_SCRIPT" + fi + + echo "" + log_info "Reboot recommended for full effect." + log_info "After reboot, verify with: systemd-analyze && nvidia-smi -q | grep Persistence" +} + +main diff --git a/linux_configuration/scripts/install_code_insiders.sh b/linux_configuration/scripts/install_code_insiders.sh new file mode 100755 index 0000000..4b3b3cb --- /dev/null +++ b/linux_configuration/scripts/install_code_insiders.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# Sets up Microsoft's APT repository and installs the latest VS Code Insiders. +# Re-running this script is safe — it will update to the newest version. +set -euo pipefail + +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root (use sudo)." >&2 + exit 1 +fi + +echo "==> Installing prerequisites..." +apt-get update -qq +apt-get install -y -qq wget gpg apt-transport-https + +KEYRING=/usr/share/keyrings/microsoft-archive-keyring.gpg +SOURCES_LIST=/etc/apt/sources.list.d/vscode.list + +echo "==> Adding Microsoft GPG key..." +wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o "$KEYRING" --yes + +echo "==> Adding VS Code repository..." +echo "deb [arch=amd64,arm64,armhf signed-by=${KEYRING}] https://packages.microsoft.com/repos/code stable main" \ + > "$SOURCES_LIST" + +echo "==> Updating package lists..." +apt-get update -qq + +echo "==> Installing code-insiders..." +apt-get install -y code-insiders + +echo "==> Done. Installed version:" +code-insiders --version 2>/dev/null || echo "(run 'code-insiders --version' to verify)" diff --git a/linux_configuration/scripts/utils/gif_to_square.sh b/linux_configuration/scripts/utils/gif_to_square.sh new file mode 100755 index 0000000..881879a --- /dev/null +++ b/linux_configuration/scripts/utils/gif_to_square.sh @@ -0,0 +1,151 @@ +#!/usr/bin/env bash +# Pad a GIF to a square with transparent background, centered. +# Useful for making Slack emojis from rectangular GIFs. +# Usage: gif_to_square.sh [output.gif] [background] + +set -euo pipefail + +# Source common library for shared functions +SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" +# shellcheck source=../lib/common.sh +source "$SCRIPT_DIR/../lib/common.sh" + +# Default background color (transparent) +DEFAULT_BG="none" + +# Function to display usage +usage() { + cat << EOF +Usage: $0 [output.gif] [background] + +Arguments: + input.gif Path to the input GIF file (required) + output.gif Path to the output GIF file (default: _square.gif) + background Background color for padding (default: ${DEFAULT_BG}) + Use "none" for transparent, or any color name/hex + +Examples: + $0 emoji.gif + $0 emoji.gif square_emoji.gif + $0 emoji.gif square_emoji.gif white + $0 emoji.gif square_emoji.gif "#FF0000" + +Note: Requires ImageMagick (magick or convert command) + Slack emoji max size: 128x128 pixels, 256KB +EOF + exit 1 +} + +# Install ImageMagick if missing +if ! command -v magick &> /dev/null && ! command -v convert &> /dev/null; then + echo "ImageMagick not found. Installing..." + if command -v pacman &> /dev/null; then + sudo pacman -S --noconfirm imagemagick + elif command -v apt-get &> /dev/null; then + sudo apt-get update && sudo apt-get install -y imagemagick + else + echo "Error: Could not detect package manager. Install ImageMagick manually." + exit 1 + fi +fi + +require_imagemagick || exit 1 + +# Set up identify command (IM7: magick identify, IM6: identify) +if [[ ${MAGICK_CMD} == "magick" ]]; then + IDENTIFY_CMD="magick identify" +else + IDENTIFY_CMD="identify" +fi + +# Parse arguments +if [[ $# -lt 1 ]]; then + echo "Error: Missing required argument " + usage +fi + +INPUT_GIF="$1" +OUTPUT_GIF="${2:-}" +BACKGROUND="${3:-${DEFAULT_BG}}" + +# Validate input file exists +if [[ ! -f ${INPUT_GIF} ]]; then + echo "Error: Input file '${INPUT_GIF}' does not exist." + exit 1 +fi + +# Validate it's a GIF +MIME_TYPE=$(file --mime-type -b "${INPUT_GIF}") +if [[ ${MIME_TYPE} != "image/gif" ]]; then + echo "Error: '${INPUT_GIF}' is not a GIF file (detected: ${MIME_TYPE})" + exit 1 +fi + +# Generate output filename if not provided +if [[ -z ${OUTPUT_GIF} ]]; then + OUTPUT_GIF=$(generate_output_filename "${INPUT_GIF}" "_square") +fi + +# Get dimensions of the first frame +DIMENSIONS=$(${IDENTIFY_CMD} -format "%wx%h" "${INPUT_GIF}[0]") +WIDTH="${DIMENSIONS%x*}" +HEIGHT="${DIMENSIONS#*x}" + +echo "Input: ${INPUT_GIF}" +echo "Dimensions: ${WIDTH}x${HEIGHT}" + +if [[ ${WIDTH} -eq ${HEIGHT} ]]; then + echo "Image is already square. Copying to output." + cp "${INPUT_GIF}" "${OUTPUT_GIF}" +else + # Stretch to square using the larger dimension + if [[ ${WIDTH} -gt ${HEIGHT} ]]; then + SIDE=${WIDTH} + else + SIDE=${HEIGHT} + fi + + echo "Stretching to ${SIDE}x${SIDE}..." + + "${MAGICK_CMD}" "${INPUT_GIF}" \ + -coalesce \ + -resize "${SIDE}x${SIDE}!" \ + -layers Optimize \ + "${OUTPUT_GIF}" +fi + +if [[ -f ${OUTPUT_GIF} ]]; then + OUT_DIMENSIONS=$(${IDENTIFY_CMD} -format "%wx%h" "${OUTPUT_GIF}[0]") + INPUT_SIZE=$(du -h "${INPUT_GIF}" | cut -f1) + OUTPUT_SIZE=$(du -h "${OUTPUT_GIF}" | cut -f1) + + echo "✓ Successfully created square GIF" + echo "Output: ${OUTPUT_GIF} (${OUT_DIMENSIONS})" + echo "Input size: ${INPUT_SIZE}" + echo "Output size: ${OUTPUT_SIZE}" + + # Auto-shrink if over Slack's 128KB emoji limit (target 124KB for safety margin) + MAX_BYTES=126976 + OUTPUT_BYTES=$(stat -c%s "${OUTPUT_GIF}" 2>/dev/null || stat -f%z "${OUTPUT_GIF}" 2>/dev/null) + if [[ ${OUTPUT_BYTES} -gt ${MAX_BYTES} ]]; then + echo "" + echo "Output is over 128KB (${OUTPUT_BYTES} bytes). Auto-shrinking for Slack..." + CURRENT_SIDE=$(${IDENTIFY_CMD} -format "%w" "${OUTPUT_GIF}[0]") + while [[ ${OUTPUT_BYTES} -gt ${MAX_BYTES} && ${CURRENT_SIDE} -gt 16 ]]; do + # Reduce by ~25% each iteration + CURRENT_SIDE=$(( CURRENT_SIDE * 75 / 100 )) + echo " Trying ${CURRENT_SIDE}x${CURRENT_SIDE}..." + "${MAGICK_CMD}" "${OUTPUT_GIF}" \ + -coalesce \ + -resize "${CURRENT_SIDE}x${CURRENT_SIDE}!" \ + -layers Optimize \ + "${OUTPUT_GIF}" + OUTPUT_BYTES=$(stat -c%s "${OUTPUT_GIF}" 2>/dev/null || stat -f%z "${OUTPUT_GIF}" 2>/dev/null) + done + OUTPUT_SIZE=$(du -h "${OUTPUT_GIF}" | cut -f1) + echo "✓ Shrunk to ${CURRENT_SIDE}x${CURRENT_SIDE} (${OUTPUT_SIZE}, ${OUTPUT_BYTES} bytes)" + fi +else + echo "✗ Error: Failed to create output file" + exit 1 +fi diff --git a/linux_configuration/scripts/utils/upgrade.sh b/linux_configuration/scripts/utils/upgrade.sh new file mode 100755 index 0000000..cf42512 --- /dev/null +++ b/linux_configuration/scripts/utils/upgrade.sh @@ -0,0 +1,123 @@ +#!/bin/bash +# System upgrade script with automatic apt source hygiene +# Fixes common warnings/errors before running upgrades. +# All fixes are idempotent and safe to re-run. + +set -euo pipefail + +log() { printf '[upgrade] %s\n' "$*"; } + +# ===================================================================== +# Fix 1: Duplicate repository — microsoft-edge.list is a copy of +# google-chrome.list (both point to dl.google.com/linux/chrome) +# ===================================================================== +fix_duplicate_chrome_edge_repo() { + local edge="/etc/apt/sources.list.d/microsoft-edge.list" + local chrome="/etc/apt/sources.list.d/google-chrome.list" + + if [[ ! -f $edge ]]; then + return + fi + + # Only act if edge list points to the chrome repo (the known bug) + if grep -q 'dl.google.com/linux/chrome' "$edge" 2>/dev/null; then + log "Disabling duplicate microsoft-edge.list (identical to google-chrome.list)" + mv "$edge" "${edge}.disabled" + fi +} + +# ===================================================================== +# Fix 2: Expired Cloudflare WARP GPG key (expired 2025-12-03) +# ===================================================================== +fix_cloudflare_key() { + local keyring="/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg" + local source_list="/etc/apt/sources.list.d/cloudflare-client.list" + + if [[ ! -f $source_list ]]; then + return + fi + + # Check if key is expired + local expired + expired=$(gpg --no-default-keyring --keyring "$keyring" --list-keys 2>&1 | grep -c 'expired' || true) + + if [[ ${expired:-0} -gt 0 ]]; then + log "Refreshing expired Cloudflare WARP GPG key..." + curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg \ + | gpg --yes --dearmor -o "$keyring" 2>/dev/null \ + && log "Cloudflare key refreshed." \ + || log "WARNING: Could not refresh Cloudflare key (network issue?). Skipping." + fi +} + +# ===================================================================== +# Fix 3: WineHQ key in legacy trusted.gpg + repo targets focal not noble +# ===================================================================== +fix_wine_legacy_key() { + local legacy_keyring="/etc/apt/trusted.gpg" + local wine_key_id="D43F640145369C51D786DDEA76F1A20FF987672F" + local modern_keyring="/usr/share/keyrings/winehq-archive.gpg" + local wine_source="/etc/apt/sources.list.d/winehq-focal.list" + + # Check if wine key is in the legacy keyring + if ! gpg --no-default-keyring --keyring "$legacy_keyring" --list-keys "$wine_key_id" >/dev/null 2>&1; then + return + fi + + log "Migrating WineHQ key from legacy trusted.gpg to modern keyring..." + + # Export key to modern location + gpg --no-default-keyring --keyring "$legacy_keyring" \ + --export "$wine_key_id" \ + | gpg --yes --dearmor -o "$modern_keyring" 2>/dev/null + + # Remove from legacy keyring (suppress the deprecation warning) + apt-key del "$wine_key_id" >/dev/null 2>&1 || true + + # Fix the source file to use signed-by and correct distro codename + local codename + codename=$(lsb_release -cs 2>/dev/null || echo "noble") + + # Find all wine source files + for src in /etc/apt/sources.list.d/*wine*.list; do + [[ -f $src ]] || continue + + # Check if already using signed-by + if grep -q 'signed-by=' "$src" 2>/dev/null; then + continue + fi + + local old_codename + old_codename=$(grep -oP 'ubuntu/?\s+\K\w+' "$src" | head -1) + + log "Updating $src: ${old_codename:-unknown} → $codename, adding signed-by" + sed -i \ + -e "s|deb https://|deb [arch=amd64 signed-by=$modern_keyring] https://|" \ + -e "s|deb-src https://|# deb-src [arch=amd64 signed-by=$modern_keyring] https://|" \ + -e "s|ubuntu/ ${old_codename}|ubuntu/ ${codename}|g" \ + -e "s|ubuntu ${old_codename}|ubuntu ${codename}|g" \ + "$src" + done + + log "WineHQ key migrated and source updated." +} + +# ===================================================================== +# Run all fixes, then upgrade +# ===================================================================== +log "Running apt source hygiene checks..." +fix_duplicate_chrome_edge_repo +fix_cloudflare_key +fix_wine_legacy_key +log "Apt source checks complete." + +echo "" +log "Installing aptitude if needed..." +apt-get install -y aptitude + +log "Starting system upgrade..." +apt-get -y update && apt-get -y upgrade && apt-get -y dist-upgrade +apt-get -y autoremove +aptitude -y update && aptitude -y safe-upgrade && aptitude -y dist-upgrade + +log "Upgrade complete."