#!/bin/bash # ============================================================================= # Automated ext4/LUKS disk mounting for macOS using links # Automates Finder mounting and ensures safe single execution. # # Created by: Francesco Galgani # Website: https://www.informatica-libera.net/ # License: CC0 1.0 Universal (Public Domain) # # This script is free of any copyright. Feel free to use it as you wish. # ============================================================================= set -e # --- Configuration --- LOCK_FILE="/tmp/linsk_manager.lock" # --- Functions --- # Check if linsk or its VM is already running check_linsk_running() { if pgrep -x "linsk" > /dev/null 2>&1 || pgrep -f "linsk run" > /dev/null 2>&1 || pgrep -f "\.linsk/.*qcow2" > /dev/null 2>&1; then echo "[ERROR] An instance of 'linsk' or its virtual machine is already running." echo " Please terminate it (or press Ctrl+C in its terminal) before starting this script." exit 1 fi } # Check for existing script instances via lock file check_single_instance() { if [ -e "$LOCK_FILE" ]; then local lock_pid lock_pid=$(cat "$LOCK_FILE") if kill -0 "$lock_pid" 2>/dev/null; then echo "[ERROR] Another instance of this script is already running (PID: $lock_pid)." echo " Please finish the current session before starting a new one." exit 1 else echo "[WARN] Found stale lock file. Removing it..." rm -f "$LOCK_FILE" fi fi echo $$ > "$LOCK_FILE" } # Find Linux partition find_linux_partition() { echo "[INFO] Searching for Linux partitions on external disks..." local partitions=() # Get list of external physical disks identifiers (e.g., disk3, disk4) local disks=$(diskutil list | grep "external, physical" | awk -F':' '{print $1}' | awk '{print $1}') if [ -z "$disks" ]; then echo "[ERROR] No external physical disks found. Please connect your disk." rm -f "$LOCK_FILE" exit 1 fi for disk in $disks; do # Extract partition identifier for Linux type local parts=$(diskutil list "$disk" | grep "Linux" | awk '{print $NF}') for part in $parts; do # Clean up any invisible characters/spaces part=$(echo "$part" | tr -d '[:space:]') if [ -n "$part" ]; then partitions+=("/dev/$part") fi done done if [ ${#partitions[@]} -eq 0 ]; then echo "[ERROR] No Linux partitions found on external disks." echo " Note: This script does not currently support LVM (Logical Volume Manager)." echo " Please check your disk manually following the instructions at:" echo " https://github.com/AlexSSD7/linsk/blob/master/USAGE_MACOS.md" rm -f "$LOCK_FILE" exit 1 elif [ ${#partitions[@]} -eq 1 ]; then SELECTED_PARTITION="${partitions[0]}" echo "[INFO] Automatically selected partition: $SELECTED_PARTITION" else echo "[INFO] Multiple Linux partitions found:" for i in "${!partitions[@]}"; do echo " $((i+1)). ${partitions[$i]}" done read -p "Select partition number (1-${#partitions[@]}): " sel if [[ "$sel" =~ ^[0-9]+$ ]] && [ "$sel" -ge 1 ] && [ "$sel" -le "${#partitions[@]}" ]; then SELECTED_PARTITION="${partitions[$((sel-1))]}" echo "[INFO] Selected partition: $SELECTED_PARTITION" else echo "[ERROR] Invalid selection." rm -f "$LOCK_FILE" exit 1 fi fi # Final cleanup of the variable to prevent stat errors in linsk SELECTED_PARTITION=$(echo "$SELECTED_PARTITION" | tr -d '[:space:]') } # Auto-detect LUKS by reading the partition header detect_luks() { echo "[INFO] Checking partition type (LUKS vs standard)..." # LUKS headers start with the magic bytes 4c 55 4b 53 ba be (which spells "LUKS\xba\xbe") # We read the first 6 bytes and convert them to hex to avoid grep binary issues. local hex_header hex_header=$(sudo dd if="$SELECTED_PARTITION" bs=6 count=1 2>/dev/null | hexdump -ve '6/1 "%02x"') if [[ "$hex_header" == "4c554b53babe" ]]; then LUKS_FLAG="-l" echo "[INFO] LUKS encryption detected automatically." echo ">>> NOTE: When the terminal prompts 'Enter Password:', enter your LUKS decryption password." else LUKS_FLAG="" echo "[INFO] Standard Linux filesystem detected (non-LUKS). No password will be required." fi } # Cleanup on exit cleanup() { echo "" echo "[INFO] Script interrupted. Cleaning up..." if [ -n "$MONITOR_PID" ]; then kill "$MONITOR_PID" 2>/dev/null fi # Clean temp file and lock file rm -f "$TMP_LOG" rm -f "$LOCK_FILE" echo "[INFO] Done. You can safely disconnect your disk." exit 0 } # --- Main Execution --- if [ "$EUID" -ne 0 ]; then echo "Please run this script with sudo: sudo $0" exit 1 fi # Check if linsk is installed if ! command -v linsk > /dev/null 2>&1; then echo "[ERROR] 'linsk' command not found." echo " Please install it following the instructions at:" echo " https://github.com/AlexSSD7/linsk/blob/master/INSTALL_MACOS.md" exit 1 fi echo "============================================================" echo "linsk source code and documentation: https://github.com/AlexSSD7/linsk" echo "Script created by Francesco Galgani: https://www.informatica-libera.net" echo "============================================================" echo ">>> DISCLAIMER: This script does not support LVM volumes." echo " If macOS shows the 'disk not readable' popup, click 'Ignore'." echo "============================================================" echo "" check_linsk_running check_single_instance TMP_LOG=$(mktemp) trap cleanup SIGINT SIGTERM # 1. Find the Linux partition (disk must already be connected) find_linux_partition # Verify the device node actually exists in /dev before proceeding if [ ! -e "$SELECTED_PARTITION" ]; then echo "[ERROR] Device $SELECTED_PARTITION does not exist!" echo " This can happen if macOS failed to register the device node." echo " Try unplugging and replugging the disk, then run the script again." rm -f "$LOCK_FILE" exit 1 fi # 2. Auto-detect if it's LUKS encrypted detect_luks echo "" echo "[INFO] Starting linsk..." echo "============================================================" echo ">>> IMPORTANT: When you are finished using the disk:" echo "1. Eject the 'linsk' network drive in Finder (Right-click -> Eject)" echo "2. Then return to this terminal and press Ctrl+C to exit." echo "============================================================" echo "" # Background process to monitor log and auto-mount share in Finder ( tail -f -n +1 "$TMP_LOG" | while read -r line; do # Look for the AFP password line (e.g., "Password: 5J076gRa2493AG18") if [[ "$line" == "Password:"* ]]; then AFP_PASS=$(echo "$line" | awk '{print $2}') if [ -n "$AFP_PASS" ]; then echo "" echo "[INFO] AFP Share credentials detected, you may need to enter manually the password: ${AFP_PASS}. Mounting automatically in Finder..." # Get the UID of the original user who invoked sudo ORIGINAL_UID=$(id -u "$SUDO_USER") # 'open' mounts the AFP volume via Finder launchctl asuser "$ORIGINAL_UID" sudo -u "$SUDO_USER" open "afp://linsk:${AFP_PASS}@127.0.0.1:9000/linsk" echo "" echo "" echo "[INFO] Finder window should open shortly." # Stop monitoring once mounted break fi fi done ) & MONITOR_PID=$! # Run linsk in foreground with PTY to allow interactive password input (if LUKS) # 'script' provides the PTY, 'tee' writes to the terminal and the log file in real-time. script -q /dev/null linsk run $LUKS_FLAG "dev:$SELECTED_PARTITION" 2>&1 | tee "$TMP_LOG" # If script exits naturally, cleanup cleanup