diff --git a/linux_configuration/scripts/digital_wellbeing/pacman/pacman_wrapper.sh b/linux_configuration/scripts/digital_wellbeing/pacman/pacman_wrapper.sh index 2912492..3515674 100755 --- a/linux_configuration/scripts/digital_wellbeing/pacman/pacman_wrapper.sh +++ b/linux_configuration/scripts/digital_wellbeing/pacman/pacman_wrapper.sh @@ -821,7 +821,7 @@ auto_remove_virtualbox_vms() { echo -e "${RED} Failed to remove: ${vm_name}${NC}" >&2 ((++failed)) fi - done <<< "$vm_list" + done <<<"$vm_list" echo -e "${CYAN}VM removal complete: ${success} removed, ${failed} failed.${NC}" >&2 } diff --git a/linux_configuration/scripts/digital_wellbeing/virtualbox/enforce_vbox_hosts.sh b/linux_configuration/scripts/digital_wellbeing/virtualbox/enforce_vbox_hosts.sh index 3454535..caf96ed 100755 --- a/linux_configuration/scripts/digital_wellbeing/virtualbox/enforce_vbox_hosts.sh +++ b/linux_configuration/scripts/digital_wellbeing/virtualbox/enforce_vbox_hosts.sh @@ -15,29 +15,29 @@ NC='\033[0m' # No Color # Auto-sudo functionality with confirmation if [ "$EUID" -ne 0 ]; then - echo -e "${YELLOW}This script requires root privileges to configure VirtualBox VMs.${NC}" - echo -e "${CYAN}Executing with sudo...${NC}" - exec sudo bash "$0" "$@" + echo -e "${YELLOW}This script requires root privileges to configure VirtualBox VMs.${NC}" + echo -e "${CYAN}Executing with sudo...${NC}" + exec sudo bash "$0" "$@" fi # Determine the real (non-root) user who invoked this script. # VBoxManage must run as this user because VMs are registered per-user. REAL_USER="${SUDO_USER:-$USER}" if [[ $REAL_USER == "root" ]]; then - echo -e "${RED}Cannot determine the real user. Do not run this script as root directly.${NC}" - echo -e "${RED}Run it as a normal user (it will auto-sudo as needed).${NC}" - exit 1 + echo -e "${RED}Cannot determine the real user. Do not run this script as root directly.${NC}" + echo -e "${RED}Run it as a normal user (it will auto-sudo as needed).${NC}" + exit 1 fi # Check if VBoxManage is available -if ! command -v VBoxManage > /dev/null 2>&1; then - echo -e "${RED}VBoxManage not found. VirtualBox may not be installed.${NC}" - exit 1 +if ! command -v VBoxManage >/dev/null 2>&1; then + echo -e "${RED}VBoxManage not found. VirtualBox may not be installed.${NC}" + exit 1 fi # Run VBoxManage as the real user so it sees their registered VMs vboxmanage_as_user() { - sudo -u "$REAL_USER" VBoxManage "$@" + sudo -u "$REAL_USER" VBoxManage "$@" } # Configuration @@ -46,54 +46,54 @@ HOSTS_ENFORCEMENT_MARKER="/var/lib/vbox-hosts-enforced" # Get list of all VMs get_all_vms() { - vboxmanage_as_user list vms | awk -F'"' '{print $2}' + vboxmanage_as_user list vms | awk -F'"' '{print $2}' } # Get list of running VMs get_running_vms() { - vboxmanage_as_user list runningvms | awk -F'"' '{print $2}' + vboxmanage_as_user list runningvms | awk -F'"' '{print $2}' } # Configure a VM to use host DNS (NAT network) configure_vm_dns() { - local vm_name="$1" - echo -e "${BLUE}Configuring DNS for VM: ${vm_name}${NC}" + local vm_name="$1" + echo -e "${BLUE}Configuring DNS for VM: ${vm_name}${NC}" - # Enable DNS proxy for NAT adapter (adapter 1 by default) - # This makes the VM use the host's DNS resolution - vboxmanage_as_user modifyvm "$vm_name" --natdnshostresolver1 on 2>/dev/null || true - vboxmanage_as_user modifyvm "$vm_name" --natdnsproxy1 on 2>/dev/null || true + # Enable DNS proxy for NAT adapter (adapter 1 by default) + # This makes the VM use the host's DNS resolution + vboxmanage_as_user modifyvm "$vm_name" --natdnshostresolver1 on 2>/dev/null || true + vboxmanage_as_user modifyvm "$vm_name" --natdnsproxy1 on 2>/dev/null || true - echo -e "${GREEN}DNS configuration applied to ${vm_name}${NC}" + echo -e "${GREEN}DNS configuration applied to ${vm_name}${NC}" } # Add shared folder for /etc directory (read-only) configure_hosts_shared_folder() { - local vm_name="$1" - echo -e "${BLUE}Setting up /etc/hosts sharing for VM: ${vm_name}${NC}" + local vm_name="$1" + echo -e "${BLUE}Setting up /etc/hosts sharing for VM: ${vm_name}${NC}" - # Remove existing shared folder if present - vboxmanage_as_user sharedfolder remove "$vm_name" --name "$VBOX_SHARED_FOLDER_NAME" 2>/dev/null || true + # Remove existing shared folder if present + vboxmanage_as_user sharedfolder remove "$vm_name" --name "$VBOX_SHARED_FOLDER_NAME" 2>/dev/null || true - # Add /etc as a shared folder (read-only) - vboxmanage_as_user sharedfolder add "$vm_name" \ - --name "$VBOX_SHARED_FOLDER_NAME" \ - --hostpath "/etc" \ - --readonly \ - --automount 2>/dev/null || { - echo -e "${YELLOW}Could not add shared folder to ${vm_name} (VM may be running)${NC}" - return 1 - } + # Add /etc as a shared folder (read-only) + vboxmanage_as_user sharedfolder add "$vm_name" \ + --name "$VBOX_SHARED_FOLDER_NAME" \ + --hostpath "/etc" \ + --readonly \ + --automount 2>/dev/null || { + echo -e "${YELLOW}Could not add shared folder to ${vm_name} (VM may be running)${NC}" + return 1 + } - echo -e "${GREEN}Shared folder configured for ${vm_name}${NC}" - return 0 + echo -e "${GREEN}Shared folder configured for ${vm_name}${NC}" + return 0 } # Create a startup script that can be placed in VMs generate_vm_startup_script() { - local output_file="${1:-/tmp/vbox_hosts_sync.sh}" + local output_file="${1:-/tmp/vbox_hosts_sync.sh}" - cat > "$output_file" << 'EOF' + cat >"$output_file" <<'EOF' #!/bin/bash # VirtualBox VM startup script to sync /etc/hosts from host machine # This should be placed in the VM and run at startup @@ -161,283 +161,283 @@ if [ -f "$HOST_HOSTS_FILE" ]; then fi EOF - chmod +x "$output_file" - echo -e "${GREEN}Generated VM startup script at ${output_file}${NC}" - echo -e "${CYAN}Copy this script to your VMs and add it to their startup (e.g., /etc/rc.local or systemd)${NC}" + chmod +x "$output_file" + echo -e "${GREEN}Generated VM startup script at ${output_file}${NC}" + echo -e "${CYAN}Copy this script to your VMs and add it to their startup (e.g., /etc/rc.local or systemd)${NC}" } # Get the disk image path for a VM (first SATA/IDE .vdi/.vmdk/.vhd) get_vm_disk_path() { - local vm_name="$1" - vboxmanage_as_user showvminfo "$vm_name" --machinereadable 2>/dev/null \ - | grep -E '^"(SATA|IDE|SCSI|NVMe)-[0-9]+-[0-9]+"=' \ - | grep -vE '="none"$' \ - | grep -vE '\.iso"$' \ - | head -1 \ - | sed 's/^[^=]*="//; s/"$//' + local vm_name="$1" + vboxmanage_as_user showvminfo "$vm_name" --machinereadable 2>/dev/null | + grep -E '^"(SATA|IDE|SCSI|NVMe)-[0-9]+-[0-9]+"=' | + grep -vE '="none"$' | + grep -vE '\.iso"$' | + head -1 | + sed 's/^[^=]*="//; s/"$//' } # Inject host's /etc/hosts directly into a VM disk image using qemu-nbd. # This is the only reliable way to enforce blocking, because NAT DNS proxy # alone does not work when the guest browser uses DNS-over-HTTPS (DoH). inject_hosts_into_vm_disk() { - local vm_name="$1" - local disk_path - disk_path="$(get_vm_disk_path "$vm_name")" + local vm_name="$1" + local disk_path + disk_path="$(get_vm_disk_path "$vm_name")" - if [[ -z $disk_path || ! -f $disk_path ]]; then - echo -e "${YELLOW}Could not find disk image for VM '${vm_name}', skipping hosts injection${NC}" - return 1 - fi + if [[ -z $disk_path || ! -f $disk_path ]]; then + echo -e "${YELLOW}Could not find disk image for VM '${vm_name}', skipping hosts injection${NC}" + return 1 + fi - # Ensure VM is not running - if vboxmanage_as_user list runningvms 2>/dev/null | grep -q "\"${vm_name}\""; then - echo -e "${YELLOW}VM '${vm_name}' is running, cannot inject hosts file. Stop it first.${NC}" - return 1 - fi + # Ensure VM is not running + if vboxmanage_as_user list runningvms 2>/dev/null | grep -q "\"${vm_name}\""; then + echo -e "${YELLOW}VM '${vm_name}' is running, cannot inject hosts file. Stop it first.${NC}" + return 1 + fi - # Check for qemu-nbd - if ! command -v qemu-nbd > /dev/null 2>&1; then - echo -e "${YELLOW}qemu-nbd not found. Install qemu-base to enable hosts file injection.${NC}" - return 1 - fi + # Check for qemu-nbd + if ! command -v qemu-nbd >/dev/null 2>&1; then + echo -e "${YELLOW}qemu-nbd not found. Install qemu-base to enable hosts file injection.${NC}" + return 1 + fi - echo -e "${BLUE}Injecting /etc/hosts into disk image for VM: ${vm_name}${NC}" + echo -e "${BLUE}Injecting /etc/hosts into disk image for VM: ${vm_name}${NC}" - # Load nbd module if needed - if [[ ! -e /dev/nbd0 ]]; then - modprobe nbd max_part=8 2>/dev/null || { - echo -e "${YELLOW}Could not load nbd kernel module${NC}" - return 1 - } - fi + # Load nbd module if needed + if [[ ! -e /dev/nbd0 ]]; then + modprobe nbd max_part=8 2>/dev/null || { + echo -e "${YELLOW}Could not load nbd kernel module${NC}" + return 1 + } + fi - # Find a free nbd device - local nbd_dev="" - for dev in /dev/nbd{0..15}; do - if [[ -e $dev ]] && ! lsblk "$dev" > /dev/null 2>&1; then - nbd_dev="$dev" - break - fi - done - # Fallback: try /dev/nbd0 if no device was found via lsblk check - if [[ -z $nbd_dev ]]; then - nbd_dev="/dev/nbd0" - fi + # Find a free nbd device + local nbd_dev="" + for dev in /dev/nbd{0..15}; do + if [[ -e $dev ]] && ! lsblk "$dev" >/dev/null 2>&1; then + nbd_dev="$dev" + break + fi + done + # Fallback: try /dev/nbd0 if no device was found via lsblk check + if [[ -z $nbd_dev ]]; then + nbd_dev="/dev/nbd0" + fi - local mount_point="/tmp/vbox_hosts_inject_$$" + local mount_point="/tmp/vbox_hosts_inject_$$" - # Connect disk image - qemu-nbd --connect="$nbd_dev" "$disk_path" 2>/dev/null || { - echo -e "${YELLOW}Could not connect disk image via qemu-nbd${NC}" - return 1 - } + # Connect disk image + qemu-nbd --connect="$nbd_dev" "$disk_path" 2>/dev/null || { + echo -e "${YELLOW}Could not connect disk image via qemu-nbd${NC}" + return 1 + } - # Wait for partitions to appear - sleep 1 - partprobe "$nbd_dev" 2>/dev/null || true + # Wait for partitions to appear + sleep 1 + partprobe "$nbd_dev" 2>/dev/null || true - # Find the root partition (first Linux partition) - local part="" - for p in "${nbd_dev}p1" "${nbd_dev}p2" "${nbd_dev}p3"; do - if [[ -b $p ]]; then - part="$p" - break - fi - done + # Find the root partition (first Linux partition) + local part="" + for p in "${nbd_dev}p1" "${nbd_dev}p2" "${nbd_dev}p3"; do + if [[ -b $p ]]; then + part="$p" + break + fi + done - if [[ -z $part ]]; then - echo -e "${YELLOW}No partitions found on disk image${NC}" - qemu-nbd --disconnect "$nbd_dev" 2>/dev/null || true - return 1 - fi + if [[ -z $part ]]; then + echo -e "${YELLOW}No partitions found on disk image${NC}" + qemu-nbd --disconnect "$nbd_dev" 2>/dev/null || true + return 1 + fi - # Mount the partition - mkdir -p "$mount_point" - if ! mount "$part" "$mount_point" 2>/dev/null; then - # Journal may need recovery — run e2fsck then retry - e2fsck -y "$part" > /dev/null 2>&1 || true - if ! mount "$part" "$mount_point" 2>/dev/null; then - echo -e "${YELLOW}Could not mount partition $part${NC}" - qemu-nbd --disconnect "$nbd_dev" 2>/dev/null || true - rmdir "$mount_point" 2>/dev/null || true - return 1 - fi - fi + # Mount the partition + mkdir -p "$mount_point" + if ! mount "$part" "$mount_point" 2>/dev/null; then + # Journal may need recovery — run e2fsck then retry + e2fsck -y "$part" >/dev/null 2>&1 || true + if ! mount "$part" "$mount_point" 2>/dev/null; then + echo -e "${YELLOW}Could not mount partition $part${NC}" + qemu-nbd --disconnect "$nbd_dev" 2>/dev/null || true + rmdir "$mount_point" 2>/dev/null || true + return 1 + fi + fi - # Check if this partition has /etc/hosts (i.e., it's the root fs) - if [[ ! -f "$mount_point/etc/hosts" ]]; then - echo -e "${YELLOW}Partition does not appear to be root filesystem (no /etc/hosts)${NC}" - umount "$mount_point" 2>/dev/null || true - qemu-nbd --disconnect "$nbd_dev" 2>/dev/null || true - rmdir "$mount_point" 2>/dev/null || true - return 1 - fi + # Check if this partition has /etc/hosts (i.e., it's the root fs) + if [[ ! -f "$mount_point/etc/hosts" ]]; then + echo -e "${YELLOW}Partition does not appear to be root filesystem (no /etc/hosts)${NC}" + umount "$mount_point" 2>/dev/null || true + qemu-nbd --disconnect "$nbd_dev" 2>/dev/null || true + rmdir "$mount_point" 2>/dev/null || true + return 1 + fi - # Backup original if not already backed up - if [[ ! -f "$mount_point/etc/hosts.original" ]]; then - cp "$mount_point/etc/hosts" "$mount_point/etc/hosts.original" - echo -e "${CYAN}Backed up original hosts file${NC}" - fi + # Backup original if not already backed up + if [[ ! -f "$mount_point/etc/hosts.original" ]]; then + cp "$mount_point/etc/hosts" "$mount_point/etc/hosts.original" + echo -e "${CYAN}Backed up original hosts file${NC}" + fi - # Copy host's /etc/hosts into VM - cp /etc/hosts "$mount_point/etc/hosts" - chmod 444 "$mount_point/etc/hosts" + # Copy host's /etc/hosts into VM + cp /etc/hosts "$mount_point/etc/hosts" + chmod 444 "$mount_point/etc/hosts" - local blocked_count - blocked_count="$(grep -c '0.0.0.0' "$mount_point/etc/hosts")" + local blocked_count + blocked_count="$(grep -c '0.0.0.0' "$mount_point/etc/hosts")" - # Cleanup: unmount and disconnect - umount "$mount_point" 2>/dev/null || true - qemu-nbd --disconnect "$nbd_dev" 2>/dev/null || true - rmdir "$mount_point" 2>/dev/null || true + # Cleanup: unmount and disconnect + umount "$mount_point" 2>/dev/null || true + qemu-nbd --disconnect "$nbd_dev" 2>/dev/null || true + rmdir "$mount_point" 2>/dev/null || true - echo -e "${GREEN}Hosts file injected into VM '${vm_name}' (${blocked_count} domains blocked)${NC}" - return 0 + echo -e "${GREEN}Hosts file injected into VM '${vm_name}' (${blocked_count} domains blocked)${NC}" + return 0 } # Apply enforcement to all VMs enforce_all_vms() { - local -a vms - mapfile -t vms < <(get_all_vms) + local -a vms + mapfile -t vms < <(get_all_vms) - if [[ ${#vms[@]} -eq 0 ]]; then - echo -e "${YELLOW}No VirtualBox VMs found.${NC}" - return 0 - fi + if [[ ${#vms[@]} -eq 0 ]]; then + echo -e "${YELLOW}No VirtualBox VMs found.${NC}" + return 0 + fi - echo -e "${CYAN}Found ${#vms[@]} VM(s). Applying /etc/hosts enforcement...${NC}" + echo -e "${CYAN}Found ${#vms[@]} VM(s). Applying /etc/hosts enforcement...${NC}" - local success=0 - local failed=0 + local success=0 + local failed=0 - for vm in "${vms[@]}"; do - echo -e "\n${BLUE}Processing VM: ${vm}${NC}" + for vm in "${vms[@]}"; do + echo -e "\n${BLUE}Processing VM: ${vm}${NC}" - # Configure DNS settings (works even when VM is running) - configure_vm_dns "$vm" + # Configure DNS settings (works even when VM is running) + configure_vm_dns "$vm" - # Try to configure shared folder (only works when VM is stopped) - if configure_hosts_shared_folder "$vm"; then - ((++success)) - else - ((++failed)) - echo -e "${YELLOW}Note: Stop the VM and run this script again to add shared folder${NC}" - fi + # Try to configure shared folder (only works when VM is stopped) + if configure_hosts_shared_folder "$vm"; then + ((++success)) + else + ((++failed)) + echo -e "${YELLOW}Note: Stop the VM and run this script again to add shared folder${NC}" + fi - # Inject hosts file directly into VM disk (the actual enforcement) - inject_hosts_into_vm_disk "$vm" || true - done + # Inject hosts file directly into VM disk (the actual enforcement) + inject_hosts_into_vm_disk "$vm" || true + done - echo -e "\n${GREEN}Enforcement complete!${NC}" - echo -e "Successfully configured: ${success} VM(s)" - [[ $failed -gt 0 ]] && echo -e "${YELLOW}Needs VM shutdown for full config: ${failed} VM(s)${NC}" + echo -e "\n${GREEN}Enforcement complete!${NC}" + echo -e "Successfully configured: ${success} VM(s)" + [[ $failed -gt 0 ]] && echo -e "${YELLOW}Needs VM shutdown for full config: ${failed} VM(s)${NC}" - # Mark that enforcement has been applied - touch "$HOSTS_ENFORCEMENT_MARKER" + # Mark that enforcement has been applied + touch "$HOSTS_ENFORCEMENT_MARKER" } # Check if a single VM has the shared folder configured vm_has_shared_folder() { - local vm_name="$1" - vboxmanage_as_user showvminfo "$vm_name" --machinereadable 2>/dev/null \ - | grep -q "SharedFolderNameMachineMapping.*=\"${VBOX_SHARED_FOLDER_NAME}\"" + local vm_name="$1" + vboxmanage_as_user showvminfo "$vm_name" --machinereadable 2>/dev/null | + grep -q "SharedFolderNameMachineMapping.*=\"${VBOX_SHARED_FOLDER_NAME}\"" } # Check if enforcement is applied to ALL registered VMs check_enforcement_status() { - local -a vms - mapfile -t vms < <(get_all_vms) + local -a vms + mapfile -t vms < <(get_all_vms) - if [[ ${#vms[@]} -eq 0 ]]; then - echo -e "${GREEN}No VMs to enforce.${NC}" - return 0 - fi + if [[ ${#vms[@]} -eq 0 ]]; then + echo -e "${GREEN}No VMs to enforce.${NC}" + return 0 + fi - for vm in "${vms[@]}"; do - if ! vm_has_shared_folder "$vm"; then - echo -e "${YELLOW}VM '${vm}' is missing hosts enforcement.${NC}" - return 1 - fi - done + for vm in "${vms[@]}"; do + if ! vm_has_shared_folder "$vm"; then + echo -e "${YELLOW}VM '${vm}' is missing hosts enforcement.${NC}" + return 1 + fi + done - echo -e "${GREEN}All ${#vms[@]} VM(s) have hosts enforcement applied.${NC}" - return 0 + echo -e "${GREEN}All ${#vms[@]} VM(s) have hosts enforcement applied.${NC}" + return 0 } # Show status show_status() { - echo -e "${CYAN}VirtualBox Hosts Enforcement Status${NC}" - echo -e "${CYAN}====================================${NC}\n" + echo -e "${CYAN}VirtualBox Hosts Enforcement Status${NC}" + echo -e "${CYAN}====================================${NC}\n" - local -a all_vms running_vms - mapfile -t all_vms < <(get_all_vms) - mapfile -t running_vms < <(get_running_vms) + local -a all_vms running_vms + mapfile -t all_vms < <(get_all_vms) + mapfile -t running_vms < <(get_running_vms) - echo -e "Total VMs: ${#all_vms[@]}" - echo -e "Running VMs: ${#running_vms[@]}" + echo -e "Total VMs: ${#all_vms[@]}" + echo -e "Running VMs: ${#running_vms[@]}" - if check_enforcement_status > /dev/null 2>&1; then - echo -e "Enforcement status: ${GREEN}Applied to all VMs${NC}" - else - echo -e "Enforcement status: ${RED}Not fully applied${NC}" - fi + if check_enforcement_status >/dev/null 2>&1; then + echo -e "Enforcement status: ${GREEN}Applied to all VMs${NC}" + else + echo -e "Enforcement status: ${RED}Not fully applied${NC}" + fi - echo -e "\n${CYAN}VMs:${NC}" - for vm in "${all_vms[@]}"; do - local flags="" - if printf '%s\n' "${running_vms[@]}" | grep -qx "$vm"; then - flags+=" ${GREEN}[RUNNING]${NC}" - fi - if vm_has_shared_folder "$vm"; then - flags+=" ${GREEN}[ENFORCED]${NC}" - else - flags+=" ${RED}[NOT ENFORCED]${NC}" - fi - echo -e " - ${vm}${flags}" - done + echo -e "\n${CYAN}VMs:${NC}" + for vm in "${all_vms[@]}"; do + local flags="" + if printf '%s\n' "${running_vms[@]}" | grep -qx "$vm"; then + flags+=" ${GREEN}[RUNNING]${NC}" + fi + if vm_has_shared_folder "$vm"; then + flags+=" ${GREEN}[ENFORCED]${NC}" + else + flags+=" ${RED}[NOT ENFORCED]${NC}" + fi + echo -e " - ${vm}${flags}" + done } # Main function main() { - local action="${1:-enforce}" + local action="${1:-enforce}" - case "$action" in - enforce|apply) - enforce_all_vms - ;; - check) - if check_enforcement_status; then - exit 0 - else - exit 1 - fi - ;; - status) - show_status - ;; - generate-script) - local output="${2:-/tmp/vbox_hosts_sync.sh}" - generate_vm_startup_script "$output" - ;; - *) - echo -e "${CYAN}VirtualBox /etc/hosts Enforcement Tool${NC}" - echo "" - echo "Usage: $0 [command]" - echo "" - echo "Commands:" - echo " enforce Apply /etc/hosts enforcement to all VMs (default)" - echo " check Check if enforcement has been applied" - echo " status Show current enforcement status" - echo " generate-script [path] Generate a script to place in VMs for hosts sync" - echo "" - echo "This tool configures VirtualBox VMs to:" - echo " 1. Use host's DNS resolution (via NAT DNS proxy)" - echo " 2. Share /etc from host (read-only) for hosts file access" - echo "" - exit 0 - ;; - esac + case "$action" in + enforce | apply) + enforce_all_vms + ;; + check) + if check_enforcement_status; then + exit 0 + else + exit 1 + fi + ;; + status) + show_status + ;; + generate-script) + local output="${2:-/tmp/vbox_hosts_sync.sh}" + generate_vm_startup_script "$output" + ;; + *) + echo -e "${CYAN}VirtualBox /etc/hosts Enforcement Tool${NC}" + echo "" + echo "Usage: $0 [command]" + echo "" + echo "Commands:" + echo " enforce Apply /etc/hosts enforcement to all VMs (default)" + echo " check Check if enforcement has been applied" + echo " status Show current enforcement status" + echo " generate-script [path] Generate a script to place in VMs for hosts sync" + echo "" + echo "This tool configures VirtualBox VMs to:" + echo " 1. Use host's DNS resolution (via NAT DNS proxy)" + echo " 2. Share /etc from host (read-only) for hosts file access" + echo "" + exit 0 + ;; + esac } main "$@" diff --git a/linux_configuration/scripts/fixes/diagnose_arch_performance.sh b/linux_configuration/scripts/fixes/diagnose_arch_performance.sh index 37ea37e..c98a966 100755 --- a/linux_configuration/scripts/fixes/diagnose_arch_performance.sh +++ b/linux_configuration/scripts/fixes/diagnose_arch_performance.sh @@ -15,7 +15,7 @@ declare -a FINDINGS=() declare -a ACTIONS=() usage() { - cat << 'EOF' + cat <<'EOF' diagnose_arch_performance.sh - Diagnose common causes of Arch Linux slowness/instability Usage: @@ -38,334 +38,334 @@ EOF } parse_args() { - while [[ $# -gt 0 ]]; do - case "$1" in - --apply-safe-fixes) - APPLY_SAFE_FIXES=true - shift - ;; - --install-tools) - INSTALL_TOOLS=true - shift - ;; - -h | --help) - usage - exit 0 - ;; - *) - log_error "Unknown option: $1" - usage - exit 2 - ;; - esac - done + while [[ $# -gt 0 ]]; do + case "$1" in + --apply-safe-fixes) + APPLY_SAFE_FIXES=true + shift + ;; + --install-tools) + INSTALL_TOOLS=true + shift + ;; + -h | --help) + usage + exit 0 + ;; + *) + log_error "Unknown option: $1" + usage + exit 2 + ;; + esac + done } add_finding() { - FINDINGS+=("$1") - log_warn "$1" + FINDINGS+=("$1") + log_warn "$1" } add_action() { - ACTIONS+=("$1") - log_info "$1" + ACTIONS+=("$1") + log_info "$1" } run_and_log() { - local header="$1" - shift - { - echo - echo "=== $header ===" - "$@" 2>&1 || true - } >> "$REPORT_FILE" + local header="$1" + shift + { + echo + echo "=== $header ===" + "$@" 2>&1 || true + } >>"$REPORT_FILE" } check_root_if_needed() { - if [[ $APPLY_SAFE_FIXES == "true" || $INSTALL_TOOLS == "true" ]]; then - require_root "$@" - fi + if [[ $APPLY_SAFE_FIXES == "true" || $INSTALL_TOOLS == "true" ]]; then + require_root "$@" + fi } install_optional_tools() { - if [[ $INSTALL_TOOLS != "true" ]]; then - return - fi + if [[ $INSTALL_TOOLS != "true" ]]; then + return + fi - local packages=(lm_sensors smartmontools nvtop iotop powertop) - log_info "Installing optional diagnostic packages: ${packages[*]}" - pacman -S --needed --noconfirm "${packages[@]}" + local packages=(lm_sensors smartmontools nvtop iotop powertop) + log_info "Installing optional diagnostic packages: ${packages[*]}" + pacman -S --needed --noconfirm "${packages[@]}" } collect_basics() { - run_and_log "Kernel" uname -a - run_and_log "Uptime" uptime - run_and_log "Memory" free -h - run_and_log "Swap" swapon --show - run_and_log "CPU (lscpu)" lscpu - run_and_log "Disk Usage" df -h / - run_and_log "Boot Time" systemd-analyze - run_and_log "Failed Units" systemctl --failed --no-pager - run_and_log "Recent Errors (this boot)" journalctl -b -p err --no-pager -n 200 + run_and_log "Kernel" uname -a + run_and_log "Uptime" uptime + run_and_log "Memory" free -h + run_and_log "Swap" swapon --show + run_and_log "CPU (lscpu)" lscpu + run_and_log "Disk Usage" df -h / + run_and_log "Boot Time" systemd-analyze + run_and_log "Failed Units" systemctl --failed --no-pager + run_and_log "Recent Errors (this boot)" journalctl -b -p err --no-pager -n 200 - local cpu_count - cpu_count=$(getconf _NPROCESSORS_ONLN 2> /dev/null || echo 1) - local load1 - load1=$(awk '{print int($1)}' /proc/loadavg 2> /dev/null || echo 0) - if [[ ${load1:-0} -ge ${cpu_count:-1} ]]; then - add_finding "1-minute load average is at/above CPU thread count (${load1}/${cpu_count}); background tasks may be saturating the system." - fi + local cpu_count + cpu_count=$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 1) + local load1 + load1=$(awk '{print int($1)}' /proc/loadavg 2>/dev/null || echo 0) + if [[ ${load1:-0} -ge ${cpu_count:-1} ]]; then + add_finding "1-minute load average is at/above CPU thread count (${load1}/${cpu_count}); background tasks may be saturating the system." + fi - local failed_count - failed_count=$(systemctl --failed --no-legend 2> /dev/null | wc -l || true) - failed_count=${failed_count//[[:space:]]/} - if [[ ${failed_count:-0} -gt 0 ]]; then - add_finding "One or more systemd units are failed (${failed_count}); failed services can cause repeated retries and instability." - fi + local failed_count + failed_count=$(systemctl --failed --no-legend 2>/dev/null | wc -l || true) + failed_count=${failed_count//[[:space:]]/} + if [[ ${failed_count:-0} -gt 0 ]]; then + add_finding "One or more systemd units are failed (${failed_count}); failed services can cause repeated retries and instability." + fi - local acpi_error_count - acpi_error_count=$(journalctl -b -p err --no-pager 2> /dev/null | grep -ic 'acpi' || true) - if [[ ${acpi_error_count:-0} -ge 5 ]]; then - add_finding "Frequent ACPI errors detected in current boot (${acpi_error_count}); BIOS/firmware update may improve stability." - fi + local acpi_error_count + acpi_error_count=$(journalctl -b -p err --no-pager 2>/dev/null | grep -ic 'acpi' || true) + if [[ ${acpi_error_count:-0} -ge 5 ]]; then + add_finding "Frequent ACPI errors detected in current boot (${acpi_error_count}); BIOS/firmware update may improve stability." + fi - local top_snapshot - top_snapshot=$(ps -eo pid,comm,%cpu,%mem --sort=-%cpu | head -n 12 || true) - { - echo - echo "=== Top CPU Processes ===" - echo "$top_snapshot" - } >> "$REPORT_FILE" + local top_snapshot + top_snapshot=$(ps -eo pid,comm,%cpu,%mem --sort=-%cpu | head -n 12 || true) + { + echo + echo "=== Top CPU Processes ===" + echo "$top_snapshot" + } >>"$REPORT_FILE" - local xorg_cpu - xorg_cpu=$(ps -C Xorg -o %cpu= | awk '{sum+=$1} END {printf "%.0f", sum+0}' || echo 0) - if [[ ${xorg_cpu:-0} -ge 20 ]]; then - add_finding "Xorg is using high CPU (${xorg_cpu}%); desktop/compositor/GPU driver path may be a primary slowdown source." - fi + local xorg_cpu + xorg_cpu=$(ps -C Xorg -o %cpu= | awk '{sum+=$1} END {printf "%.0f", sum+0}' || echo 0) + if [[ ${xorg_cpu:-0} -ge 20 ]]; then + add_finding "Xorg is using high CPU (${xorg_cpu}%); desktop/compositor/GPU driver path may be a primary slowdown source." + fi } check_cpu_governor() { - local gov_files - gov_files=$(find /sys/devices/system/cpu -maxdepth 3 -name scaling_governor 2> /dev/null || true) + local gov_files + gov_files=$(find /sys/devices/system/cpu -maxdepth 3 -name scaling_governor 2>/dev/null || true) - if [[ -z $gov_files ]]; then - add_action "CPU governor files not found (may be unsupported on this platform)." - return - fi + if [[ -z $gov_files ]]; then + add_action "CPU governor files not found (may be unsupported on this platform)." + return + fi - local summary - summary=$(awk '{count[$1]++} END {for (g in count) printf "%s:%d ", g, count[g]}' $gov_files 2> /dev/null || true) - echo "CPU governor summary: ${summary:-unknown}" >> "$REPORT_FILE" + local summary + summary=$(awk '{count[$1]++} END {for (g in count) printf "%s:%d ", g, count[g]}' $gov_files 2>/dev/null || true) + echo "CPU governor summary: ${summary:-unknown}" >>"$REPORT_FILE" - if grep -q '^powersave$' $gov_files 2> /dev/null; then - add_finding "CPU governor includes 'powersave' on one or more cores; this can make high-end hardware feel slow." - fi + if grep -q '^powersave$' $gov_files 2>/dev/null; then + add_finding "CPU governor includes 'powersave' on one or more cores; this can make high-end hardware feel slow." + fi } check_thermal_state() { - if has_cmd sensors; then - run_and_log "Temperatures (sensors)" sensors - else - add_action "Install lm_sensors and run 'sensors' to verify thermal throttling." - fi + if has_cmd sensors; then + run_and_log "Temperatures (sensors)" sensors + else + add_action "Install lm_sensors and run 'sensors' to verify thermal throttling." + fi - if has_cmd dmesg; then - local therm_hits - therm_hits=$(dmesg | grep -Ei 'throttl|thermal|overheat|cpu clock throttled' | tail -n 30 || true) - if [[ -n $therm_hits ]]; then - add_finding "Kernel logs show thermal/throttling related messages." - { - echo - echo "=== Thermal/Throttling dmesg excerpts ===" - echo "$therm_hits" - } >> "$REPORT_FILE" - fi - fi + if has_cmd dmesg; then + local therm_hits + therm_hits=$(dmesg | grep -Ei 'throttl|thermal|overheat|cpu clock throttled' | tail -n 30 || true) + if [[ -n $therm_hits ]]; then + add_finding "Kernel logs show thermal/throttling related messages." + { + echo + echo "=== Thermal/Throttling dmesg excerpts ===" + echo "$therm_hits" + } >>"$REPORT_FILE" + fi + fi } check_power_services() { - local tlp_enabled="false" - local ppd_enabled="false" + local tlp_enabled="false" + local ppd_enabled="false" - if systemctl is-enabled tlp.service > /dev/null 2>&1; then - tlp_enabled="true" - fi - if systemctl is-enabled power-profiles-daemon.service > /dev/null 2>&1; then - ppd_enabled="true" - fi + if systemctl is-enabled tlp.service >/dev/null 2>&1; then + tlp_enabled="true" + fi + if systemctl is-enabled power-profiles-daemon.service >/dev/null 2>&1; then + ppd_enabled="true" + fi - echo "Power services: tlp=${tlp_enabled}, power-profiles-daemon=${ppd_enabled}" >> "$REPORT_FILE" + echo "Power services: tlp=${tlp_enabled}, power-profiles-daemon=${ppd_enabled}" >>"$REPORT_FILE" - if [[ $tlp_enabled == "true" && $ppd_enabled == "true" ]]; then - add_finding "Both TLP and power-profiles-daemon are enabled; they often conflict and cause inconsistent performance." - fi + if [[ $tlp_enabled == "true" && $ppd_enabled == "true" ]]; then + add_finding "Both TLP and power-profiles-daemon are enabled; they often conflict and cause inconsistent performance." + fi - if [[ $tlp_enabled == "false" && $ppd_enabled == "false" ]]; then - add_action "No power management daemon is enabled; consider installing/enabling power-profiles-daemon for predictable AC/battery behavior." - fi + if [[ $tlp_enabled == "false" && $ppd_enabled == "false" ]]; then + add_action "No power management daemon is enabled; consider installing/enabling power-profiles-daemon for predictable AC/battery behavior." + fi } check_storage_health() { - run_and_log "Block Devices" lsblk -o NAME,MODEL,ROTA,SIZE,TYPE,MOUNTPOINT,FSTYPE + run_and_log "Block Devices" lsblk -o NAME,MODEL,ROTA,SIZE,TYPE,MOUNTPOINT,FSTYPE - if has_cmd fstrim; then - run_and_log "fstrim dry-run" fstrim -av --dry-run - fi + if has_cmd fstrim; then + run_and_log "fstrim dry-run" fstrim -av --dry-run + fi - if systemctl is-enabled fstrim.timer > /dev/null 2>&1; then - add_action "fstrim.timer is enabled (good for SSD performance longevity)." - else - add_finding "fstrim.timer is not enabled; SSD maintenance trimming may be missing." - fi + if systemctl is-enabled fstrim.timer >/dev/null 2>&1; then + add_action "fstrim.timer is enabled (good for SSD performance longevity)." + else + add_finding "fstrim.timer is not enabled; SSD maintenance trimming may be missing." + fi - if has_cmd smartctl; then - local root_disk - root_disk=$(findmnt -n -o SOURCE / | sed 's/[0-9]*$//' | sed 's/p$//' || true) - if [[ -n ${root_disk:-} && -b $root_disk ]]; then - run_and_log "SMART Summary ($root_disk)" smartctl -H "$root_disk" - fi - else - add_action "Install smartmontools and run SMART health checks for your SSD/NVMe." - fi + if has_cmd smartctl; then + local root_disk + root_disk=$(findmnt -n -o SOURCE / | sed 's/[0-9]*$//' | sed 's/p$//' || true) + if [[ -n ${root_disk:-} && -b $root_disk ]]; then + run_and_log "SMART Summary ($root_disk)" smartctl -H "$root_disk" + fi + else + add_action "Install smartmontools and run SMART health checks for your SSD/NVMe." + fi } check_memory_pressure() { - local mem_total mem_available swap_total swap_free - mem_total=$(awk '/MemTotal/ {print $2}' /proc/meminfo) - mem_available=$(awk '/MemAvailable/ {print $2}' /proc/meminfo) - swap_total=$(awk '/SwapTotal/ {print $2}' /proc/meminfo) - swap_free=$(awk '/SwapFree/ {print $2}' /proc/meminfo) + local mem_total mem_available swap_total swap_free + mem_total=$(awk '/MemTotal/ {print $2}' /proc/meminfo) + mem_available=$(awk '/MemAvailable/ {print $2}' /proc/meminfo) + swap_total=$(awk '/SwapTotal/ {print $2}' /proc/meminfo) + swap_free=$(awk '/SwapFree/ {print $2}' /proc/meminfo) - if [[ ${swap_total:-0} -gt 0 ]]; then - local swap_used - swap_used=$((swap_total - swap_free)) - local swap_pct - swap_pct=$((swap_used * 100 / swap_total)) - echo "Swap usage: ${swap_pct}%" >> "$REPORT_FILE" - if [[ $swap_pct -ge 35 && ${mem_available:-0} -gt $((mem_total / 3)) ]]; then - add_finding "High swap usage while RAM is still available; this can cause stutter." - add_action "Consider lowering swappiness (temporary: sudo sysctl vm.swappiness=10)." - fi - fi + if [[ ${swap_total:-0} -gt 0 ]]; then + local swap_used + swap_used=$((swap_total - swap_free)) + local swap_pct + swap_pct=$((swap_used * 100 / swap_total)) + echo "Swap usage: ${swap_pct}%" >>"$REPORT_FILE" + if [[ $swap_pct -ge 35 && ${mem_available:-0} -gt $((mem_total / 3)) ]]; then + add_finding "High swap usage while RAM is still available; this can cause stutter." + add_action "Consider lowering swappiness (temporary: sudo sysctl vm.swappiness=10)." + fi + fi - if [[ -f /proc/pressure/memory ]]; then - run_and_log "Memory PSI" cat /proc/pressure/memory - fi + if [[ -f /proc/pressure/memory ]]; then + run_and_log "Memory PSI" cat /proc/pressure/memory + fi } check_gpu_state() { - if has_cmd nvidia-smi; then - run_and_log "NVIDIA State" nvidia-smi - local pstate util power - pstate=$(nvidia-smi --query-gpu=pstate --format=csv,noheader 2> /dev/null | head -n 1 | xargs || true) - util=$(nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader,nounits 2> /dev/null | head -n 1 | xargs || true) - power=$(nvidia-smi --query-gpu=power.draw --format=csv,noheader,nounits 2> /dev/null | head -n 1 | xargs || true) + if has_cmd nvidia-smi; then + run_and_log "NVIDIA State" nvidia-smi + local pstate util power + pstate=$(nvidia-smi --query-gpu=pstate --format=csv,noheader 2>/dev/null | head -n 1 | xargs || true) + util=$(nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader,nounits 2>/dev/null | head -n 1 | xargs || true) + power=$(nvidia-smi --query-gpu=power.draw --format=csv,noheader,nounits 2>/dev/null | head -n 1 | xargs || true) - echo "NVIDIA pstate: ${pstate:-unknown}" >> "$REPORT_FILE" - echo "NVIDIA util: ${util:-unknown}%" >> "$REPORT_FILE" - echo "NVIDIA power: ${power:-unknown}W" >> "$REPORT_FILE" + echo "NVIDIA pstate: ${pstate:-unknown}" >>"$REPORT_FILE" + echo "NVIDIA util: ${util:-unknown}%" >>"$REPORT_FILE" + echo "NVIDIA power: ${power:-unknown}W" >>"$REPORT_FILE" - if [[ ${pstate:-} == "P0" && ${util:-100} -le 5 ]]; then - add_finding "NVIDIA GPU is in P0 high-performance state while mostly idle; this can increase heat and trigger thermal limits." - add_action "If laptop has hybrid graphics, prefer iGPU mode for desktop workloads and use dGPU on demand." - fi - else - run_and_log "PCI VGA Devices" lspci -nnk | grep -A3 -Ei 'vga|3d|display' - fi + if [[ ${pstate:-} == "P0" && ${util:-100} -le 5 ]]; then + add_finding "NVIDIA GPU is in P0 high-performance state while mostly idle; this can increase heat and trigger thermal limits." + add_action "If laptop has hybrid graphics, prefer iGPU mode for desktop workloads and use dGPU on demand." + fi + else + run_and_log "PCI VGA Devices" lspci -nnk | grep -A3 -Ei 'vga|3d|display' + fi } check_journal_size() { - local journal_line - journal_line=$(journalctl --disk-usage 2> /dev/null || true) - echo "Journal usage: ${journal_line:-unknown}" >> "$REPORT_FILE" + local journal_line + journal_line=$(journalctl --disk-usage 2>/dev/null || true) + echo "Journal usage: ${journal_line:-unknown}" >>"$REPORT_FILE" - if [[ $journal_line =~ ([0-9]+\.?[0-9]*)\ (G|M) ]]; then - local value unit - value="${BASH_REMATCH[1]}" - unit="${BASH_REMATCH[2]}" - if [[ $unit == "G" ]]; then - add_finding "Systemd journal is large (${value}G); excessive logs can waste I/O and disk space." - fi - fi + if [[ $journal_line =~ ([0-9]+\.?[0-9]*)\ (G|M) ]]; then + local value unit + value="${BASH_REMATCH[1]}" + unit="${BASH_REMATCH[2]}" + if [[ $unit == "G" ]]; then + add_finding "Systemd journal is large (${value}G); excessive logs can waste I/O and disk space." + fi + fi } apply_safe_fixes() { - if [[ $APPLY_SAFE_FIXES != "true" ]]; then - return - fi + if [[ $APPLY_SAFE_FIXES != "true" ]]; then + return + fi - log_info "Applying safe fixes..." + log_info "Applying safe fixes..." - if ! systemctl is-enabled fstrim.timer > /dev/null 2>&1; then - systemctl enable --now fstrim.timer - add_action "Enabled and started fstrim.timer." - fi + if ! systemctl is-enabled fstrim.timer >/dev/null 2>&1; then + systemctl enable --now fstrim.timer + add_action "Enabled and started fstrim.timer." + fi - if systemctl is-enabled tlp.service > /dev/null 2>&1 && systemctl is-enabled power-profiles-daemon.service > /dev/null 2>&1; then - systemctl disable --now tlp.service - add_action "Disabled tlp.service to avoid conflict with power-profiles-daemon." - fi + if systemctl is-enabled tlp.service >/dev/null 2>&1 && systemctl is-enabled power-profiles-daemon.service >/dev/null 2>&1; then + systemctl disable --now tlp.service + add_action "Disabled tlp.service to avoid conflict with power-profiles-daemon." + fi - local journal_line - journal_line=$(journalctl --disk-usage 2> /dev/null || true) - if [[ $journal_line =~ ([0-9]+\.?[0-9]*)\ G ]]; then - journalctl --vacuum-size=300M - add_action "Vacuumed systemd journal to 300M." - fi + local journal_line + journal_line=$(journalctl --disk-usage 2>/dev/null || true) + if [[ $journal_line =~ ([0-9]+\.?[0-9]*)\ G ]]; then + journalctl --vacuum-size=300M + add_action "Vacuumed systemd journal to 300M." + fi } print_summary() { - echo - echo "==============================" - echo " Arch Performance Diagnostics" - echo "==============================" - echo "Report: $REPORT_FILE" - echo + echo + echo "==============================" + echo " Arch Performance Diagnostics" + echo "==============================" + echo "Report: $REPORT_FILE" + echo - if [[ ${#FINDINGS[@]} -eq 0 ]]; then - log_ok "No high-confidence bottlenecks detected by automated checks." - else - log_warn "Likely issues found (${#FINDINGS[@]}):" - local item - for item in "${FINDINGS[@]}"; do - echo " - $item" - done - fi + if [[ ${#FINDINGS[@]} -eq 0 ]]; then + log_ok "No high-confidence bottlenecks detected by automated checks." + else + log_warn "Likely issues found (${#FINDINGS[@]}):" + local item + for item in "${FINDINGS[@]}"; do + echo " - $item" + done + fi - if [[ ${#ACTIONS[@]} -gt 0 ]]; then - echo - log_info "Actions/recommendations:" - local action - for action in "${ACTIONS[@]}"; do - echo " - $action" - done - fi + if [[ ${#ACTIONS[@]} -gt 0 ]]; then + echo + log_info "Actions/recommendations:" + local action + for action in "${ACTIONS[@]}"; do + echo " - $action" + done + fi - echo - echo "Recommended next command for deep per-process analysis:" - echo " sudo iotop -oPa" - echo " top" - echo " systemd-analyze blame" + echo + echo "Recommended next command for deep per-process analysis:" + echo " sudo iotop -oPa" + echo " top" + echo " systemd-analyze blame" } main() { - parse_args "$@" - check_root_if_needed "$@" + parse_args "$@" + check_root_if_needed "$@" - mkdir -p "$REPORT_DIR" - log_info "Writing diagnostic report to: $REPORT_FILE" + mkdir -p "$REPORT_DIR" + log_info "Writing diagnostic report to: $REPORT_FILE" - collect_basics - install_optional_tools - check_cpu_governor - check_thermal_state - check_power_services - check_storage_health - check_memory_pressure - check_gpu_state - check_journal_size - apply_safe_fixes - print_summary + collect_basics + install_optional_tools + check_cpu_governor + check_thermal_state + check_power_services + check_storage_health + check_memory_pressure + check_gpu_state + check_journal_size + apply_safe_fixes + print_summary } main "$@" diff --git a/linux_configuration/scripts/fixes/fix_arch_performance.sh b/linux_configuration/scripts/fixes/fix_arch_performance.sh index b20cae6..5876acb 100755 --- a/linux_configuration/scripts/fixes/fix_arch_performance.sh +++ b/linux_configuration/scripts/fixes/fix_arch_performance.sh @@ -30,12 +30,12 @@ shift "$COMMON_ARGS_SHIFT" DRY_RUN=false for arg in "$@"; do - case "$arg" in - --dry-run) - DRY_RUN=true - ;; - -h | --help) - cat << 'EOF' + case "$arg" in + --dry-run) + DRY_RUN=true + ;; + -h | --help) + cat <<'EOF' fix_arch_performance.sh - Fix common Arch Linux laptop performance issues Usage: fix_arch_performance.sh [OPTIONS] @@ -55,9 +55,9 @@ Fixes applied: All fixes are idempotent and safe to re-run. Xorg fixes require reboot/re-login to take effect. EOF - exit 0 - ;; - esac + exit 0 + ;; + esac done require_root "$@" @@ -71,53 +71,53 @@ FIXES_SKIPPED=0 # Helper: run or print a fix depending on --dry-run / --interactive # --------------------------------------------------------------------------- apply_fix() { - local description="$1" - shift + local description="$1" + shift - echo "" - log_info "$description" + echo "" + log_info "$description" - if [[ $DRY_RUN == "true" ]]; then - echo " [dry-run] Would run: $*" - return 0 - fi + 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 [[ $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 + if "$@"; then + log_ok "Done." + ((FIXES_APPLIED++)) || true + else + log_error "Failed (non-fatal, continuing)." + fi } # =================================================================== # Fix 1: NVIDIA RenderAccel # =================================================================== fix_nvidia_render_accel() { - local conf="/etc/X11/xorg.conf.d/20-nvidia.conf" + local conf="/etc/X11/xorg.conf.d/20-nvidia.conf" - # Check if RenderAccel is already correct - if [[ -f $conf ]] && grep -qi 'RenderAccel.*true' "$conf"; then - log_ok "NVIDIA RenderAccel is already enabled — skipping." - return 0 - fi + # Check if RenderAccel is already correct + if [[ -f $conf ]] && grep -qi 'RenderAccel.*true' "$conf"; then + log_ok "NVIDIA RenderAccel is already enabled — skipping." + return 0 + fi - mkdir -p /etc/X11/xorg.conf.d + mkdir -p /etc/X11/xorg.conf.d - # Back up the current config if it exists and has the bad setting - if [[ -f $conf ]]; then - cp "$conf" "${conf}.bak.$(date +%Y%m%d_%H%M%S)" - fi + # Back up the current config if it exists and has the bad setting + if [[ -f $conf ]]; then + cp "$conf" "${conf}.bak.$(date +%Y%m%d_%H%M%S)" + fi - cat > "$conf" << 'XORGEOF' + cat >"$conf" <<'XORGEOF' # NVIDIA configuration - hardware acceleration enabled # Disabling RenderAccel forces Xorg into software rendering, # causing 30%+ CPU usage on desktop. Keep this set to "true". @@ -128,131 +128,131 @@ Section "Device" EndSection XORGEOF - # Clean up old backups left by nvidia_troubleshoot.sh - rm -f /etc/X11/xorg.conf.d/20-nvidia.conf.backup.* 2> /dev/null || true - return 0 + # Clean up old backups left by nvidia_troubleshoot.sh + rm -f /etc/X11/xorg.conf.d/20-nvidia.conf.backup.* 2>/dev/null || true + return 0 } # =================================================================== # Fix 2: Power management daemon + performance profile # =================================================================== fix_power_management() { - # Install power-profiles-daemon if missing - if ! pacman -Qi power-profiles-daemon > /dev/null 2>&1; then - log_info "Installing power-profiles-daemon..." - pacman -S --needed --noconfirm power-profiles-daemon - fi + # Install power-profiles-daemon if missing + if ! pacman -Qi power-profiles-daemon >/dev/null 2>&1; then + log_info "Installing power-profiles-daemon..." + pacman -S --needed --noconfirm power-profiles-daemon + fi - # Enable and start the service - if ! systemctl is-enabled power-profiles-daemon.service > /dev/null 2>&1; then - systemctl enable --now power-profiles-daemon.service - elif ! systemctl is-active power-profiles-daemon.service > /dev/null 2>&1; then - systemctl start power-profiles-daemon.service - fi + # Enable and start the service + if ! systemctl is-enabled power-profiles-daemon.service >/dev/null 2>&1; then + systemctl enable --now power-profiles-daemon.service + elif ! systemctl is-active power-profiles-daemon.service >/dev/null 2>&1; then + systemctl start power-profiles-daemon.service + fi - # Resolve TLP conflict if both are enabled - if systemctl is-enabled tlp.service > /dev/null 2>&1; then - log_warn "TLP conflicts with power-profiles-daemon — disabling TLP." - systemctl disable --now tlp.service - fi + # Resolve TLP conflict if both are enabled + if systemctl is-enabled tlp.service >/dev/null 2>&1; then + log_warn "TLP conflicts with power-profiles-daemon — disabling TLP." + systemctl disable --now tlp.service + fi - # Set performance profile (appropriate when plugged in with strong hardware) - sleep 1 - if has_cmd powerprofilesctl; then - powerprofilesctl set performance - log_info "Power profile set to: $(powerprofilesctl get)" - fi + # Set performance profile (appropriate when plugged in with strong hardware) + sleep 1 + if has_cmd powerprofilesctl; then + powerprofilesctl set performance + log_info "Power profile set to: $(powerprofilesctl get)" + fi - return 0 + return 0 } # =================================================================== # Fix 3: Journal vacuum + permanent size cap # =================================================================== fix_journal() { - local usage_line - usage_line=$(journalctl --disk-usage 2> /dev/null || true) + 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 + 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 is already under 1GiB." - fi + if [[ $needs_vacuum == "true" ]]; then + journalctl --vacuum-size=300M + else + log_ok "Journal is already under 1GiB." + fi - # Create permanent size cap via drop-in - local dropin_dir="/etc/systemd/journald.conf.d" - local dropin_file="$dropin_dir/size-limit.conf" + # 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." - else - mkdir -p "$dropin_dir" - cat > "$dropin_file" << 'JOURNALEOF' + 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 + systemctl restart systemd-journald + fi - return 0 + return 0 } # =================================================================== # Fix 4: Disable NetworkManager-wait-online # =================================================================== 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 + 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 - return 0 + systemctl disable NetworkManager-wait-online.service + return 0 } # =================================================================== # Fix 5: media-organizer.service # =================================================================== fix_media_organizer() { - local service_file="/etc/systemd/system/media-organizer.service" + local service_file="/etc/systemd/system/media-organizer.service" - # Find the organize_downloads.sh script - local script_path="" - local candidates=( - "/home/kuhy/testsAndMisc/linux_configuration/scripts/utils/organize_downloads.sh" - "/home/kuhy/linux-configuration/scripts/utils/organize_downloads.sh" - ) - for candidate in "${candidates[@]}"; do - if [[ -f $candidate ]]; then - script_path="$candidate" - break - fi - done + # Find the organize_downloads.sh script + local script_path="" + local candidates=( + "/home/kuhy/testsAndMisc/linux_configuration/scripts/utils/organize_downloads.sh" + "/home/kuhy/linux-configuration/scripts/utils/organize_downloads.sh" + ) + for candidate in "${candidates[@]}"; do + if [[ -f $candidate ]]; then + script_path="$candidate" + break + fi + done - if [[ -z $script_path ]]; then - log_warn "organize_downloads.sh not found — skipping media-organizer fix." - return 0 - fi + if [[ -z $script_path ]]; then + log_warn "organize_downloads.sh not found — skipping media-organizer fix." + return 0 + fi - local target_user="${SUDO_USER:-kuhy}" + local target_user="${SUDO_USER:-kuhy}" - # Check if already correct - if [[ -f $service_file ]]; then - if grep -q "User=$target_user" "$service_file" \ - && grep -q "ExecStart=$script_path" "$service_file"; then - log_ok "media-organizer.service is already correctly configured — skipping." - return 0 - fi - fi + # Check if already correct + if [[ -f $service_file ]]; then + if grep -q "User=$target_user" "$service_file" && + grep -q "ExecStart=$script_path" "$service_file"; then + log_ok "media-organizer.service is already correctly configured — skipping." + return 0 + fi + fi - systemctl stop media-organizer.service 2> /dev/null || true + systemctl stop media-organizer.service 2>/dev/null || true - cat > "$service_file" << EOF + cat >"$service_file" < /dev/null || true - systemctl enable media-organizer.service - return 0 + systemctl daemon-reload + systemctl reset-failed media-organizer.service 2>/dev/null || true + systemctl enable media-organizer.service + return 0 } # =================================================================== # Apply all fixes # =================================================================== main() { - apply_fix \ - "Fix 1/5: Enable NVIDIA hardware acceleration (RenderAccel → true)" \ - fix_nvidia_render_accel + apply_fix \ + "Fix 1/5: Enable NVIDIA hardware acceleration (RenderAccel → true)" \ + fix_nvidia_render_accel - apply_fix \ - "Fix 2/5: Install/enable power-profiles-daemon + set performance profile" \ - fix_power_management + apply_fix \ + "Fix 2/5: Install/enable power-profiles-daemon + set performance profile" \ + fix_power_management - apply_fix \ - "Fix 3/5: Vacuum journal logs + set permanent 300M size cap" \ - fix_journal + apply_fix \ + "Fix 3/5: Vacuum journal logs + set permanent 300M size cap" \ + fix_journal - apply_fix \ - "Fix 4/5: Disable NetworkManager-wait-online.service (~6s boot saving)" \ - fix_nm_wait_online + apply_fix \ + "Fix 4/5: Disable NetworkManager-wait-online.service (~6s boot saving)" \ + fix_nm_wait_online - apply_fix \ - "Fix 5/5: Fix media-organizer.service (correct path and user)" \ - fix_media_organizer + apply_fix \ + "Fix 5/5: Fix media-organizer.service (correct path and user)" \ + fix_media_organizer - # --------------------------------------------------------------- - # Summary - # --------------------------------------------------------------- - echo "" - echo "==============================" - echo " Performance Fix Summary" - echo "==============================" + # --------------------------------------------------------------- + # 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 - fi + 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 + fi - echo "" - log_info "Reboot or re-login for xorg changes (Fix 1) to take effect." - log_info "After reboot, verify with: diagnose_arch_performance.sh" + echo "" + log_info "Reboot or re-login for xorg changes (Fix 1) to take effect." + log_info "After reboot, verify with: diagnose_arch_performance.sh" } main diff --git a/linux_configuration/scripts/fixes/fix_systemctl.sh b/linux_configuration/scripts/fixes/fix_systemctl.sh index 269caa0..5a33298 100755 --- a/linux_configuration/scripts/fixes/fix_systemctl.sh +++ b/linux_configuration/scripts/fixes/fix_systemctl.sh @@ -14,39 +14,39 @@ SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service" DEFAULT_ORGANIZE_SCRIPT="/home/kuhy/testsAndMisc/linux_configuration/scripts/utils/organize_downloads.sh" LEGACY_ORGANIZE_SCRIPT="/home/kuhy/linux-configuration/scripts/utils/organize_downloads.sh" if [[ -f $DEFAULT_ORGANIZE_SCRIPT ]]; then - ORGANIZE_SCRIPT="$DEFAULT_ORGANIZE_SCRIPT" + ORGANIZE_SCRIPT="$DEFAULT_ORGANIZE_SCRIPT" elif [[ -f $LEGACY_ORGANIZE_SCRIPT ]]; then - ORGANIZE_SCRIPT="$LEGACY_ORGANIZE_SCRIPT" + ORGANIZE_SCRIPT="$LEGACY_ORGANIZE_SCRIPT" else - ORGANIZE_SCRIPT="$DEFAULT_ORGANIZE_SCRIPT" + ORGANIZE_SCRIPT="$DEFAULT_ORGANIZE_SCRIPT" fi TARGET_USER="${SUDO_USER:-kuhy}" log() { - echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" } # Check if running as root if [[ $EUID -ne 0 ]]; then - log "This script needs to be run as root." - log "Re-executing with sudo..." - exec sudo "$0" "$@" + log "This script needs to be run as root." + log "Re-executing with sudo..." + exec sudo "$0" "$@" fi log "Fixing media-organizer.service..." # Verify the organize_downloads.sh script exists if [[ ! -f $ORGANIZE_SCRIPT ]]; then - log "ERROR: organize_downloads.sh not found at $ORGANIZE_SCRIPT" - exit 1 + log "ERROR: organize_downloads.sh not found at $ORGANIZE_SCRIPT" + exit 1 fi # Stop the service if running (ignore errors) -systemctl stop "$SERVICE_NAME.service" 2> /dev/null || true +systemctl stop "$SERVICE_NAME.service" 2>/dev/null || true # Recreate the service file with correct configuration -cat > "$SERVICE_FILE" << EOF +cat >"$SERVICE_FILE" < /dev/null || true +systemctl reset-failed "$SERVICE_NAME.service" 2>/dev/null || true log "Reset failed state" # Re-enable the service @@ -82,9 +82,9 @@ log "Service enabled" # Optionally start the service to verify it works log "Starting service to verify fix..." if systemctl start "$SERVICE_NAME.service"; then - log "SUCCESS: media-organizer.service started successfully!" + log "SUCCESS: media-organizer.service started successfully!" else - log "WARNING: Service still has issues. Check: journalctl -u $SERVICE_NAME" + log "WARNING: Service still has issues. Check: journalctl -u $SERVICE_NAME" fi # Show current status diff --git a/linux_configuration/scripts/fixes/nvidia_troubleshoot.sh b/linux_configuration/scripts/fixes/nvidia_troubleshoot.sh index 142b8f2..2e64862 100755 --- a/linux_configuration/scripts/fixes/nvidia_troubleshoot.sh +++ b/linux_configuration/scripts/fixes/nvidia_troubleshoot.sh @@ -21,7 +21,7 @@ print_setup_header "NVIDIA Comprehensive Troubleshooter & GSP Disabler" # Check if nvidia module is loaded if ! lsmod | grep -q nvidia; then - echo "Warning: NVIDIA module not currently loaded" + echo "Warning: NVIDIA module not currently loaded" fi # Create modprobe configuration directory if it doesn't exist @@ -34,7 +34,7 @@ echo "======================================" mkdir -p "$MODPROBE_DIR" # Create the configuration file -cat > "$CONFIG_FILE" << EOF +cat >"$CONFIG_FILE" < "$NVIDIA_CONF" << EOF + # Create NVIDIA-specific configuration + # NOTE: RenderAccel must be "true" (or omitted, since it defaults to true). + # Setting it to "false" forces software rendering, causing Xorg to consume + # 30%+ CPU on the desktop and making the system feel extremely sluggish. + cat >"$NVIDIA_CONF" <> "$PROFILE_FILE" - echo "✓ Added IGNORE_CC_MISMATCH=1 to $PROFILE_FILE" - else - echo "✓ IGNORE_CC_MISMATCH already configured in $PROFILE_FILE" - fi + # Check if IGNORE_CC_MISMATCH is already set + if ! grep -q "IGNORE_CC_MISMATCH" "$PROFILE_FILE"; then + { + printf '\n' + printf '# NVIDIA GCC version mismatch workaround\n' + printf '# Added by nvidia_troubleshoot.sh on %s\n' "$timestamp" + printf 'export IGNORE_CC_MISMATCH=1\n' + } >>"$PROFILE_FILE" + echo "✓ Added IGNORE_CC_MISMATCH=1 to $PROFILE_FILE" + else + echo "✓ IGNORE_CC_MISMATCH already configured in $PROFILE_FILE" + fi } # Function to install pyroveil for mesh shader issues install_pyroveil() { - echo "" - echo "4. Pyroveil Setup for Mesh Shader Issues..." - echo "===========================================" + echo "" + echo "4. Pyroveil Setup for Mesh Shader Issues..." + echo "===========================================" - local user_home="/home/$SUDO_USER" - local pyroveil_dir="$user_home/pyroveil" + local user_home="/home/$SUDO_USER" + local pyroveil_dir="$user_home/pyroveil" - echo "Mesh shaders have poor support on NVIDIA drivers, causing issues in games" - echo "like Final Fantasy VII Rebirth. Pyroveil can work around these problems." - echo "" + echo "Mesh shaders have poor support on NVIDIA drivers, causing issues in games" + echo "like Final Fantasy VII Rebirth. Pyroveil can work around these problems." + echo "" - local install_pyroveil=true + local install_pyroveil=true - if [[ $INTERACTIVE_MODE == "true" ]]; then - read -p "Would you like to install Pyroveil? (y/N): " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Yy]$ ]]; then - install_pyroveil=false - fi - else - echo "Auto-installing Pyroveil (use --interactive to prompt)" - fi + if [[ $INTERACTIVE_MODE == "true" ]]; then + read -p "Would you like to install Pyroveil? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + install_pyroveil=false + fi + else + echo "Auto-installing Pyroveil (use --interactive to prompt)" + fi - if [[ $install_pyroveil == "true" ]]; then - # Check for required dependencies - local missing_deps=() + if [[ $install_pyroveil == "true" ]]; then + # Check for required dependencies + local missing_deps=() - for dep in git cmake ninja gcc; do - if ! command -v "$dep" &> /dev/null; then - missing_deps+=("$dep") - fi - done + for dep in git cmake ninja gcc; do + if ! command -v "$dep" &>/dev/null; then + missing_deps+=("$dep") + fi + done - if [[ ${#missing_deps[@]} -gt 0 ]]; then - echo "Missing dependencies: ${missing_deps[*]}" - echo "Please install them first. On Arch Linux:" - echo "pacman -S base-devel git cmake ninja" - return 1 - fi + if [[ ${#missing_deps[@]} -gt 0 ]]; then + echo "Missing dependencies: ${missing_deps[*]}" + echo "Please install them first. On Arch Linux:" + echo "pacman -S base-devel git cmake ninja" + return 1 + fi - # Clone and build pyroveil as the original user - echo "Installing Pyroveil to $pyroveil_dir..." + # Clone and build pyroveil as the original user + echo "Installing Pyroveil to $pyroveil_dir..." - if [[ -d $pyroveil_dir ]]; then - echo "Pyroveil directory already exists. Updating..." - sudo -u "$SUDO_USER" bash -c "cd '$pyroveil_dir' && git pull" - else - sudo -u "$SUDO_USER" git clone https://github.com/HansKristian-Work/pyroveil.git "$pyroveil_dir" - fi + if [[ -d $pyroveil_dir ]]; then + echo "Pyroveil directory already exists. Updating..." + sudo -u "$SUDO_USER" bash -c "cd '$pyroveil_dir' && git pull" + else + sudo -u "$SUDO_USER" git clone https://github.com/HansKristian-Work/pyroveil.git "$pyroveil_dir" + fi - sudo -u "$SUDO_USER" bash -c " + sudo -u "$SUDO_USER" bash -c " cd '$pyroveil_dir' git submodule update --init cmake . -Bbuild -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$user_home/.local ninja -C build install " - echo "✓ Pyroveil installed successfully" - echo "" - echo "To use Pyroveil with games that have mesh shader issues:" - echo "1. For Final Fantasy VII Rebirth:" - echo " PYROVEIL=1 PYROVEIL_CONFIG=$pyroveil_dir/hacks/ffvii-rebirth-nvidia/pyroveil.json %command%" - echo "" - echo "2. For Steam games, add to launch options:" - echo " PYROVEIL=1 PYROVEIL_CONFIG=/path/to/config/pyroveil.json %command%" - echo "" - echo "Available configs in: $pyroveil_dir/hacks/" + echo "✓ Pyroveil installed successfully" + echo "" + echo "To use Pyroveil with games that have mesh shader issues:" + echo "1. For Final Fantasy VII Rebirth:" + echo " PYROVEIL=1 PYROVEIL_CONFIG=$pyroveil_dir/hacks/ffvii-rebirth-nvidia/pyroveil.json %command%" + echo "" + echo "2. For Steam games, add to launch options:" + echo " PYROVEIL=1 PYROVEIL_CONFIG=/path/to/config/pyroveil.json %command%" + echo "" + echo "Available configs in: $pyroveil_dir/hacks/" - # Create a helper script - cat > "$user_home/run-with-pyroveil.sh" << EOF + # Create a helper script + cat >"$user_home/run-with-pyroveil.sh" < @@ -207,88 +207,88 @@ echo "Config file: \$PYROVEIL_CONFIG" exec "\$@" EOF - chown "$SUDO_USER:$SUDO_USER" "$user_home/run-with-pyroveil.sh" - chmod +x "$user_home/run-with-pyroveil.sh" - echo "✓ Created helper script: $user_home/run-with-pyroveil.sh" + chown "$SUDO_USER:$SUDO_USER" "$user_home/run-with-pyroveil.sh" + chmod +x "$user_home/run-with-pyroveil.sh" + echo "✓ Created helper script: $user_home/run-with-pyroveil.sh" - else - echo "Skipping Pyroveil installation" - echo "Note: You can manually install it later for mesh shader issues" - fi + else + echo "Skipping Pyroveil installation" + echo "Note: You can manually install it later for mesh shader issues" + fi } # Function to check for kernel parameter modifications suggest_kernel_params() { - echo "" - echo "5. Kernel Parameter Recommendations..." - echo "=====================================" + echo "" + echo "5. Kernel Parameter Recommendations..." + echo "=====================================" - echo "NVIDIA Driver Issues and Recommended Kernel Parameters:" - echo "" - echo "A) For 'conflicting memory type' or 'failed to allocate primary buffer' errors" - echo " (especially with nvidia-96xx drivers):" - echo " → Add 'nopat' to kernel parameters" - echo "" - echo "B) For OpenGL visual glitches, hangs, and errors with modern CPUs:" - echo " → Consider disabling micro-op cache in BIOS settings" - echo " → This affects Intel Sandy Bridge (2011+) and AMD Zen (2017+) CPUs" - echo " → Helps with severe graphical glitches in Xwayland applications" - echo " → Note: Disabling micro-op cache reduces CPU performance" - echo "" - echo "To add kernel parameters:" - echo "1. Edit /etc/default/grub" - echo "2. Add parameters to GRUB_CMDLINE_LINUX_DEFAULT" - echo "3. Run: grub-mkconfig -o /boot/grub/grub.cfg" - echo "4. Reboot" - echo "" - echo "Example GRUB_CMDLINE_LINUX_DEFAULT line:" - echo 'GRUB_CMDLINE_LINUX_DEFAULT="quiet nopat"' + echo "NVIDIA Driver Issues and Recommended Kernel Parameters:" + echo "" + echo "A) For 'conflicting memory type' or 'failed to allocate primary buffer' errors" + echo " (especially with nvidia-96xx drivers):" + echo " → Add 'nopat' to kernel parameters" + echo "" + echo "B) For OpenGL visual glitches, hangs, and errors with modern CPUs:" + echo " → Consider disabling micro-op cache in BIOS settings" + echo " → This affects Intel Sandy Bridge (2011+) and AMD Zen (2017+) CPUs" + echo " → Helps with severe graphical glitches in Xwayland applications" + echo " → Note: Disabling micro-op cache reduces CPU performance" + echo "" + echo "To add kernel parameters:" + echo "1. Edit /etc/default/grub" + echo "2. Add parameters to GRUB_CMDLINE_LINUX_DEFAULT" + echo "3. Run: grub-mkconfig -o /boot/grub/grub.cfg" + echo "4. Reboot" + echo "" + echo "Example GRUB_CMDLINE_LINUX_DEFAULT line:" + echo 'GRUB_CMDLINE_LINUX_DEFAULT="quiet nopat"' - # Check current CPU for micro-op cache relevance - echo "" - echo "CPU Information (for micro-op cache consideration):" - if command -v lscpu &> /dev/null; then - local cpu_info - cpu_info=$(lscpu | grep "Model name" | cut -d: -f2 | xargs) - echo "Current CPU: $cpu_info" + # Check current CPU for micro-op cache relevance + echo "" + echo "CPU Information (for micro-op cache consideration):" + if command -v lscpu &>/dev/null; then + local cpu_info + cpu_info=$(lscpu | grep "Model name" | cut -d: -f2 | xargs) + echo "Current CPU: $cpu_info" - if echo "$cpu_info" | grep -qi "intel"; then - echo "→ Intel CPU detected. Sandy Bridge (2011) and later have micro-op cache" - elif echo "$cpu_info" | grep -qi "amd"; then - echo "→ AMD CPU detected. Zen (2017) and later have micro-op cache" - fi - fi + if echo "$cpu_info" | grep -qi "intel"; then + echo "→ Intel CPU detected. Sandy Bridge (2011) and later have micro-op cache" + elif echo "$cpu_info" | grep -qi "amd"; then + echo "→ AMD CPU detected. Zen (2017) and later have micro-op cache" + fi + fi } # Function to suggest desktop environment settings suggest_desktop_settings() { - echo "" - echo "6. Desktop Environment Recommendations..." - echo "========================================" + echo "" + echo "6. Desktop Environment Recommendations..." + echo "========================================" - echo "For fullscreen application freezing/crashing issues:" - echo "" - echo "Enable Display Compositing and Direct fullscreen rendering:" - echo "" - echo "• KDE Plasma:" - echo " System Settings → Display and Monitor → Compositor" - echo " → Enable compositor + Enable direct rendering for fullscreen windows" - echo "" - echo "• GNOME:" - echo " Use Extensions or dconf-editor to enable compositing features" - echo "" - echo "• XFCE:" - echo " Settings → Window Manager Tweaks → Compositor" - echo " → Enable display compositing" - echo "" - echo "• Cinnamon:" - echo " System Settings → Effects → Enable desktop effects" + echo "For fullscreen application freezing/crashing issues:" + echo "" + echo "Enable Display Compositing and Direct fullscreen rendering:" + echo "" + echo "• KDE Plasma:" + echo " System Settings → Display and Monitor → Compositor" + echo " → Enable compositor + Enable direct rendering for fullscreen windows" + echo "" + echo "• GNOME:" + echo " Use Extensions or dconf-editor to enable compositing features" + echo "" + echo "• XFCE:" + echo " Settings → Window Manager Tweaks → Compositor" + echo " → Enable display compositing" + echo "" + echo "• Cinnamon:" + echo " System Settings → Effects → Enable desktop effects" - # Detect current desktop environment - if [[ -n $XDG_CURRENT_DESKTOP ]]; then - echo "" - echo "Detected desktop environment: $XDG_CURRENT_DESKTOP" - fi + # Detect current desktop environment + if [[ -n $XDG_CURRENT_DESKTOP ]]; then + echo "" + echo "Detected desktop environment: $XDG_CURRENT_DESKTOP" + fi } # Apply all configurations @@ -300,14 +300,14 @@ install_pyroveil echo "" echo "7. Regenerating Initramfs..." echo "============================" -if command -v mkinitcpio &> /dev/null; then - mkinitcpio -P - echo "✓ Initramfs regenerated with mkinitcpio" -elif command -v dracut &> /dev/null; then - dracut --force - echo "✓ Initramfs regenerated with dracut" +if command -v mkinitcpio &>/dev/null; then + mkinitcpio -P + echo "✓ Initramfs regenerated with mkinitcpio" +elif command -v dracut &>/dev/null; then + dracut --force + echo "✓ Initramfs regenerated with dracut" else - echo "Warning: Could not find mkinitcpio or dracut. You may need to manually regenerate initramfs." + echo "Warning: Could not find mkinitcpio or dracut. You may need to manually regenerate initramfs." fi # Display all recommendations @@ -323,7 +323,7 @@ echo "✓ GSP firmware disabled" echo "✓ RenderAccel disabled in Xorg configuration" echo "✓ GCC version mismatch workaround added" if [[ -d "/home/$SUDO_USER/pyroveil" ]]; then - echo "✓ Pyroveil installed for mesh shader issues" + echo "✓ Pyroveil installed for mesh shader issues" fi echo "✓ Initramfs regenerated" echo "" diff --git a/linux_configuration/scripts/install_joplin.sh b/linux_configuration/scripts/install_joplin.sh index e3e5001..73db565 100755 --- a/linux_configuration/scripts/install_joplin.sh +++ b/linux_configuration/scripts/install_joplin.sh @@ -19,8 +19,8 @@ GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' -info() { echo -e "${GREEN}[INFO]${NC} $*"; } -warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +info() { echo -e "${GREEN}[INFO]${NC} $*"; } +warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } error() { echo -e "${RED}[ERROR]${NC} $*" >&2; } WITH_SERVER=false @@ -30,154 +30,160 @@ DUCKDNS_DOMAIN="" DUCKDNS_TOKEN="" for arg in "$@"; do - case "$arg" in - --with-server) WITH_SERVER=true ;; - --help|-h) - echo "Usage: $0 [--with-server]" - echo "" - echo "Options:" - echo " --with-server Also set up Joplin Server via Docker" - echo " --help, -h Show this help message" - exit 0 - ;; - *) - error "Unknown argument: $arg" - exit 1 - ;; - esac + case "$arg" in + --with-server) WITH_SERVER=true ;; + --help | -h) + echo "Usage: $0 [--with-server]" + echo "" + echo "Options:" + echo " --with-server Also set up Joplin Server via Docker" + echo " --help, -h Show this help message" + exit 0 + ;; + *) + error "Unknown argument: $arg" + exit 1 + ;; + esac done # ── Check prerequisites ───────────────────────────────────────────── -command -v pacman >/dev/null 2>&1 || { error "pacman not found. This script is for Arch Linux."; exit 1; } +command -v pacman >/dev/null 2>&1 || { + error "pacman not found. This script is for Arch Linux." + exit 1 +} # ── Install Joplin Desktop ────────────────────────────────────────── install_joplin_desktop() { - if [[ -f "$HOME/.joplin/Joplin.AppImage" ]]; then - info "Joplin desktop is already installed at $HOME/.joplin/Joplin.AppImage" - return - fi + if [[ -f "$HOME/.joplin/Joplin.AppImage" ]]; then + info "Joplin desktop is already installed at $HOME/.joplin/Joplin.AppImage" + return + fi - info "Installing Joplin desktop app via official installer (AppImage)..." + info "Installing Joplin desktop app via official installer (AppImage)..." - # Official Joplin install script downloads the latest AppImage - wget -O - https://raw.githubusercontent.com/laurent22/joplin/dev/Joplin_install_and_update.sh | bash + # Official Joplin install script downloads the latest AppImage + wget -O - https://raw.githubusercontent.com/laurent22/joplin/dev/Joplin_install_and_update.sh | bash - info "Joplin desktop installed at ~/.joplin/Joplin.AppImage" - info "Launch with: ~/.joplin/Joplin.AppImage (or 'joplin-desktop' from menu)" + info "Joplin desktop installed at ~/.joplin/Joplin.AppImage" + info "Launch with: ~/.joplin/Joplin.AppImage (or 'joplin-desktop' from menu)" } # ── Set up DuckDNS for stable URL ─────────────────────────────────── setup_duckdns() { - info "Setting up DuckDNS for stable server URL..." + info "Setting up DuckDNS for stable server URL..." - if [[ -z "$DUCKDNS_DOMAIN" ]]; then - echo "" - info "Your public IP may change. DuckDNS provides a free stable hostname." - info "1. Go to https://www.duckdns.org/ and sign in (Google/GitHub/etc.)" - info "2. Create a subdomain (e.g. 'myjoplin' for myjoplin.duckdns.org)" - info "3. Copy your token from the DuckDNS dashboard" - echo "" - read -r -p "Enter your DuckDNS subdomain (without .duckdns.org): " DUCKDNS_DOMAIN - read -r -p "Enter your DuckDNS token: " DUCKDNS_TOKEN - fi + if [[ -z "$DUCKDNS_DOMAIN" ]]; then + echo "" + info "Your public IP may change. DuckDNS provides a free stable hostname." + info "1. Go to https://www.duckdns.org/ and sign in (Google/GitHub/etc.)" + info "2. Create a subdomain (e.g. 'myjoplin' for myjoplin.duckdns.org)" + info "3. Copy your token from the DuckDNS dashboard" + echo "" + read -r -p "Enter your DuckDNS subdomain (without .duckdns.org): " DUCKDNS_DOMAIN + read -r -p "Enter your DuckDNS token: " DUCKDNS_TOKEN + fi - if [[ -z "$DUCKDNS_DOMAIN" ]] || [[ -z "$DUCKDNS_TOKEN" ]]; then - warn "DuckDNS not configured. Falling back to raw public IP (may change!)." - return 1 - fi + if [[ -z "$DUCKDNS_DOMAIN" ]] || [[ -z "$DUCKDNS_TOKEN" ]]; then + warn "DuckDNS not configured. Falling back to raw public IP (may change!)." + return 1 + fi - local full_domain="${DUCKDNS_DOMAIN}.duckdns.org" + local full_domain="${DUCKDNS_DOMAIN}.duckdns.org" - # Update DuckDNS now - info "Updating DuckDNS record for ${full_domain}..." - local result - result=$(curl -s "https://www.duckdns.org/update?domains=${DUCKDNS_DOMAIN}&token=${DUCKDNS_TOKEN}&ip=") - if [[ "$result" == "OK" ]]; then - info "DuckDNS updated successfully: ${full_domain}" - else - warn "DuckDNS update returned: $result" - fi + # Update DuckDNS now + info "Updating DuckDNS record for ${full_domain}..." + local result + result=$(curl -s "https://www.duckdns.org/update?domains=${DUCKDNS_DOMAIN}&token=${DUCKDNS_TOKEN}&ip=") + if [[ "$result" == "OK" ]]; then + info "DuckDNS updated successfully: ${full_domain}" + else + warn "DuckDNS update returned: $result" + fi - # Set up cron job to keep IP updated every 5 minutes - local duckdns_script="$JOPLIN_DATA_DIR/duckdns-update.sh" - cat > "$duckdns_script" <"$duckdns_script" <> "$JOPLIN_DATA_DIR/duckdns.log" DUCKEOF - chmod +x "$duckdns_script" + chmod +x "$duckdns_script" - # Add cron job (remove old one if exists, add new) - (crontab -l 2>/dev/null | grep -v "duckdns-update.sh"; echo "*/5 * * * * $duckdns_script") | crontab - - info "DuckDNS cron job installed (updates every 5 minutes)" + # Add cron job (remove old one if exists, add new) + ( + crontab -l 2>/dev/null | grep -v "duckdns-update.sh" + echo "*/5 * * * * $duckdns_script" + ) | crontab - + info "DuckDNS cron job installed (updates every 5 minutes)" - # Save config for future runs - local config_file="$JOPLIN_DATA_DIR/.duckdns.conf" - cat > "$config_file" <"$config_file" </dev/null 2>&1; then - info "Installing Docker..." - sudo pacman -S --needed --noconfirm docker docker-compose - fi + # Ensure Docker is installed and running + if ! command -v docker >/dev/null 2>&1; then + info "Installing Docker..." + sudo pacman -S --needed --noconfirm docker docker-compose + fi - if ! systemctl is-active --quiet docker; then - info "Starting Docker service..." - sudo systemctl enable --now docker - fi + if ! systemctl is-active --quiet docker; then + info "Starting Docker service..." + sudo systemctl enable --now docker + fi - # Add user to docker group if not already a member - if ! groups | grep -q '\bdocker\b'; then - warn "Adding $USER to docker group (re-login required for group to take effect)." - sudo usermod -aG docker "$USER" - fi + # Add user to docker group if not already a member + if ! groups | grep -q '\bdocker\b'; then + warn "Adding $USER to docker group (re-login required for group to take effect)." + sudo usermod -aG docker "$USER" + fi - # Create data directory - mkdir -p "$JOPLIN_DATA_DIR" + # Create data directory + mkdir -p "$JOPLIN_DATA_DIR" - local compose_file="$JOPLIN_DATA_DIR/docker-compose.yml" + local compose_file="$JOPLIN_DATA_DIR/docker-compose.yml" - # Load saved DuckDNS config if it exists - if [[ -f "$JOPLIN_DATA_DIR/.duckdns.conf" ]]; then - # shellcheck source=/dev/null - source "$JOPLIN_DATA_DIR/.duckdns.conf" - fi + # Load saved DuckDNS config if it exists + if [[ -f "$JOPLIN_DATA_DIR/.duckdns.conf" ]]; then + # shellcheck source=/dev/null + source "$JOPLIN_DATA_DIR/.duckdns.conf" + fi - # Set up DuckDNS for a stable hostname - local server_url - if setup_duckdns; then - server_url="http://${DUCKDNS_DOMAIN}.duckdns.org:${JOPLIN_SERVER_PORT}" - info "Using stable DuckDNS URL: $server_url" - else - # Fallback to public IP - local host_ip - host_ip="$(curl -s --max-time 5 ifconfig.me 2>/dev/null)" - if [[ -z "$host_ip" ]]; then - host_ip="$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{print $7; exit}')" - fi - if [[ -z "$host_ip" ]]; then - host_ip="$(hostname -I 2>/dev/null | awk '{print $1}')" - fi - if [[ -z "$host_ip" ]]; then - warn "Could not detect external IP. Falling back to 0.0.0.0" - host_ip="0.0.0.0" - fi - server_url="http://${host_ip}:${JOPLIN_SERVER_PORT}" - warn "Using raw IP URL (may change!): $server_url" - fi + # Set up DuckDNS for a stable hostname + local server_url + if setup_duckdns; then + server_url="http://${DUCKDNS_DOMAIN}.duckdns.org:${JOPLIN_SERVER_PORT}" + info "Using stable DuckDNS URL: $server_url" + else + # Fallback to public IP + local host_ip + host_ip="$(curl -s --max-time 5 ifconfig.me 2>/dev/null)" + if [[ -z "$host_ip" ]]; then + host_ip="$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{print $7; exit}')" + fi + if [[ -z "$host_ip" ]]; then + host_ip="$(hostname -I 2>/dev/null | awk '{print $1}')" + fi + if [[ -z "$host_ip" ]]; then + warn "Could not detect external IP. Falling back to 0.0.0.0" + host_ip="0.0.0.0" + fi + server_url="http://${host_ip}:${JOPLIN_SERVER_PORT}" + warn "Using raw IP URL (may change!): $server_url" + fi - cat > "$compose_file" <"$compose_file" </dev/null 2>&1; then - sudo ufw allow "${JOPLIN_SERVER_PORT}/tcp" || warn "Could not configure ufw" - elif command -v firewall-cmd >/dev/null 2>&1; then - if sudo firewall-cmd --permanent --add-port="${JOPLIN_SERVER_PORT}/tcp" \ - && sudo firewall-cmd --reload; then - : - else - warn "Could not configure firewalld" - fi - elif command -v iptables >/dev/null 2>&1; then - sudo iptables -A INPUT -p tcp --dport "${JOPLIN_SERVER_PORT}" -j ACCEPT || warn "Could not configure iptables" - else - warn "No firewall tool found. Ensure port ${JOPLIN_SERVER_PORT}/tcp is open manually." - fi - echo "" - echo " To connect Joplin desktop/Android to this server:" - echo " 1. Open Joplin → Tools → Options → Synchronisation" - echo " 2. Set target to 'Joplin Server'" - echo " 3. Enter URL: ${server_url}" - echo " 4. Enter your Joplin Server email and password" - echo "" - echo " Server management:" - echo " Start: docker compose -f $compose_file up -d" - echo " Stop: docker compose -f $compose_file down" - echo " Logs: docker compose -f $compose_file logs -f" - echo " Update: docker compose -f $compose_file pull && docker compose -f $compose_file up -d" + echo "" + info "Joplin Server is running at: ${server_url}" + echo "" + echo " Default admin credentials:" + echo " Email: admin@localhost" + echo " Password: admin" + echo "" + warn "IMPORTANT: Change the default admin password and the database" + warn "password (POSTGRES_PASSWORD in $compose_file) immediately!" + echo "" + info "Firewall: opening port ${JOPLIN_SERVER_PORT}/tcp for external access..." + if command -v ufw >/dev/null 2>&1; then + sudo ufw allow "${JOPLIN_SERVER_PORT}/tcp" || warn "Could not configure ufw" + elif command -v firewall-cmd >/dev/null 2>&1; then + if sudo firewall-cmd --permanent --add-port="${JOPLIN_SERVER_PORT}/tcp" && + sudo firewall-cmd --reload; then + : + else + warn "Could not configure firewalld" + fi + elif command -v iptables >/dev/null 2>&1; then + sudo iptables -A INPUT -p tcp --dport "${JOPLIN_SERVER_PORT}" -j ACCEPT || warn "Could not configure iptables" + else + warn "No firewall tool found. Ensure port ${JOPLIN_SERVER_PORT}/tcp is open manually." + fi + echo "" + echo " To connect Joplin desktop/Android to this server:" + echo " 1. Open Joplin → Tools → Options → Synchronisation" + echo " 2. Set target to 'Joplin Server'" + echo " 3. Enter URL: ${server_url}" + echo " 4. Enter your Joplin Server email and password" + echo "" + echo " Server management:" + echo " Start: docker compose -f $compose_file up -d" + echo " Stop: docker compose -f $compose_file down" + echo " Logs: docker compose -f $compose_file logs -f" + echo " Update: docker compose -f $compose_file pull && docker compose -f $compose_file up -d" } # ── Main ───────────────────────────────────────────────────────────── main() { - echo "╔══════════════════════════════════════════════╗" - echo "║ Joplin Installation Script ║" - echo "║ Free & Open Source Note-Taking App ║" - echo "║ https://joplinapp.org ║" - echo "╚══════════════════════════════════════════════╝" - echo "" + echo "╔══════════════════════════════════════════════╗" + echo "║ Joplin Installation Script ║" + echo "║ Free & Open Source Note-Taking App ║" + echo "║ https://joplinapp.org ║" + echo "╚══════════════════════════════════════════════╝" + echo "" - install_joplin_desktop + install_joplin_desktop - if [[ "$WITH_SERVER" == true ]]; then - setup_joplin_server - else - echo "" - info "Tip: Run with --with-server to also set up Joplin Server" - info "for self-hosted sync across devices (desktop + Android)." - fi + if [[ "$WITH_SERVER" == true ]]; then + setup_joplin_server + else + echo "" + info "Tip: Run with --with-server to also set up Joplin Server" + info "for self-hosted sync across devices (desktop + Android)." + fi - echo "" - info "Android app available at:" - info " Google Play: https://play.google.com/store/apps/details?id=net.cozic.joplin" - info " F-Droid: https://f-droid.org/packages/net.cozic.joplin/" - echo "" - info "Done!" + echo "" + info "Android app available at:" + info " Google Play: https://play.google.com/store/apps/details?id=net.cozic.joplin" + info " F-Droid: https://f-droid.org/packages/net.cozic.joplin/" + echo "" + info "Done!" } main diff --git a/linux_configuration/scripts/utils/android_guardian/service.sh b/linux_configuration/scripts/utils/android_guardian/service.sh index 8861ae4..9b264f9 100755 --- a/linux_configuration/scripts/utils/android_guardian/service.sh +++ b/linux_configuration/scripts/utils/android_guardian/service.sh @@ -20,11 +20,11 @@ REMOVE_FILE="$MODULE_DIR/remove" mkdir -p "$GUARDIAN_DIR" log() { - echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE" + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >>"$LOG_FILE" } # Initialize control file if not exists -[ ! -f "$CONTROL_FILE" ] && echo "ENABLED" > "$CONTROL_FILE" +[ ! -f "$CONTROL_FILE" ] && echo "ENABLED" >"$CONTROL_FILE" log "=== Android Guardian starting ===" @@ -36,73 +36,73 @@ log "Wireless ADB enabled on port 5555" # Function to check if guardian is enabled (via ADB control, not Magisk UI) is_enabled() { - [ "$(cat "$CONTROL_FILE" 2> /dev/null)" = "ENABLED" ] + [ "$(cat "$CONTROL_FILE" 2>/dev/null)" = "ENABLED" ] } # Function to protect module from being disabled via Magisk UI protect_module() { - # Remove disable file if someone tried to disable via Magisk - if [ -f "$DISABLE_FILE" ]; then - log "Module disable attempt detected via Magisk UI! Re-enabling..." - rm -f "$DISABLE_FILE" - log "Module re-enabled" - fi + # Remove disable file if someone tried to disable via Magisk + if [ -f "$DISABLE_FILE" ]; then + log "Module disable attempt detected via Magisk UI! Re-enabling..." + rm -f "$DISABLE_FILE" + log "Module re-enabled" + fi - # Remove remove file if someone tried to uninstall via Magisk - if [ -f "$REMOVE_FILE" ]; then - log "Module removal attempt detected via Magisk UI! Blocking..." - rm -f "$REMOVE_FILE" - log "Module removal blocked" - fi + # Remove remove file if someone tried to uninstall via Magisk + if [ -f "$REMOVE_FILE" ]; then + log "Module removal attempt detected via Magisk UI! Blocking..." + rm -f "$REMOVE_FILE" + log "Module removal blocked" + fi } # Function to restore hosts file if tampered protect_hosts() { - if [ -f "$HOSTS_BACKUP" ]; then - current_hash=$(md5sum /system/etc/hosts 2> /dev/null | cut -d' ' -f1) - backup_hash=$(md5sum "$HOSTS_BACKUP" 2> /dev/null | cut -d' ' -f1) + if [ -f "$HOSTS_BACKUP" ]; then + current_hash=$(md5sum /system/etc/hosts 2>/dev/null | cut -d' ' -f1) + backup_hash=$(md5sum "$HOSTS_BACKUP" 2>/dev/null | cut -d' ' -f1) - if [ "$current_hash" != "$backup_hash" ]; then - log "Hosts file tampering detected! Restoring..." - cp "$HOSTS_BACKUP" "$MODDIR/system/etc/hosts" - log "Hosts file restored" - fi - fi + if [ "$current_hash" != "$backup_hash" ]; then + log "Hosts file tampering detected! Restoring..." + cp "$HOSTS_BACKUP" "$MODDIR/system/etc/hosts" + log "Hosts file restored" + fi + fi } # Function to uninstall blocked apps check_blocked_apps() { - if [ ! -f "$BLOCKED_APPS_FILE" ]; then - return - fi + if [ ! -f "$BLOCKED_APPS_FILE" ]; then + return + fi - while IFS= read -r package || [ -n "$package" ]; do - # Skip comments and empty lines - case "$package" in - \#* | "") continue ;; - esac + while IFS= read -r package || [ -n "$package" ]; do + # Skip comments and empty lines + case "$package" in + \#* | "") continue ;; + esac - # Check if package is installed - if pm list packages 2> /dev/null | grep -q "package:$package"; then - log "Blocked app detected: $package - Uninstalling..." - pm uninstall "$package" 2> /dev/null && log "Uninstalled: $package" || log "Failed to uninstall: $package" - fi - done < "$BLOCKED_APPS_FILE" + # Check if package is installed + if pm list packages 2>/dev/null | grep -q "package:$package"; then + log "Blocked app detected: $package - Uninstalling..." + pm uninstall "$package" 2>/dev/null && log "Uninstalled: $package" || log "Failed to uninstall: $package" + fi + done <"$BLOCKED_APPS_FILE" } # Main monitoring loop - runs every 5 seconds for faster protection while true; do - # ALWAYS protect module from UI disabling (even if guardian is "disabled" via ADB) - # This ensures only ADB can control the guardian - protect_module + # ALWAYS protect module from UI disabling (even if guardian is "disabled" via ADB) + # This ensures only ADB can control the guardian + protect_module - if is_enabled; then - protect_hosts - check_blocked_apps - fi + if is_enabled; then + protect_hosts + check_blocked_apps + fi - # Check every 5 seconds (faster response to disable attempts) - sleep 5 + # Check every 5 seconds (faster response to disable attempts) + sleep 5 done & log "Guardian service started (PID: $!)" diff --git a/linux_configuration/scripts/utils/update_android_hosts.sh b/linux_configuration/scripts/utils/update_android_hosts.sh index d53e763..e2737a7 100755 --- a/linux_configuration/scripts/utils/update_android_hosts.sh +++ b/linux_configuration/scripts/utils/update_android_hosts.sh @@ -16,32 +16,32 @@ MODULE_DEST="/data/adb/modules/android_guardian" # Ensure android-tools (adb) is installed ensure_adb_installed() { - if command -v adb &> /dev/null; then - return 0 - fi + if command -v adb &>/dev/null; then + return 0 + fi - log "adb not found, installing android-tools..." + log "adb not found, installing android-tools..." - if command -v pacman &> /dev/null; then - sudo pacman -S --noconfirm android-tools || die "Failed to install android-tools" - elif command -v apt-get &> /dev/null; then - sudo apt-get update && sudo apt-get install -y adb || die "Failed to install adb" - elif command -v dnf &> /dev/null; then - sudo dnf install -y android-tools || die "Failed to install android-tools" - else - die "adb not found and could not determine package manager. Please install android-tools manually." - fi + if command -v pacman &>/dev/null; then + sudo pacman -S --noconfirm android-tools || die "Failed to install android-tools" + elif command -v apt-get &>/dev/null; then + sudo apt-get update && sudo apt-get install -y adb || die "Failed to install adb" + elif command -v dnf &>/dev/null; then + sudo dnf install -y android-tools || die "Failed to install android-tools" + else + die "adb not found and could not determine package manager. Please install android-tools manually." + fi - # Verify installation - if ! command -v adb &> /dev/null; then - die "adb installation failed" - fi + # Verify installation + if ! command -v adb &>/dev/null; then + die "adb installation failed" + fi - log "android-tools installed successfully" + log "android-tools installed successfully" } show_usage() { - cat << EOF + cat < /dev/null; then - if command -v pacman &> /dev/null; then - echo "Installing avahi for device discovery..." >&2 - sudo pacman -S --noconfirm avahi nss-mdns &> /dev/null || true - sudo systemctl enable --now avahi-daemon &> /dev/null || true - elif command -v apt-get &> /dev/null; then - sudo apt-get install -y avahi-utils &> /dev/null || true - fi - fi + # Ensure avahi-browse is available + if ! command -v avahi-browse &>/dev/null; then + if command -v pacman &>/dev/null; then + echo "Installing avahi for device discovery..." >&2 + sudo pacman -S --noconfirm avahi nss-mdns &>/dev/null || true + sudo systemctl enable --now avahi-daemon &>/dev/null || true + elif command -v apt-get &>/dev/null; then + sudo apt-get install -y avahi-utils &>/dev/null || true + fi + fi - if command -v avahi-browse &> /dev/null; then - echo "Scanning for Android devices (5 seconds)..." >&2 + if command -v avahi-browse &>/dev/null; then + echo "Scanning for Android devices (5 seconds)..." >&2 - # Android wireless debugging advertises as _adb-tls-connect._tcp - local discovery_result - discovery_result=$(timeout 5 avahi-browse -rpt _adb-tls-connect._tcp 2> /dev/null | grep "^=" | head -1) + # Android wireless debugging advertises as _adb-tls-connect._tcp + local discovery_result + discovery_result=$(timeout 5 avahi-browse -rpt _adb-tls-connect._tcp 2>/dev/null | grep "^=" | head -1) - if [[ -n $discovery_result ]]; then - # Parse: =;eth0;IPv4;adb-...;_adb-tls-connect._tcp;local;hostname.local;192.168.x.x;port;... - local ip port - ip=$(echo "$discovery_result" | cut -d';' -f8) - port=$(echo "$discovery_result" | cut -d';' -f9) + if [[ -n $discovery_result ]]; then + # Parse: =;eth0;IPv4;adb-...;_adb-tls-connect._tcp;local;hostname.local;192.168.x.x;port;... + local ip port + ip=$(echo "$discovery_result" | cut -d';' -f8) + port=$(echo "$discovery_result" | cut -d';' -f9) - if [[ -n $ip && -n $port ]]; then - found_address="$ip:$port" - echo "✓ Found device: $found_address" >&2 - fi - fi - fi + if [[ -n $ip && -n $port ]]; then + found_address="$ip:$port" + echo "✓ Found device: $found_address" >&2 + fi + fi + fi - # Fallback: try adb's mdns discovery - if [[ -z $found_address ]]; then - echo "Trying adb mdns discovery..." >&2 + # Fallback: try adb's mdns discovery + if [[ -z $found_address ]]; then + echo "Trying adb mdns discovery..." >&2 - # adb can discover devices via mdns - local mdns_result - mdns_result=$(timeout 5 adb mdns services 2> /dev/null | grep -E "adb-tls-connect|_adb\._tcp" | head -1) + # adb can discover devices via mdns + local mdns_result + mdns_result=$(timeout 5 adb mdns services 2>/dev/null | grep -E "adb-tls-connect|_adb\._tcp" | head -1) - if [[ -n $mdns_result ]]; then - # Try to extract IP:port from the result - local service_name - service_name=$(echo "$mdns_result" | awk '{print $1}') - if [[ -n $service_name ]]; then - # Try connecting via service name - echo "Found service: $service_name" >&2 - fi - fi - fi + if [[ -n $mdns_result ]]; then + # Try to extract IP:port from the result + local service_name + service_name=$(echo "$mdns_result" | awk '{print $1}') + if [[ -n $service_name ]]; then + # Try connecting via service name + echo "Found service: $service_name" >&2 + fi + fi + fi - # Return found address (or empty) - echo "$found_address" + # Return found address (or empty) + echo "$found_address" } # Pair with device over WiFi (Android 11+) cmd_pair() { - ensure_adb_installed + ensure_adb_installed - echo "" - echo "=== Wireless ADB Pairing (Android 11+) ===" - echo "" - echo "On your phone:" - echo " 1. Go to Settings > Developer Options > Wireless debugging" - echo " 2. Enable Wireless debugging" - echo " 3. Tap 'Pair device with pairing code'" - echo " 4. Note the IP:port and pairing code shown" - echo "" + echo "" + echo "=== Wireless ADB Pairing (Android 11+) ===" + echo "" + echo "On your phone:" + echo " 1. Go to Settings > Developer Options > Wireless debugging" + echo " 2. Enable Wireless debugging" + echo " 3. Tap 'Pair device with pairing code'" + echo " 4. Note the IP:port and pairing code shown" + echo "" - read -rp "Enter pairing IP:port (e.g., 192.168.1.100:37123): " pair_address - read -rp "Enter pairing code: " pair_code + read -rp "Enter pairing IP:port (e.g., 192.168.1.100:37123): " pair_address + read -rp "Enter pairing code: " pair_code - if [[ -z $pair_address || -z $pair_code ]]; then - die "Pairing address and code are required" - fi + if [[ -z $pair_address || -z $pair_code ]]; then + die "Pairing address and code are required" + fi - log "Pairing with device at $pair_address..." - if adb pair "$pair_address" "$pair_code"; then - echo "" - echo "✓ Pairing successful!" - echo "" - echo "Now get the connection address:" - echo " On phone: Wireless debugging screen shows IP:port under 'IP address & Port'" - echo " (This is DIFFERENT from the pairing port)" - echo "" - read -rp "Enter connection IP:port (e.g., 192.168.1.100:41567): " connect_address + log "Pairing with device at $pair_address..." + if adb pair "$pair_address" "$pair_code"; then + echo "" + echo "✓ Pairing successful!" + echo "" + echo "Now get the connection address:" + echo " On phone: Wireless debugging screen shows IP:port under 'IP address & Port'" + echo " (This is DIFFERENT from the pairing port)" + echo "" + read -rp "Enter connection IP:port (e.g., 192.168.1.100:41567): " connect_address - if [[ -n $connect_address ]]; then - # Save for future connections - mkdir -p "$(dirname "$WIRELESS_CONFIG")" - echo "$connect_address" > "$WIRELESS_CONFIG" - log "Saved connection address for future use" + if [[ -n $connect_address ]]; then + # Save for future connections + mkdir -p "$(dirname "$WIRELESS_CONFIG")" + echo "$connect_address" >"$WIRELESS_CONFIG" + log "Saved connection address for future use" - # Connect now - cmd_connect - fi - else - die "Pairing failed. Make sure the code is correct and you're on the same network." - fi + # Connect now + cmd_connect + fi + else + die "Pairing failed. Make sure the code is correct and you're on the same network." + fi } # Connect to already-paired device cmd_connect() { - ensure_adb_installed + ensure_adb_installed - local connect_address="" + local connect_address="" - # Check for saved address - if [[ -f $WIRELESS_CONFIG ]]; then - connect_address=$(cat "$WIRELESS_CONFIG") - log "Using saved address: $connect_address" - fi + # Check for saved address + if [[ -f $WIRELESS_CONFIG ]]; then + connect_address=$(cat "$WIRELESS_CONFIG") + log "Using saved address: $connect_address" + fi - # Try auto-discovery if no saved address - if [[ -z $connect_address ]]; then - echo "" - log "Searching for Android devices on network..." - connect_address=$(discover_android_device) - fi + # Try auto-discovery if no saved address + if [[ -z $connect_address ]]; then + echo "" + log "Searching for Android devices on network..." + connect_address=$(discover_android_device) + fi - # Manual fallback - if [[ -z $connect_address ]]; then - echo "" - echo "Auto-discovery failed. Enter address manually." - echo "On phone: Settings > Developer Options > Wireless debugging" - echo "Look for IP address & Port (NOT the pairing port)" - echo "" - read -rp "Enter connection IP:port (e.g., 192.168.1.100:41567): " connect_address + # Manual fallback + if [[ -z $connect_address ]]; then + echo "" + echo "Auto-discovery failed. Enter address manually." + echo "On phone: Settings > Developer Options > Wireless debugging" + echo "Look for IP address & Port (NOT the pairing port)" + echo "" + read -rp "Enter connection IP:port (e.g., 192.168.1.100:41567): " connect_address - if [[ -z $connect_address ]]; then - die "Connection address is required" - fi - fi + if [[ -z $connect_address ]]; then + die "Connection address is required" + fi + fi - # Save for future - mkdir -p "$(dirname "$WIRELESS_CONFIG")" - echo "$connect_address" > "$WIRELESS_CONFIG" + # Save for future + mkdir -p "$(dirname "$WIRELESS_CONFIG")" + echo "$connect_address" >"$WIRELESS_CONFIG" - log "Connecting to $connect_address..." - if adb connect "$connect_address" | grep -q "connected"; then - echo "" - echo "✓ Connected to device wirelessly!" - echo "" + log "Connecting to $connect_address..." + if adb connect "$connect_address" | grep -q "connected"; then + echo "" + echo "✓ Connected to device wirelessly!" + echo "" - # Verify connection - if adb devices | grep -q "$connect_address"; then - echo "Device ready. You can now run other commands." - fi - else - echo "" - echo "Connection failed. Possible issues:" - echo " - Wireless debugging not enabled on phone" - echo " - Phone and PC not on same WiFi network" - echo " - Port changed (check Wireless debugging screen)" - echo " - May need to pair first: $0 pair" - echo "" - # Clear saved config since it failed - rm -f "$WIRELESS_CONFIG" - exit 1 - fi + # Verify connection + if adb devices | grep -q "$connect_address"; then + echo "Device ready. You can now run other commands." + fi + else + echo "" + echo "Connection failed. Possible issues:" + echo " - Wireless debugging not enabled on phone" + echo " - Phone and PC not on same WiFi network" + echo " - Port changed (check Wireless debugging screen)" + echo " - May need to pair first: $0 pair" + echo "" + # Clear saved config since it failed + rm -f "$WIRELESS_CONFIG" + exit 1 + fi } # Disconnect wireless ADB cmd_disconnect() { - ensure_adb_installed + ensure_adb_installed - log "Disconnecting all wireless devices..." - adb disconnect - echo "✓ Disconnected" + log "Disconnecting all wireless devices..." + adb disconnect + echo "✓ Disconnected" } # Check device connection and root ensure_device_ready() { - ensure_adb_installed + ensure_adb_installed - # Check if any device is connected - if ! adb devices | grep -qE "device$|:.*device$"; then - echo "" - echo "No device connected!" - echo "" - echo "Options:" - echo " 1. Connect USB cable with debugging enabled" - echo " 2. Use wireless: $0 pair (first time) or $0 connect" - echo "" + # Check if any device is connected + if ! adb devices | grep -qE "device$|:.*device$"; then + echo "" + echo "No device connected!" + echo "" + echo "Options:" + echo " 1. Connect USB cable with debugging enabled" + echo " 2. Use wireless: $0 pair (first time) or $0 connect" + echo "" - # Check if we have a saved wireless config - if [[ -f $WIRELESS_CONFIG ]]; then - read -rp "Try connecting to saved wireless device? [Y/n]: " try_wireless - if [[ ${try_wireless,,} != "n" ]]; then - cmd_connect - else - exit 1 - fi - else - exit 1 - fi - fi + # Check if we have a saved wireless config + if [[ -f $WIRELESS_CONFIG ]]; then + read -rp "Try connecting to saved wireless device? [Y/n]: " try_wireless + if [[ ${try_wireless,,} != "n" ]]; then + cmd_connect + else + exit 1 + fi + else + exit 1 + fi + fi - check_adb_device - check_adb_root + check_adb_device + check_adb_root } # Build the module zip build_module() { - local tmp_dir="$WORK_DIR/guardian_module" - local module_zip="$WORK_DIR/android_guardian.zip" + local tmp_dir="$WORK_DIR/guardian_module" + local module_zip="$WORK_DIR/android_guardian.zip" - echo "[BUILD] Building Android Guardian module..." >&2 + echo "[BUILD] Building Android Guardian module..." >&2 - rm -rf "$tmp_dir" - mkdir -p "$tmp_dir/system/etc" + rm -rf "$tmp_dir" + mkdir -p "$tmp_dir/system/etc" - # Copy module files - cp "$GUARDIAN_MODULE_DIR/module.prop" "$tmp_dir/" - cp "$GUARDIAN_MODULE_DIR/service.sh" "$tmp_dir/" - cp "$GUARDIAN_MODULE_DIR/post-fs-data.sh" "$tmp_dir/" - cp "$GUARDIAN_MODULE_DIR/uninstall.sh" "$tmp_dir/" + # Copy module files + cp "$GUARDIAN_MODULE_DIR/module.prop" "$tmp_dir/" + cp "$GUARDIAN_MODULE_DIR/service.sh" "$tmp_dir/" + cp "$GUARDIAN_MODULE_DIR/post-fs-data.sh" "$tmp_dir/" + cp "$GUARDIAN_MODULE_DIR/uninstall.sh" "$tmp_dir/" - # Build hosts file - local hosts_file="$tmp_dir/system/etc/hosts" - if [[ -f /etc/hosts.stevenblack ]]; then - echo "[BUILD] Using StevenBlack hosts cache..." >&2 - cp /etc/hosts.stevenblack "$hosts_file" - elif [[ -f /etc/hosts ]]; then - echo "[BUILD] Using /etc/hosts..." >&2 - cp /etc/hosts "$hosts_file" - else - die "No hosts file found" - fi + # Build hosts file + local hosts_file="$tmp_dir/system/etc/hosts" + if [[ -f /etc/hosts.stevenblack ]]; then + echo "[BUILD] Using StevenBlack hosts cache..." >&2 + cp /etc/hosts.stevenblack "$hosts_file" + elif [[ -f /etc/hosts ]]; then + echo "[BUILD] Using /etc/hosts..." >&2 + cp /etc/hosts "$hosts_file" + else + die "No hosts file found" + fi - # Append custom blocking entries - cat >> "$hosts_file" << 'CUSTOM_EOF' + # Append custom blocking entries + cat >>"$hosts_file" <<'CUSTOM_EOF' # ============================================ # Custom blocking entries - Android Guardian @@ -563,252 +563,252 @@ build_module() { 0.0.0.0 www.dominos.com CUSTOM_EOF - local total_entries - total_entries=$(grep -c "^0\.0\.0\.0 " "$hosts_file" || echo 0) - echo "[BUILD] Hosts file contains $total_entries blocked domains" >&2 + local total_entries + total_entries=$(grep -c "^0\.0\.0\.0 " "$hosts_file" || echo 0) + echo "[BUILD] Hosts file contains $total_entries blocked domains" >&2 - # Create zip - (cd "$tmp_dir" && zip -r "$module_zip" . -x "*.DS_Store") > /dev/null + # Create zip + (cd "$tmp_dir" && zip -r "$module_zip" . -x "*.DS_Store") >/dev/null - echo "$module_zip" + echo "$module_zip" } # Install/update the guardian module cmd_install() { - ensure_device_ready + ensure_device_ready - local module_zip - module_zip=$(build_module) + local module_zip + module_zip=$(build_module) - log "Pushing module to device..." - adb push "$module_zip" /sdcard/android_guardian.zip || die "Failed to push module" + log "Pushing module to device..." + adb push "$module_zip" /sdcard/android_guardian.zip || die "Failed to push module" - log "Installing module..." - adb shell "su -c 'mkdir -p $MODULE_DEST'" || die "Failed to create module directory" - adb shell "su -c 'cd $MODULE_DEST && unzip -o /sdcard/android_guardian.zip'" || die "Failed to extract module" - adb shell "su -c 'chmod 755 $MODULE_DEST/*.sh'" - adb shell "su -c 'rm /sdcard/android_guardian.zip'" + log "Installing module..." + adb shell "su -c 'mkdir -p $MODULE_DEST'" || die "Failed to create module directory" + adb shell "su -c 'cd $MODULE_DEST && unzip -o /sdcard/android_guardian.zip'" || die "Failed to extract module" + adb shell "su -c 'chmod 755 $MODULE_DEST/*.sh'" + adb shell "su -c 'rm /sdcard/android_guardian.zip'" - # Set up guardian data directory - log "Setting up guardian data..." - adb shell "su -c 'mkdir -p $GUARDIAN_DATA_DIR'" - adb shell "su -c 'echo ENABLED > $GUARDIAN_DATA_DIR/control'" + # Set up guardian data directory + log "Setting up guardian data..." + adb shell "su -c 'mkdir -p $GUARDIAN_DATA_DIR'" + adb shell "su -c 'echo ENABLED > $GUARDIAN_DATA_DIR/control'" - # Copy blocked apps list - adb push "$GUARDIAN_MODULE_DIR/blocked_apps.txt" /sdcard/blocked_apps.txt || die "Failed to push blocked apps list" - adb shell "su -c 'cp /sdcard/blocked_apps.txt $GUARDIAN_DATA_DIR/blocked_apps.txt'" - adb shell "su -c 'rm /sdcard/blocked_apps.txt'" + # Copy blocked apps list + adb push "$GUARDIAN_MODULE_DIR/blocked_apps.txt" /sdcard/blocked_apps.txt || die "Failed to push blocked apps list" + adb shell "su -c 'cp /sdcard/blocked_apps.txt $GUARDIAN_DATA_DIR/blocked_apps.txt'" + adb shell "su -c 'rm /sdcard/blocked_apps.txt'" - # Create hosts backup for tamper protection - adb shell "su -c 'cp $MODULE_DEST/system/etc/hosts $GUARDIAN_DATA_DIR/hosts.backup'" + # Create hosts backup for tamper protection + adb shell "su -c 'cp $MODULE_DEST/system/etc/hosts $GUARDIAN_DATA_DIR/hosts.backup'" - # Immediately uninstall any currently installed blocked apps - log "Checking for blocked apps to remove..." - uninstall_blocked_apps + # Immediately uninstall any currently installed blocked apps + log "Checking for blocked apps to remove..." + uninstall_blocked_apps - echo "" - echo "==========================================" - echo " ✓ Android Guardian installed!" - echo "==========================================" - echo "" - echo "Features enabled:" - echo " • Hosts-based ad/tracker blocking" - echo " • App installation blocking" - echo " • Tamper protection" - echo "" - echo "⚠️ This can ONLY be controlled via ADB:" - echo " Disable: $0 disable" - echo " Enable: $0 enable" - echo " Status: $0 status" - echo "" - echo "Reboot your device to activate the module." - echo "" + echo "" + echo "==========================================" + echo " ✓ Android Guardian installed!" + echo "==========================================" + echo "" + echo "Features enabled:" + echo " • Hosts-based ad/tracker blocking" + echo " • App installation blocking" + echo " • Tamper protection" + echo "" + echo "⚠️ This can ONLY be controlled via ADB:" + echo " Disable: $0 disable" + echo " Enable: $0 enable" + echo " Status: $0 status" + echo "" + echo "Reboot your device to activate the module." + echo "" } # Uninstall currently installed blocked apps uninstall_blocked_apps() { - local blocked_apps - blocked_apps=$(grep -v '^#' "$GUARDIAN_MODULE_DIR/blocked_apps.txt" | grep -v '^$' || true) + local blocked_apps + blocked_apps=$(grep -v '^#' "$GUARDIAN_MODULE_DIR/blocked_apps.txt" | grep -v '^$' || true) - for package in $blocked_apps; do - if adb shell "pm list packages" 2> /dev/null | grep -q "package:$package"; then - log "Uninstalling blocked app: $package" - adb shell "pm uninstall $package" 2> /dev/null || true - fi - done + for package in $blocked_apps; do + if adb shell "pm list packages" 2>/dev/null | grep -q "package:$package"; then + log "Uninstalling blocked app: $package" + adb shell "pm uninstall $package" 2>/dev/null || true + fi + done } # Show status cmd_status() { - ensure_device_ready + ensure_device_ready - echo "" - echo "=== Android Guardian Status ===" - echo "" + echo "" + echo "=== Android Guardian Status ===" + echo "" - # Check if module is installed - if adb shell "su -c 'test -d $MODULE_DEST'" 2> /dev/null; then - echo "Module: INSTALLED" - else - echo "Module: NOT INSTALLED" - return - fi + # Check if module is installed + if adb shell "su -c 'test -d $MODULE_DEST'" 2>/dev/null; then + echo "Module: INSTALLED" + else + echo "Module: NOT INSTALLED" + return + fi - # Check control status - local status - status=$(adb shell "su -c 'cat $GUARDIAN_DATA_DIR/control 2>/dev/null || echo UNKNOWN'" | tr -d '\r') - echo "Status: $status" + # Check control status + local status + status=$(adb shell "su -c 'cat $GUARDIAN_DATA_DIR/control 2>/dev/null || echo UNKNOWN'" | tr -d '\r') + echo "Status: $status" - # Check if module is "disabled" in Magisk UI (should be auto-fixed by watchdog) - local magisk_disabled - if adb shell "su -c 'test -f $MODULE_DEST/disable'" 2> /dev/null; then - magisk_disabled="YES (watchdog should fix this)" - else - magisk_disabled="No" - fi - echo "Magisk UI disabled: $magisk_disabled" + # Check if module is "disabled" in Magisk UI (should be auto-fixed by watchdog) + local magisk_disabled + if adb shell "su -c 'test -f $MODULE_DEST/disable'" 2>/dev/null; then + magisk_disabled="YES (watchdog should fix this)" + else + magisk_disabled="No" + fi + echo "Magisk UI disabled: $magisk_disabled" - # Check if watchdog is running - local watchdog_running - watchdog_running=$(adb shell "su -c 'pgrep -f watchdog.sh 2>/dev/null | wc -l'" | tr -d '\r') - if [ "$watchdog_running" -gt 0 ] 2> /dev/null; then - echo "Watchdog: RUNNING ($watchdog_running processes)" - else - echo "Watchdog: NOT RUNNING (reboot phone to start)" - fi + # Check if watchdog is running + local watchdog_running + watchdog_running=$(adb shell "su -c 'pgrep -f watchdog.sh 2>/dev/null | wc -l'" | tr -d '\r') + if [ "$watchdog_running" -gt 0 ] 2>/dev/null; then + echo "Watchdog: RUNNING ($watchdog_running processes)" + else + echo "Watchdog: NOT RUNNING (reboot phone to start)" + fi - # Check hosts file - local hosts_entries - hosts_entries=$(adb shell "su -c 'grep -c \"^0.0.0.0\" /system/etc/hosts 2>/dev/null || echo 0'" | tr -d '\r') - echo "Blocked domains: $hosts_entries" + # Check hosts file + local hosts_entries + hosts_entries=$(adb shell "su -c 'grep -c \"^0.0.0.0\" /system/etc/hosts 2>/dev/null || echo 0'" | tr -d '\r') + echo "Blocked domains: $hosts_entries" - # Check blocked apps count - local blocked_count - blocked_count=$(adb shell "su -c 'grep -v \"^#\" $GUARDIAN_DATA_DIR/blocked_apps.txt 2>/dev/null | grep -v \"^$\" | wc -l || echo 0'" | tr -d '\r') - echo "Blocked app rules: $blocked_count packages" + # Check blocked apps count + local blocked_count + blocked_count=$(adb shell "su -c 'grep -v \"^#\" $GUARDIAN_DATA_DIR/blocked_apps.txt 2>/dev/null | grep -v \"^$\" | wc -l || echo 0'" | tr -d '\r') + echo "Blocked app rules: $blocked_count packages" - echo "" - echo "Protection: Module cannot be disabled from Magisk UI" - echo " Only controllable via: $0 disable/enable" - echo "" + echo "" + echo "Protection: Module cannot be disabled from Magisk UI" + echo " Only controllable via: $0 disable/enable" + echo "" } # Disable guardian cmd_disable() { - ensure_device_ready + ensure_device_ready - log "Disabling Android Guardian..." - adb shell "su -c 'echo DISABLED > $GUARDIAN_DATA_DIR/control'" || die "Failed to disable guardian" + log "Disabling Android Guardian..." + adb shell "su -c 'echo DISABLED > $GUARDIAN_DATA_DIR/control'" || die "Failed to disable guardian" - echo "" - echo "✓ Guardian DISABLED" - echo " Hosts blocking still active until reboot" - echo " App blocking service paused" - echo "" - echo "To re-enable: $0 enable" - echo "" + echo "" + echo "✓ Guardian DISABLED" + echo " Hosts blocking still active until reboot" + echo " App blocking service paused" + echo "" + echo "To re-enable: $0 enable" + echo "" } # Enable guardian cmd_enable() { - ensure_device_ready + ensure_device_ready - log "Enabling Android Guardian..." - adb shell "su -c 'echo ENABLED > $GUARDIAN_DATA_DIR/control'" || die "Failed to enable guardian" + log "Enabling Android Guardian..." + adb shell "su -c 'echo ENABLED > $GUARDIAN_DATA_DIR/control'" || die "Failed to enable guardian" - echo "" - echo "✓ Guardian ENABLED" - echo "" + echo "" + echo "✓ Guardian ENABLED" + echo "" } # Uninstall module cmd_uninstall() { - ensure_device_ready + ensure_device_ready - # Check if disabled first - local status - status=$(adb shell "su -c 'cat $GUARDIAN_DATA_DIR/control 2>/dev/null || echo ENABLED'" | tr -d '\r') + # Check if disabled first + local status + status=$(adb shell "su -c 'cat $GUARDIAN_DATA_DIR/control 2>/dev/null || echo ENABLED'" | tr -d '\r') - if [[ $status != "DISABLED" ]]; then - echo "" - echo "⚠️ Guardian must be disabled before uninstalling!" - echo " Run: $0 disable" - echo " Then: $0 uninstall" - echo "" - exit 1 - fi + if [[ $status != "DISABLED" ]]; then + echo "" + echo "⚠️ Guardian must be disabled before uninstalling!" + echo " Run: $0 disable" + echo " Then: $0 uninstall" + echo "" + exit 1 + fi - log "Removing Android Guardian..." - adb shell "su -c 'rm -rf $MODULE_DEST'" - adb shell "su -c 'rm -rf $GUARDIAN_DATA_DIR'" + log "Removing Android Guardian..." + adb shell "su -c 'rm -rf $MODULE_DEST'" + adb shell "su -c 'rm -rf $GUARDIAN_DATA_DIR'" - echo "" - echo "✓ Guardian uninstalled" - echo " Reboot to remove hosts blocking" - echo "" + echo "" + echo "✓ Guardian uninstalled" + echo " Reboot to remove hosts blocking" + echo "" } # Show logs cmd_logs() { - ensure_device_ready + ensure_device_ready - echo "=== Guardian Logs ===" - adb shell "su -c 'cat $GUARDIAN_DATA_DIR/guardian.log 2>/dev/null || echo \"No logs yet\"'" + echo "=== Guardian Logs ===" + adb shell "su -c 'cat $GUARDIAN_DATA_DIR/guardian.log 2>/dev/null || echo \"No logs yet\"'" } # Block an app cmd_block_app() { - local package="${1:-}" + local package="${1:-}" - if [[ -z $package ]]; then - echo "Usage: $0 block-app " - echo "Example: $0 block-app com.ubercab.eats" - exit 1 - fi + if [[ -z $package ]]; then + echo "Usage: $0 block-app " + echo "Example: $0 block-app com.ubercab.eats" + exit 1 + fi - ensure_device_ready + ensure_device_ready - log "Adding $package to block list..." - adb shell "su -c 'echo \"$package\" >> $GUARDIAN_DATA_DIR/blocked_apps.txt'" + log "Adding $package to block list..." + adb shell "su -c 'echo \"$package\" >> $GUARDIAN_DATA_DIR/blocked_apps.txt'" - # Also add to local file - echo "$package" >> "$GUARDIAN_MODULE_DIR/blocked_apps.txt" + # Also add to local file + echo "$package" >>"$GUARDIAN_MODULE_DIR/blocked_apps.txt" - # Try to uninstall if currently installed - if adb shell "pm list packages" 2> /dev/null | grep -q "package:$package"; then - log "Uninstalling $package..." - adb shell "pm uninstall $package" 2> /dev/null || true - fi + # Try to uninstall if currently installed + if adb shell "pm list packages" 2>/dev/null | grep -q "package:$package"; then + log "Uninstalling $package..." + adb shell "pm uninstall $package" 2>/dev/null || true + fi - echo "✓ $package added to block list" + echo "✓ $package added to block list" } # Unblock an app cmd_unblock_app() { - local package="${1:-}" + local package="${1:-}" - if [[ -z $package ]]; then - echo "Usage: $0 unblock-app " - exit 1 - fi + if [[ -z $package ]]; then + echo "Usage: $0 unblock-app " + exit 1 + fi - ensure_device_ready + ensure_device_ready - log "Removing $package from block list..." - adb shell "su -c 'grep -v \"^$package\$\" $GUARDIAN_DATA_DIR/blocked_apps.txt > $GUARDIAN_DATA_DIR/blocked_apps.tmp && mv $GUARDIAN_DATA_DIR/blocked_apps.tmp $GUARDIAN_DATA_DIR/blocked_apps.txt'" + log "Removing $package from block list..." + adb shell "su -c 'grep -v \"^$package\$\" $GUARDIAN_DATA_DIR/blocked_apps.txt > $GUARDIAN_DATA_DIR/blocked_apps.tmp && mv $GUARDIAN_DATA_DIR/blocked_apps.tmp $GUARDIAN_DATA_DIR/blocked_apps.txt'" - # Also remove from local file - grep -v "^$package$" "$GUARDIAN_MODULE_DIR/blocked_apps.txt" > "$GUARDIAN_MODULE_DIR/blocked_apps.tmp" && mv "$GUARDIAN_MODULE_DIR/blocked_apps.tmp" "$GUARDIAN_MODULE_DIR/blocked_apps.txt" + # Also remove from local file + grep -v "^$package$" "$GUARDIAN_MODULE_DIR/blocked_apps.txt" >"$GUARDIAN_MODULE_DIR/blocked_apps.tmp" && mv "$GUARDIAN_MODULE_DIR/blocked_apps.tmp" "$GUARDIAN_MODULE_DIR/blocked_apps.txt" - echo "✓ $package removed from block list" + echo "✓ $package removed from block list" } # List blocked apps cmd_list_blocked() { - ensure_device_ready + ensure_device_ready - echo "=== Blocked Apps ===" - adb shell "su -c 'cat $GUARDIAN_DATA_DIR/blocked_apps.txt 2>/dev/null'" | grep -v "^#" | grep -v "^$" || echo "No blocked apps" + echo "=== Blocked Apps ===" + adb shell "su -c 'cat $GUARDIAN_DATA_DIR/blocked_apps.txt 2>/dev/null'" | grep -v "^#" | grep -v "^$" || echo "No blocked apps" } # Main @@ -819,48 +819,48 @@ COMMAND="${1:-install}" shift || true case "$COMMAND" in - install) - cmd_install - ;; - status) - cmd_status - ;; - disable) - cmd_disable - ;; - enable) - cmd_enable - ;; - uninstall) - cmd_uninstall - ;; - logs) - cmd_logs - ;; - block-app) - cmd_block_app "$@" - ;; - unblock-app) - cmd_unblock_app "$@" - ;; - list-blocked) - cmd_list_blocked - ;; - pair) - cmd_pair - ;; - connect) - cmd_connect - ;; - disconnect) - cmd_disconnect - ;; - -h | --help | help) - show_usage - ;; - *) - echo "Unknown command: $COMMAND" - show_usage - exit 1 - ;; +install) + cmd_install + ;; +status) + cmd_status + ;; +disable) + cmd_disable + ;; +enable) + cmd_enable + ;; +uninstall) + cmd_uninstall + ;; +logs) + cmd_logs + ;; +block-app) + cmd_block_app "$@" + ;; +unblock-app) + cmd_unblock_app "$@" + ;; +list-blocked) + cmd_list_blocked + ;; +pair) + cmd_pair + ;; +connect) + cmd_connect + ;; +disconnect) + cmd_disconnect + ;; +-h | --help | help) + show_usage + ;; +*) + echo "Unknown command: $COMMAND" + show_usage + exit 1 + ;; esac diff --git a/python_pkg/anki_decks/polish_gminy/run.sh b/python_pkg/anki_decks/polish_gminy/run.sh index ab83b32..e18a3d3 100755 --- a/python_pkg/anki_decks/polish_gminy/run.sh +++ b/python_pkg/anki_decks/polish_gminy/run.sh @@ -13,8 +13,8 @@ echo "WARNING: This may take a very long time (fetching ~2500 gminy)" echo if [ ! -d "$VENV_DIR" ]; then - echo "Creating virtual environment..." - python3 -m venv "$VENV_DIR" + echo "Creating virtual environment..." + python3 -m venv "$VENV_DIR" fi echo "Activating virtual environment..." diff --git a/python_pkg/anki_decks/polish_powiaty/run.sh b/python_pkg/anki_decks/polish_powiaty/run.sh index 2d5d8a1..3df7b8b 100755 --- a/python_pkg/anki_decks/polish_powiaty/run.sh +++ b/python_pkg/anki_decks/polish_powiaty/run.sh @@ -11,8 +11,8 @@ echo "=== Polish Powiaty Anki Generator ===" echo if [ ! -d "$VENV_DIR" ]; then - echo "Creating virtual environment..." - python3 -m venv "$VENV_DIR" + echo "Creating virtual environment..." + python3 -m venv "$VENV_DIR" fi echo "Activating virtual environment..." diff --git a/python_pkg/anki_decks/warsaw_bridges/run.sh b/python_pkg/anki_decks/warsaw_bridges/run.sh index c00a15c..a848782 100755 --- a/python_pkg/anki_decks/warsaw_bridges/run.sh +++ b/python_pkg/anki_decks/warsaw_bridges/run.sh @@ -11,8 +11,8 @@ echo "=== Warsaw Bridges Anki Generator ===" echo if [ ! -d "$VENV_DIR" ]; then - echo "Creating virtual environment..." - python3 -m venv "$VENV_DIR" + echo "Creating virtual environment..." + python3 -m venv "$VENV_DIR" fi echo "Activating virtual environment..." diff --git a/python_pkg/anki_decks/warsaw_districts/run.sh b/python_pkg/anki_decks/warsaw_districts/run.sh index cf60e60..7af26d5 100755 --- a/python_pkg/anki_decks/warsaw_districts/run.sh +++ b/python_pkg/anki_decks/warsaw_districts/run.sh @@ -12,8 +12,8 @@ echo # Create virtual environment if it doesn't exist if [ ! -d "$VENV_DIR" ]; then - echo "Creating virtual environment..." - python3 -m venv "$VENV_DIR" + echo "Creating virtual environment..." + python3 -m venv "$VENV_DIR" fi # Activate virtual environment diff --git a/python_pkg/anki_decks/warsaw_landmarks/run.sh b/python_pkg/anki_decks/warsaw_landmarks/run.sh index d2db000..a602308 100755 --- a/python_pkg/anki_decks/warsaw_landmarks/run.sh +++ b/python_pkg/anki_decks/warsaw_landmarks/run.sh @@ -11,8 +11,8 @@ echo "=== Warsaw Landmarks Anki Generator ===" echo if [ ! -d "$VENV_DIR" ]; then - echo "Creating virtual environment..." - python3 -m venv "$VENV_DIR" + echo "Creating virtual environment..." + python3 -m venv "$VENV_DIR" fi echo "Activating virtual environment..." diff --git a/python_pkg/anki_decks/warsaw_metro/run.sh b/python_pkg/anki_decks/warsaw_metro/run.sh index 8b05b6a..7e4415c 100755 --- a/python_pkg/anki_decks/warsaw_metro/run.sh +++ b/python_pkg/anki_decks/warsaw_metro/run.sh @@ -11,8 +11,8 @@ echo "=== Warsaw Metro Stations Anki Generator ===" echo if [ ! -d "$VENV_DIR" ]; then - echo "Creating virtual environment..." - python3 -m venv "$VENV_DIR" + echo "Creating virtual environment..." + python3 -m venv "$VENV_DIR" fi echo "Activating virtual environment..." diff --git a/python_pkg/anki_decks/warsaw_osiedla/run.sh b/python_pkg/anki_decks/warsaw_osiedla/run.sh index 17bc8ba..73c09bc 100755 --- a/python_pkg/anki_decks/warsaw_osiedla/run.sh +++ b/python_pkg/anki_decks/warsaw_osiedla/run.sh @@ -11,8 +11,8 @@ echo "=== Warsaw Osiedla Anki Generator ===" echo if [ ! -d "$VENV_DIR" ]; then - echo "Creating virtual environment..." - python3 -m venv "$VENV_DIR" + echo "Creating virtual environment..." + python3 -m venv "$VENV_DIR" fi echo "Activating virtual environment..." diff --git a/python_pkg/anki_decks/warsaw_streets/run.sh b/python_pkg/anki_decks/warsaw_streets/run.sh index 439958e..6aa117a 100755 --- a/python_pkg/anki_decks/warsaw_streets/run.sh +++ b/python_pkg/anki_decks/warsaw_streets/run.sh @@ -11,8 +11,8 @@ echo "=== Warsaw Streets Anki Generator ===" echo if [ ! -d "$VENV_DIR" ]; then - echo "Creating virtual environment..." - python3 -m venv "$VENV_DIR" + echo "Creating virtual environment..." + python3 -m venv "$VENV_DIR" fi echo "Activating virtual environment..." diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..5f9131e --- /dev/null +++ b/setup.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# Post-clone setup script for testsAndMisc repository. +# Run once after cloning: ./setup.sh + +set -euo pipefail + +repo_root="$(git rev-parse --show-toplevel)" +cd "$repo_root" + +printf 'Configuring git hooks path...\n' +git config core.hooksPath linux_configuration/.githooks +printf ' ✓ core.hooksPath set to linux_configuration/.githooks\n' + +printf 'Setup complete.\n'