From 253b327b72041eb0c1b4a84668a2486cdee6cd2e Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Mon, 2 Mar 2026 19:13:22 +0100 Subject: [PATCH] fix: bluetooth optimze arch desktop phone foucs mode and no secres --- .pre-commit-config.yaml | 11 + .../scripts/fixes/fix_bluetooth.sh | 283 +++++++- .../scripts/fixes/optimize_arch_desktop.sh | 623 ++++++++++++++++++ phone_focus_mode/README.md | 7 +- phone_focus_mode/deploy.sh | 6 +- scripts/check_no_secrets.sh | 46 ++ scripts/makepkg-manual-dlagent.sh | 88 +++ 7 files changed, 1044 insertions(+), 20 deletions(-) create mode 100755 linux_configuration/scripts/fixes/optimize_arch_desktop.sh create mode 100755 scripts/check_no_secrets.sh create mode 100755 scripts/makepkg-manual-dlagent.sh diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2ac259f..e4a8913 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -335,6 +335,17 @@ repos: pass_filenames: false always_run: true + # =========================================================================== + # SECRET PATTERNS - Block commits containing sensitive data + # =========================================================================== + - repo: local + hooks: + - id: check-no-secrets + name: check for leaked secrets + entry: scripts/check_no_secrets.sh + language: script + exclude: ^(\.secret-patterns|\.pre-commit-config\.yaml|.*\.geojson)$ + # =========================================================================== # COMMITIZEN - Conventional commits (optional) # =========================================================================== diff --git a/linux_configuration/scripts/fixes/fix_bluetooth.sh b/linux_configuration/scripts/fixes/fix_bluetooth.sh index 9b01904..1b1ac51 100755 --- a/linux_configuration/scripts/fixes/fix_bluetooth.sh +++ b/linux_configuration/scripts/fixes/fix_bluetooth.sh @@ -8,11 +8,15 @@ # 3. Stale pairing data causing connection hangs # 4. Missing Broadcom firmware (.hcd files) # 5. Stuck/unresponsive adapter requiring USB reset +# 6. USB autosuspend causing audio dropouts +# 7. Hung PipeWire/WirePlumber audio stack +# 8. Auto scan/pair/trust/connect when MAC is provided +# 9. SBC-XQ codec causing dropouts on older adapters # # Usage: # ./fix_bluetooth.sh # Diagnose and fix all issues # ./fix_bluetooth.sh --interactive # Prompt before each fix -# ./fix_bluetooth.sh # Target a specific device +# ./fix_bluetooth.sh # Fix + auto-connect to device # ./fix_bluetooth.sh --interactive # Both # # Safe to re-run: all fixes are idempotent. @@ -61,6 +65,14 @@ apply_fix() { fi } +# --------------------------------------------------------------------------- +# Helper: run a bluetoothctl command reliably via stdin pipe. +# (bluetoothctl -- returns empty when run non-interactively) +# --------------------------------------------------------------------------- +_btctl() { + echo "$*" | bluetoothctl 2>/dev/null +} + # ========================================================================== # 1. Check Bluetooth service status # ========================================================================== @@ -181,7 +193,7 @@ check_adapter_stuck() { # Test if bluetoothctl can see the adapter local adapter_list - adapter_list=$(echo "list" | bluetoothctl 2>/dev/null | grep "^Controller" || true) + adapter_list=$(_btctl list | grep "^Controller" || true) if [[ -n $adapter_list ]]; then log_ok "Adapter is responsive: $adapter_list" @@ -224,16 +236,19 @@ remove_stale_pairing() { echo "" log_info "Checking for stale pairing with $TARGET_MAC..." - if bluetoothctl info "$TARGET_MAC" 2>/dev/null | grep -q "Device $TARGET_MAC"; then + local info + info=$(_btctl info "$TARGET_MAC" || true) + + if echo "$info" | grep -q "Device $TARGET_MAC"; then local paired - paired=$(bluetoothctl info "$TARGET_MAC" 2>/dev/null | grep "Paired:" | awk '{print $2}') + paired=$(echo "$info" | grep "Paired:" | awk '{print $2}') local connected - connected=$(bluetoothctl info "$TARGET_MAC" 2>/dev/null | grep "Connected:" | awk '{print $2}') + connected=$(echo "$info" | grep "Connected:" | awk '{print $2}') if [[ $paired == "yes" && $connected == "no" ]]; then log_warn "Device is paired but NOT connected — may have stale pairing." apply_fix "Removing stale pairing for $TARGET_MAC" \ - bluetoothctl remove "$TARGET_MAC" + _btctl remove "$TARGET_MAC" elif [[ $paired == "no" ]]; then log_info "Device is not currently paired." else @@ -258,7 +273,244 @@ restart_bluetooth() { } # ========================================================================== -# 7. Show connection instructions +# 7. Disable USB autosuspend for Bluetooth adapter +# ========================================================================== +fix_usb_autosuspend() { + echo "" + log_info "Checking USB autosuspend for Bluetooth adapter..." + + local bt_usb + bt_usb=$(lsusb 2>/dev/null | grep -i bluetooth | head -1 || true) + if [[ -z $bt_usb ]]; then + return 0 + fi + + local usb_id + usb_id=$(echo "$bt_usb" | grep -oP 'ID \K[0-9a-f]{4}:[0-9a-f]{4}' || true) + if [[ -z $usb_id ]]; then + return 0 + fi + + local vendor="${usb_id%%:*}" + local product="${usb_id##*:}" + + # Find the sysfs device path + local sysfs_path="" + local dev_path + for dev_path in /sys/bus/usb/devices/*/; do + if [[ -f "${dev_path}idVendor" && -f "${dev_path}idProduct" ]]; then + local v p + v=$(cat "${dev_path}idVendor" 2>/dev/null || true) + p=$(cat "${dev_path}idProduct" 2>/dev/null || true) + if [[ $v == "$vendor" && $p == "$product" ]]; then + sysfs_path="$dev_path" + break + fi + fi + done + + if [[ -z $sysfs_path ]]; then + log_warn "Could not find sysfs path for BT adapter." + return 0 + fi + + local power_control="${sysfs_path}power/control" + if [[ -f $power_control ]]; then + local current + current=$(cat "$power_control" 2>/dev/null || true) + if [[ $current != "on" ]]; then + log_warn "USB autosuspend is enabled ($current) — can cause audio dropouts." + apply_fix "Disabling USB autosuspend for BT adapter" \ + _disable_usb_autosuspend "$power_control" "$vendor" "$product" + else + log_ok "USB autosuspend already disabled." + fi + fi +} + +_disable_usb_autosuspend() { + local power_control="$1" + local vendor="$2" + local product="$3" + + # Immediate fix + echo "on" > "$power_control" + + # Persistent udev rule + local rule_file="/etc/udev/rules.d/50-bluetooth-no-autosuspend.rules" + local rule="ACTION==\"add\", SUBSYSTEM==\"usb\", ATTR{idVendor}==\"$vendor\", ATTR{idProduct}==\"$product\", ATTR{power/control}=\"on\"" + + if [[ ! -f $rule_file ]] || ! grep -qF "$vendor" "$rule_file" 2>/dev/null; then + echo "$rule" > "$rule_file" + udevadm control --reload-rules 2>/dev/null || true + log_info "Created persistent udev rule: $rule_file" + fi +} + +# ========================================================================== +# 8. Check PipeWire/WirePlumber health (hung audio stack) +# ========================================================================== +check_pipewire_health() { + echo "" + log_info "Checking PipeWire/WirePlumber health..." + + if ! has_cmd wpctl; then + log_info "wpctl not found — skipping PipeWire health check." + return 0 + fi + + # Test if PipeWire is responding within 3 seconds + if timeout 3 wpctl status &>/dev/null; then + log_ok "PipeWire is responsive." + return 0 + fi + + log_warn "PipeWire/WirePlumber appears hung (wpctl timed out)." + apply_fix "Restarting PipeWire + WirePlumber audio stack" \ + _restart_pipewire_stack +} + +_restart_pipewire_stack() { + # Restart as the calling user (these are user services) + local target_user + target_user="${SUDO_USER:-$USER}" + local target_uid + target_uid=$(id -u "$target_user") + + sudo -u "$target_user" \ + XDG_RUNTIME_DIR="/run/user/$target_uid" \ + DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$target_uid/bus" \ + systemctl --user restart pipewire pipewire-pulse wireplumber + + sleep 3 + log_info "Waiting for audio stack to initialize..." +} + +# ========================================================================== +# 9. Auto-connect target device +# ========================================================================== +connect_device() { + if [[ -z $TARGET_MAC ]]; then + return 0 + fi + + echo "" + log_info "Attempting to connect to $TARGET_MAC..." + + # Check if already connected + local info + info=$(_btctl info "$TARGET_MAC" || true) + if echo "$info" | grep -q "Connected: yes"; then + log_ok "Device $TARGET_MAC is already connected." + return 0 + fi + + # Power on adapter + _btctl power on >/dev/null || true + sleep 1 + + # ---- Attempt 1: direct connect (existing pairing) ---- + if echo "$info" | grep -q "Paired: yes"; then + log_info "Device is already paired. Trying direct connect..." + { echo "power on"; sleep 1; echo "connect $TARGET_MAC"; sleep 15; } \ + | bluetoothctl 2>/dev/null || true + + info=$(_btctl info "$TARGET_MAC" || true) + if echo "$info" | grep -q "Connected: yes"; then + log_ok "Connected to $TARGET_MAC!" + return 0 + fi + + # Direct connect failed — remove stale pairing and try fresh + log_warn "Direct connect failed. Removing stale pairing for fresh start." + _btctl remove "$TARGET_MAC" >/dev/null || true + sleep 2 + fi + + # ---- Attempt 2: scan + pair from scratch ---- + log_info "Scanning for $TARGET_MAC (20 seconds)..." + log_info "Make sure the device is in pairing mode." + { echo "power on"; sleep 1; echo "scan on"; sleep 20; echo "scan off"; sleep 2; } \ + | bluetoothctl 2>/dev/null || true + + # Check if device was found + local devices + devices=$(_btctl devices || true) + if ! echo "$devices" | grep -qi "$TARGET_MAC"; then + log_error "Device $TARGET_MAC not found during scan." + log_info "Put the device in pairing mode and re-run the script." + return 1 + fi + + log_ok "Device found during scan." + + # Pair + log_info "Pairing..." + { echo "power on"; sleep 1; echo "pair $TARGET_MAC"; sleep 5; } \ + | bluetoothctl 2>/dev/null || true + + # Trust (so it auto-reconnects in the future) + log_info "Trusting..." + { echo "trust $TARGET_MAC"; sleep 2; } | bluetoothctl 2>/dev/null || true + + # Connect + log_info "Connecting..." + { echo "power on"; sleep 1; echo "connect $TARGET_MAC"; sleep 15; } \ + | bluetoothctl 2>/dev/null || true + + # Verify connection + sleep 2 + info=$(_btctl info "$TARGET_MAC" || true) + if echo "$info" | grep -q "Connected: yes"; then + log_ok "Successfully connected to $TARGET_MAC!" + else + log_error "Connection to $TARGET_MAC failed." + log_info "Try putting the device in pairing mode and re-run." + return 1 + fi +} + +# ========================================================================== +# 10. Set audio profile (avoid SBC-XQ dropouts on older adapters) +# ========================================================================== +set_audio_profile() { + if [[ -z $TARGET_MAC ]]; then + return 0 + fi + + if ! has_cmd pactl; then + return 0 + fi + + echo "" + log_info "Checking audio profile..." + + # Wait a moment for PipeWire to set up the audio card + sleep 3 + + local card_name="bluez_card.${TARGET_MAC//:/_}" + local card_info + card_info=$(pactl list cards 2>/dev/null || true) + + if ! echo "$card_info" | grep -q "$card_name"; then + log_info "No PipeWire audio card found for device (may not be an audio device)." + return 0 + fi + + local current_profile + current_profile=$(echo "$card_info" | grep -A 50 "$card_name" | grep "Active Profile:" | head -1 | awk '{print $3}' || true) + + if [[ $current_profile == *"sbc_xq"* ]]; then + log_warn "SBC-XQ codec active — may cause audio dropouts on older adapters." + apply_fix "Switching to standard SBC codec" \ + pactl set-card-profile "$card_name" a2dp-sink + elif [[ -n $current_profile ]]; then + log_ok "Audio profile: $current_profile" + fi +} + +# ========================================================================== +# 11. Show connection instructions # ========================================================================== show_instructions() { echo "" @@ -294,7 +546,7 @@ EOF } # ========================================================================== -# 8. Dump diagnostic info +# 12. Dump diagnostic info # ========================================================================== dump_diagnostics() { echo "" @@ -302,11 +554,11 @@ dump_diagnostics() { echo "" echo "--- Bluetooth adapter ---" - echo "show" | bluetoothctl 2>/dev/null | grep -v '\[bluetoothctl\]' | head -20 || true + _btctl show | grep -v '\[bluetoothctl\]' | head -20 || true echo "" echo "--- Known devices ---" - echo "devices" | bluetoothctl 2>/dev/null | grep '^Device' || true + _btctl devices | grep '^Device' || true echo "" echo "--- Loaded Bluetooth kernel modules ---" @@ -319,7 +571,7 @@ dump_diagnostics() { if [[ -n $TARGET_MAC ]]; then echo "" echo "--- Device info: $TARGET_MAC ---" - bluetoothctl info "$TARGET_MAC" 2>/dev/null || echo "(device not known)" + _btctl info "$TARGET_MAC" || echo "(device not known)" fi echo "" @@ -336,7 +588,8 @@ main() { check_packages check_firmware check_adapter_stuck - remove_stale_pairing + fix_usb_autosuspend + check_pipewire_health restart_bluetooth echo "" @@ -344,7 +597,11 @@ main() { printf "Fixes applied: %d | Skipped: %d\n" "$FIXES_APPLIED" "$FIXES_SKIPPED" echo "===========================================" - show_instructions + if ! connect_device; then + show_instructions + fi + + set_audio_profile } main diff --git a/linux_configuration/scripts/fixes/optimize_arch_desktop.sh b/linux_configuration/scripts/fixes/optimize_arch_desktop.sh new file mode 100755 index 0000000..af38f3c --- /dev/null +++ b/linux_configuration/scripts/fixes/optimize_arch_desktop.sh @@ -0,0 +1,623 @@ +#!/usr/bin/env bash + +# Optimize Arch Linux desktop for maximum performance on high-end hardware +# +# Tuning areas: +# 1. CPU scheduler — performance governor on all cores +# 2. I/O scheduler — optimal scheduler per drive type (none for NVMe, mq-deadline for SATA SSD) +# 3. Memory / swap — lower swappiness, tune dirty page writeback for responsiveness +# 4. Kernel network — TCP BBR, fastopen, larger buffers +# 5. Filesystem — fstrim timer, noatime advisory +# 6. NVIDIA GPU — max performance level via persistence mode +# 7. Kernel mitigations — option to disable CPU vulnerability mitigations for extra speed +# 8. Boot speed — disable unnecessary wait-online services +# 9. Journal housekeeping — cap at 300M +# 10. Process scheduler — install ananicy-cpp for automatic nice/ionice/scheduling +# +# Usage: +# ./optimize_arch_desktop.sh # Apply safe optimizations +# ./optimize_arch_desktop.sh --dry-run # Show what would be done +# ./optimize_arch_desktop.sh --interactive # Prompt before each tweak +# ./optimize_arch_desktop.sh --aggressive # Include CPU mitigation disable (risk: security) +# ./optimize_arch_desktop.sh -h # Show help +# +# All tweaks are idempotent and safe to re-run. +# Some kernel parameter changes require a reboot to take full effect. + +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 +AGGRESSIVE=false + +for arg in "$@"; do + case "$arg" in + --dry-run) + DRY_RUN=true + ;; + --aggressive) + AGGRESSIVE=true + ;; + -h | --help) + cat <<'EOF' +optimize_arch_desktop.sh - Squeeze maximum performance from an Arch Linux desktop + +Usage: optimize_arch_desktop.sh [OPTIONS] + +Options: + --dry-run Show what would be done without making changes + --aggressive Also disable CPU vulnerability mitigations (trades security for speed) + -i, --interactive Prompt before each optimization + -h, --help Show this help message + +Optimizations applied: + 1. Set CPU governor to performance on all cores + 2. Set optimal I/O scheduler per drive (none/mq-deadline) + 3. Tune vm.swappiness, dirty ratios, vfs_cache_pressure via sysctl + 4. Enable TCP BBR congestion control + fastopen + buffer tuning + 5. Enable fstrim.timer for SSD TRIM maintenance + 6. Set NVIDIA GPU to max performance level (persistence mode) + 7. [--aggressive] Disable CPU vulnerability mitigations + 8. Disable NetworkManager-wait-online.service for faster boot + 9. Vacuum & cap systemd journal at 300M + 10. Install/enable ananicy-cpp for automatic process prioritization + +All optimizations are idempotent. Re-run safely at any time. +EOF + exit 0 + ;; + esac +done + +require_root "$@" + +print_setup_header "Arch Linux Desktop Performance Optimizer" + +TWEAKS_APPLIED=0 +TWEAKS_SKIPPED=0 + +# --------------------------------------------------------------------------- +# Helper: apply or preview a tweak +# --------------------------------------------------------------------------- +apply_tweak() { + 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 optimization?"; then + log_warn "Skipped." + ((TWEAKS_SKIPPED++)) || true + return 0 + fi + fi + + if "$@"; then + log_ok "Done." + ((TWEAKS_APPLIED++)) || true + else + log_error "Failed (non-fatal, continuing)." + fi +} + +# =================================================================== +# 1. CPU Governor → performance +# =================================================================== +tweak_cpu_governor() { + local gov_files + gov_files=$(find /sys/devices/system/cpu -maxdepth 3 -name scaling_governor 2>/dev/null || true) + + if [[ -z $gov_files ]]; then + log_warn "No CPU governor sysfs files found — skipping." + return 0 + fi + + # Check current state + local all_performance=true + local f + for f in $gov_files; do + if [[ $(cat "$f") != "performance" ]]; then + all_performance=false + break + fi + done + + if [[ $all_performance == "true" ]]; then + log_ok "All CPU cores already on 'performance' governor — skipping." + return 0 + fi + + for f in $gov_files; do + echo "performance" >"$f" + done + + # Make it persistent via a sysctl-style drop-in using udev rule + local udev_rule="/etc/udev/rules.d/60-cpu-governor-performance.rules" + if [[ ! -f $udev_rule ]]; then + cat >"$udev_rule" <<'UDEVEOF' +# Set CPU governor to performance on all cores at boot +SUBSYSTEM=="module", DEVPATH=="*/cpu/*", ATTR{scaling_governor}=="*", ATTR{scaling_governor}="performance" +UDEVEOF + fi + + # Also install cpupower hook as a more reliable persistence method + local cpupower_conf="/etc/default/cpupower" + if has_cmd cpupower; then + if [[ ! -f $cpupower_conf ]] || ! grep -q "^governor='performance'" "$cpupower_conf" 2>/dev/null; then + mkdir -p "$(dirname "$cpupower_conf")" + cat >"$cpupower_conf" <<'CPUEOF' +# /etc/default/cpupower — managed by optimize_arch_desktop.sh +governor='performance' +CPUEOF + systemctl enable cpupower.service 2>/dev/null || true + fi + fi + + return 0 +} + +# =================================================================== +# 2. I/O Scheduler per drive type +# =================================================================== +tweak_io_scheduler() { + local changed=false + + local block_dev + for block_dev in /sys/block/sd* /sys/block/nvme* /sys/block/vd*; do + [[ -d $block_dev ]] || continue + local sched_file="$block_dev/queue/scheduler" + [[ -f $sched_file ]] || continue + + local dev_name + dev_name=$(basename "$block_dev") + local rotational + rotational=$(cat "$block_dev/queue/rotational" 2>/dev/null || echo 1) + local current + current=$(sed 's/.*\[\(.*\)\].*/\1/' "$sched_file" 2>/dev/null || true) + + local target + if [[ $dev_name == nvme* ]]; then + target="none" + elif [[ $rotational -eq 0 ]]; then + target="mq-deadline" + else + target="bfq" + fi + + if [[ $current == "$target" ]]; then + log_ok "$dev_name: already using '$target' scheduler." + continue + fi + + echo "$target" >"$sched_file" 2>/dev/null || true + log_info "$dev_name: scheduler changed from '$current' to '$target'." + changed=true + done + + # Persist via udev rule + local udev_rule="/etc/udev/rules.d/60-io-scheduler.rules" + if [[ ! -f $udev_rule ]]; then + cat >"$udev_rule" <<'IOEOF' +# NVMe: no scheduler (multi-queue hardware handles it) +ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/scheduler}="none" +# SATA SSD: mq-deadline (low latency) +ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline" +# HDD: BFQ (fair bandwidth allocation) +ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="bfq" +IOEOF + fi + + if [[ $changed == "false" ]]; then + log_ok "All I/O schedulers already optimal." + fi + + return 0 +} + +# =================================================================== +# 3. Memory & swap tuning via sysctl +# =================================================================== +tweak_vm_sysctl() { + local dropin="/etc/sysctl.d/90-desktop-performance.conf" + + # Desktop workloads: low swappiness, aggressive VFS caching, tuned dirty ratios + local -A params=( + ["vm.swappiness"]="10" + ["vm.vfs_cache_pressure"]="50" + ["vm.dirty_ratio"]="15" + ["vm.dirty_background_ratio"]="5" + ["vm.dirty_writeback_centisecs"]="1500" + ["vm.page-cluster"]="0" + ) + + local needs_update=false + local key + for key in "${!params[@]}"; do + local current + current=$(sysctl -n "$key" 2>/dev/null || true) + if [[ $current != "${params[$key]}" ]]; then + needs_update=true + break + fi + done + + if [[ $needs_update == "false" && -f $dropin ]]; then + log_ok "VM sysctl parameters already tuned — skipping." + return 0 + fi + + cat >"$dropin" <<'VMEOF' +# Desktop performance tuning — managed by optimize_arch_desktop.sh +# +# vm.swappiness=10 — prefer keeping data in RAM over swapping +# vm.vfs_cache_pressure=50 — favor keeping inode/dentry caches (speeds up file operations) +# vm.dirty_ratio=15 — allow up to 15% RAM dirty before synchronous writeback +# vm.dirty_background_ratio=5 — start async writeback at 5% dirty +# vm.dirty_writeback_centisecs=1500 — flush dirty pages every 15s (less I/O churn) +# vm.page-cluster=0 — read one page at a time from swap (reduces latency on SSD) +vm.swappiness = 10 +vm.vfs_cache_pressure = 50 +vm.dirty_ratio = 15 +vm.dirty_background_ratio = 5 +vm.dirty_writeback_centisecs = 1500 +vm.page-cluster = 0 +VMEOF + + sysctl --system >/dev/null 2>&1 + return 0 +} + +# =================================================================== +# 4. Network: TCP BBR + fastopen + buffer tuning +# =================================================================== +tweak_network_sysctl() { + local dropin="/etc/sysctl.d/91-desktop-network.conf" + + # Check if BBR module is available + if ! modprobe tcp_bbr 2>/dev/null; then + log_warn "tcp_bbr kernel module unavailable — skipping network tuning." + return 0 + fi + + local -A params=( + ["net.core.default_qdisc"]="fq" + ["net.ipv4.tcp_congestion_control"]="bbr" + ["net.ipv4.tcp_fastopen"]="3" + ["net.core.rmem_max"]="16777216" + ["net.core.wmem_max"]="16777216" + ["net.ipv4.tcp_rmem"]="4096 1048576 16777216" + ["net.ipv4.tcp_wmem"]="4096 1048576 16777216" + ["net.ipv4.tcp_mtu_probing"]="1" + ) + + local needs_update=false + local key + for key in "${!params[@]}"; do + local current + current=$(sysctl -n "$key" 2>/dev/null || true) + # Normalize whitespace for comparison (kernel uses tabs) + current=$(echo "$current" | xargs) + local expected + expected=$(echo "${params[$key]}" | xargs) + if [[ $current != "$expected" ]]; then + needs_update=true + break + fi + done + + if [[ $needs_update == "false" && -f $dropin ]]; then + log_ok "Network sysctl parameters already tuned — skipping." + return 0 + fi + + cat >"$dropin" <<'NETEOF' +# Network performance tuning — managed by optimize_arch_desktop.sh +# +# BBR congestion control — better throughput and lower latency than cubic +# TCP fastopen — saves one RTT on repeated connections (both client and server) +# Larger buffers — helps on high-bandwidth or high-latency links +net.core.default_qdisc = fq +net.ipv4.tcp_congestion_control = bbr +net.ipv4.tcp_fastopen = 3 +net.core.rmem_max = 16777216 +net.core.wmem_max = 16777216 +net.ipv4.tcp_rmem = 4096 1048576 16777216 +net.ipv4.tcp_wmem = 4096 1048576 16777216 +net.ipv4.tcp_mtu_probing = 1 +NETEOF + + sysctl --system >/dev/null 2>&1 + return 0 +} + +# =================================================================== +# 5. fstrim timer +# =================================================================== +tweak_fstrim() { + if systemctl is-enabled fstrim.timer >/dev/null 2>&1; then + log_ok "fstrim.timer already enabled — skipping." + return 0 + fi + + systemctl enable --now fstrim.timer + return 0 +} + +# =================================================================== +# 6. NVIDIA GPU — max performance +# =================================================================== +tweak_nvidia_gpu() { + if ! has_cmd nvidia-smi; then + log_info "nvidia-smi not found — skipping GPU tuning." + return 0 + fi + + # Enable persistence mode (keeps driver loaded, faster app launches) + local persist_status + persist_status=$(nvidia-smi --query-gpu=persistence_mode --format=csv,noheader 2>/dev/null | head -n 1 | xargs || true) + if [[ $persist_status != "Enabled" ]]; then + nvidia-smi -pm 1 >/dev/null 2>&1 || true + log_info "NVIDIA persistence mode enabled." + else + log_ok "NVIDIA persistence mode already enabled." + fi + + # Set power management to prefer maximum performance + # PowerMizerMode: 1 = prefer max perf + nvidia-smi -gps 0 >/dev/null 2>&1 || true + + # Persist via systemd service + local service_file="/etc/systemd/system/nvidia-performance.service" + if [[ ! -f $service_file ]]; then + cat >"$service_file" <<'NVSVC' +[Unit] +Description=Set NVIDIA GPU to max performance mode +After=nvidia-persistenced.service + +[Service] +Type=oneshot +ExecStart=/usr/bin/nvidia-smi -pm 1 +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target +NVSVC + systemctl daemon-reload + systemctl enable nvidia-performance.service 2>/dev/null || true + fi + + # Ensure nvidia-persistenced is enabled + if has_cmd nvidia-persistenced; then + systemctl enable nvidia-persistenced.service 2>/dev/null || true + if ! systemctl is-active nvidia-persistenced.service >/dev/null 2>&1; then + systemctl start nvidia-persistenced.service 2>/dev/null || true + fi + fi + + return 0 +} + +# =================================================================== +# 7. [AGGRESSIVE] Disable CPU vulnerability mitigations +# =================================================================== +tweak_mitigations() { + if [[ $AGGRESSIVE != "true" ]]; then + log_info "Skipping CPU mitigation disable (use --aggressive to enable)." + return 0 + fi + + # Detect boot loader + local boot_method="" + if [[ -d /boot/loader/entries ]]; then + boot_method="systemd-boot" + elif [[ -f /etc/default/grub ]]; then + boot_method="grub" + else + log_warn "Could not detect boot loader — skipping mitigation tweak." + log_info "Manually add 'mitigations=off' to your kernel command line for extra speed." + return 0 + fi + + if [[ $boot_method == "systemd-boot" ]]; then + local entry + entry=$(find /boot/loader/entries -name '*.conf' -print -quit 2>/dev/null || true) + if [[ -n $entry ]]; then + if grep -q 'mitigations=off' "$entry" 2>/dev/null; then + log_ok "mitigations=off already set in systemd-boot — skipping." + return 0 + fi + # Append to the options line + sed -i '/^options / s/$/ mitigations=off/' "$entry" + log_warn "Added mitigations=off to $entry. REBOOT REQUIRED." + log_warn "This trades security for ~5-15% performance. Only for isolated desktops." + fi + elif [[ $boot_method == "grub" ]]; then + if grep -q 'mitigations=off' /etc/default/grub 2>/dev/null; then + log_ok "mitigations=off already set in GRUB — skipping." + return 0 + fi + sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT="\(.*\)"/GRUB_CMDLINE_LINUX_DEFAULT="\1 mitigations=off"/' /etc/default/grub + grub-mkconfig -o /boot/grub/grub.cfg + log_warn "Added mitigations=off to GRUB config. REBOOT REQUIRED." + fi + + return 0 +} + +# =================================================================== +# 8. Disable NetworkManager-wait-online +# =================================================================== +tweak_nm_wait_online() { + if ! systemctl is-enabled NetworkManager-wait-online.service >/dev/null 2>&1; then + log_ok "NetworkManager-wait-online already disabled — skipping." + return 0 + fi + + systemctl disable NetworkManager-wait-online.service + return 0 +} + +# =================================================================== +# 9. Journal vacuum + permanent cap +# =================================================================== +tweak_journal() { + local usage_line + usage_line=$(journalctl --disk-usage 2>/dev/null || true) + + local needs_vacuum=false + if [[ $usage_line =~ ([0-9]+\.?[0-9]*)\ G ]]; then + needs_vacuum=true + fi + + if [[ $needs_vacuum == "true" ]]; then + journalctl --vacuum-size=300M + else + log_ok "Journal already under 1GiB." + fi + + 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." + else + mkdir -p "$dropin_dir" + cat >"$dropin_file" <<'JOURNALEOF' +[Journal] +SystemMaxUse=300M +JOURNALEOF + systemctl restart systemd-journald + fi + + return 0 +} + +# =================================================================== +# 10. ananicy-cpp — automatic process nice/ionice/scheduler tuning +# =================================================================== +tweak_ananicy() { + # ananicy-cpp is the C++ rewrite, available in the AUR via ananicy-cpp + if systemctl is-enabled ananicy-cpp.service >/dev/null 2>&1; then + log_ok "ananicy-cpp is already enabled — skipping." + return 0 + fi + + if pacman -Qi ananicy-cpp >/dev/null 2>&1; then + systemctl enable --now ananicy-cpp.service + log_info "Enabled ananicy-cpp.service." + return 0 + fi + + # Check for the original ananicy + if pacman -Qi ananicy >/dev/null 2>&1; then + if ! systemctl is-enabled ananicy.service >/dev/null 2>&1; then + systemctl enable --now ananicy.service + log_info "Enabled ananicy.service." + else + log_ok "ananicy is already enabled." + fi + return 0 + fi + + log_info "ananicy-cpp is not installed." + log_info "Install from AUR for automatic per-process priority tuning:" + log_info " yay -S ananicy-cpp cachyos-ananicy-rules-git" + + return 0 +} + +# =================================================================== +# Apply all tweaks +# =================================================================== +main() { + apply_tweak \ + "Tweak 1/10: Set CPU governor to performance on all cores" \ + tweak_cpu_governor + + apply_tweak \ + "Tweak 2/10: Optimize I/O scheduler per drive type" \ + tweak_io_scheduler + + apply_tweak \ + "Tweak 3/10: Tune VM/memory sysctl for desktop responsiveness" \ + tweak_vm_sysctl + + apply_tweak \ + "Tweak 4/10: Enable TCP BBR + fastopen + larger buffers" \ + tweak_network_sysctl + + apply_tweak \ + "Tweak 5/10: Enable fstrim.timer for SSD TRIM maintenance" \ + tweak_fstrim + + apply_tweak \ + "Tweak 6/10: NVIDIA GPU persistence mode + max performance" \ + tweak_nvidia_gpu + + apply_tweak \ + "Tweak 7/10: CPU vulnerability mitigations (--aggressive only)" \ + tweak_mitigations + + apply_tweak \ + "Tweak 8/10: Disable NetworkManager-wait-online (faster boot)" \ + tweak_nm_wait_online + + apply_tweak \ + "Tweak 9/10: Vacuum & cap systemd journal at 300M" \ + tweak_journal + + apply_tweak \ + "Tweak 10/10: Enable ananicy-cpp process prioritization" \ + tweak_ananicy + + # --------------------------------------------------------------- + # Summary + # --------------------------------------------------------------- + echo "" + echo "==============================" + echo " Desktop Optimization Summary" + echo "==============================" + + if [[ $DRY_RUN == "true" ]]; then + log_info "Dry-run mode — no changes were made." + else + log_ok "Optimizations applied: $TWEAKS_APPLIED" + if [[ $TWEAKS_SKIPPED -gt 0 ]]; then + log_warn "Optimizations skipped: $TWEAKS_SKIPPED" + fi + fi + + echo "" + + # Advisory: check for noatime + local root_mount_opts + root_mount_opts=$(findmnt -n -o OPTIONS / 2>/dev/null || true) + if [[ -n $root_mount_opts ]] && ! echo "$root_mount_opts" | grep -q 'noatime'; then + log_info "Tip: Your root filesystem does not use 'noatime'." + log_info " Adding 'noatime' to /etc/fstab can reduce unnecessary disk writes." + log_info " (Change 'relatime' or 'atime' to 'noatime' in /etc/fstab, then reboot)" + fi + + if [[ $AGGRESSIVE == "true" ]]; then + log_warn "Aggressive mode was used — mitigations=off trades security for speed." + fi + + echo "" + log_info "Reboot recommended for kernel parameter and boot loader changes to take effect." + log_info "Verify after reboot with: diagnose_arch_performance.sh" +} + +main diff --git a/phone_focus_mode/README.md b/phone_focus_mode/README.md index 8036234..5399fb2 100644 --- a/phone_focus_mode/README.md +++ b/phone_focus_mode/README.md @@ -18,12 +18,11 @@ When outside that radius: all apps work normally. Open Google Maps, right-click your apartment → copy the coordinates shown. -### 2. Edit `config.sh` +### 2. Edit `config_secrets.sh` ```sh -HOME_LAT="52.123456" # your latitude -HOME_LON="21.098765" # your longitude -RADIUS=500 # meters +HOME_LAT="-48.876667" # your latitude +HOME_LON="-123.393333" # your longitude ``` ### 3. (Optional) Adjust the whitelist in `config.sh` diff --git a/phone_focus_mode/deploy.sh b/phone_focus_mode/deploy.sh index 09c8be2..dcd230e 100755 --- a/phone_focus_mode/deploy.sh +++ b/phone_focus_mode/deploy.sh @@ -60,9 +60,9 @@ check_coords() { echo "ERROR: You must set your home coordinates in config.sh before deploying!" echo "" echo " 1. Find your coords on Google Maps (right-click your apartment)" - echo " 2. Edit phone_focus_mode/config.sh:" - echo " HOME_LAT=\"52.123456\"" - echo " HOME_LON=\"21.098765\"" + echo " 2. Edit phone_focus_mode/config_secrets.sh:" + echo " HOME_LAT=\"-48.876667\"" + echo " HOME_LON=\"-123.393333\"" exit 1 fi echo " Home location: $lat, $lon" diff --git a/scripts/check_no_secrets.sh b/scripts/check_no_secrets.sh new file mode 100755 index 0000000..3aa7796 --- /dev/null +++ b/scripts/check_no_secrets.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# Pre-commit hook: check that no staged file contains a secret pattern. +# Patterns are read from .secret-patterns (one regex per line, # = comment). +set -euo pipefail + +PATTERNS_FILE=".secret-patterns" + +if [ ! -f "$PATTERNS_FILE" ]; then + # Try finding it relative to the git root + GIT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)" + if [ -n "$GIT_ROOT" ] && [ -f "$GIT_ROOT/$PATTERNS_FILE" ]; then + PATTERNS_FILE="$GIT_ROOT/$PATTERNS_FILE" + else + echo "Warning: $PATTERNS_FILE not found, skipping secret check." + exit 0 + fi +fi + +found=0 +# Build a temp file with non-comment, non-empty patterns +TMPPATTERNS="$(mktemp)" +trap 'rm -f "$TMPPATTERNS"' EXIT +grep -v '^\s*#' "$PATTERNS_FILE" | grep -v '^\s*$' > "$TMPPATTERNS" + +if [ ! -s "$TMPPATTERNS" ]; then + echo "No secret patterns defined in $PATTERNS_FILE, skipping." + exit 0 +fi + +for file in "$@"; do + # Skip binary files + if file --brief --mime-encoding "$file" 2>/dev/null | grep -q binary; then + continue + fi + if grep -En -f "$TMPPATTERNS" "$file" 2>/dev/null; then + echo "^^^ SECRET PATTERN found in: $file" + found=1 + fi +done + +if [ "$found" -eq 1 ]; then + echo "" + echo "ERROR: Committed files contain secret patterns from $PATTERNS_FILE" + echo "Either remove the sensitive data or update $PATTERNS_FILE if this is a false positive." + exit 1 +fi diff --git a/scripts/makepkg-manual-dlagent.sh b/scripts/makepkg-manual-dlagent.sh new file mode 100755 index 0000000..4c01555 --- /dev/null +++ b/scripts/makepkg-manual-dlagent.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash +# makepkg-manual-dlagent.sh — A makepkg download agent for the manual:// protocol. +# +# makepkg calls this as: makepkg-manual-dlagent.sh +# +# For Unreal Engine URLs, it opens the Epic download page in your browser, +# watches ~/Downloads via inotifywait, and copies the finished file to the +# expected output path — making `yay -Sua` seamless. +# +# For any other manual:// URL, it prints the original "please download manually" +# message and watches ~/Downloads for a matching filename. +# +# Install: +# 1. Place this script somewhere on your PATH or a known location. +# 2. Add to ~/.makepkg.conf: +# DLAGENTS+=('manual::/path/to/makepkg-manual-dlagent.sh %u %o') +# +# Dependencies: inotify-tools (inotifywait), xdg-open + +set -euo pipefail + +URL="$1" # e.g. manual://Linux_Unreal_Engine_5.7.2.zip +OUTPUT="$2" # e.g. /home/user/.cache/yay/unreal-engine-bin/Linux_Unreal_Engine_5.7.2.zip + +DOWNLOAD_DIR="${XDG_DOWNLOAD_DIR:-$HOME/Downloads}" + +# Strip the manual:// prefix to get the bare filename +FILENAME="${URL#manual://}" + +# If the output file already exists, nothing to do +if [[ -f "$OUTPUT" ]]; then + echo " -> File already exists: $OUTPUT" + exit 0 +fi + +# If already sitting in ~/Downloads, just copy it +if [[ -f "$DOWNLOAD_DIR/$FILENAME" ]]; then + echo " -> Found $FILENAME in $DOWNLOAD_DIR, copying..." + cp -- "$DOWNLOAD_DIR/$FILENAME" "$OUTPUT" + exit 0 +fi + +# Determine which browser page to open based on the filename +OPEN_URL="" +case "$FILENAME" in + Linux_Unreal_Engine_*.zip) + OPEN_URL="https://www.unrealengine.com/linux" + ;; +esac + +echo "" +echo " ┌─────────────────────────────────────────────────────────────┐" +echo " │ manual:// download agent │" +echo " │ File needed: $FILENAME" +echo " │ Destination: $OUTPUT" +if [[ -n "$OPEN_URL" ]]; then + echo " │ Download from: $OPEN_URL" +fi +echo " │ │" +echo " │ Download the file in your browser. │" +echo " │ It will be detected automatically from ~/Downloads. │" +echo " │ Press Ctrl+C to abort. │" +echo " └─────────────────────────────────────────────────────────────┘" +echo "" + +# Open browser if we have a URL +if [[ -n "$OPEN_URL" ]]; then + xdg-open "$OPEN_URL" 2>/dev/null & +fi + +# Escape dots in filename for inotifywait regex +FILENAME_ESCAPED="${FILENAME//./\\.}" + +# Watch ~/Downloads for the file to appear +while true; do + inotifywait -q -q -e close_write,moved_to \ + --include "${FILENAME_ESCAPED}$" \ + "$DOWNLOAD_DIR" 2>/dev/null || true + + if [[ -f "$DOWNLOAD_DIR/$FILENAME" ]]; then + # Brief pause to ensure the file is fully flushed + sleep 2 + echo " -> Download complete: $DOWNLOAD_DIR/$FILENAME" + cp -- "$DOWNLOAD_DIR/$FILENAME" "$OUTPUT" + echo " -> Copied to $OUTPUT" + exit 0 + fi +done