@@ -19,17 +19,22 @@ error_exit() {
1919
2020# Warning function
2121warn () {
22- echo -e " ${YEL} WARNING: $1 ${NC} "
22+ echo -e " ${YEL} WARNING: $1 ${NC} " >&2
2323}
2424
2525# Success function
2626success () {
27- echo -e " ${GRN} ✓ $1 ${NC} "
27+ echo -e " ${GRN} ✓ $1 ${NC} " >&2
2828}
2929
3030# Info function
3131info () {
32- echo -e " ${BLU} ℹ $1 ${NC} "
32+ echo -e " ${BLU} ℹ $1 ${NC} " >&2
33+ }
34+
35+ # Debug function
36+ debug () {
37+ echo -e " ${PUR} [DEBUG] $1 ${NC} " >&2
3338}
3439
3540# Validation function for username
@@ -94,6 +99,124 @@ find_available_uid() {
9499 return 1
95100}
96101
102+ # Mount (and if needed, FileVault-unlock) the Data volume in Recovery Mode.
103+ # APFS volumes are not auto-mounted in Recovery, and on modern Macs the Data
104+ # volume is typically FileVault-encrypted. Must run before detect_volumes.
105+ mount_data_volume () {
106+ info " === MOUNT DATA VOLUME STEP ==="
107+
108+ if [ -d " /Volumes/Data" ]; then
109+ info " Data volume already mounted at /Volumes/Data"
110+ return 0
111+ fi
112+
113+ debug " Data volume not found at /Volumes/Data, need to mount it"
114+
115+ local data_volume_id=" "
116+ info " Searching for 'Data' volume in diskutil..."
117+
118+ data_volume_id=$( diskutil list | grep " APFS Volume" | grep " Data" | grep " disk3" | awk ' {print $NF}' | head -1)
119+ debug " After searching on disk3: data_volume_id='$data_volume_id '"
120+
121+ if [ -z " $data_volume_id " ]; then
122+ debug " Not found on disk3, searching all disks..."
123+ data_volume_id=$( diskutil list | grep " APFS Volume" | grep " Data" | awk ' {print $NF}' | head -1)
124+ debug " After searching all disks: data_volume_id='$data_volume_id '"
125+ fi
126+
127+ if [ -z " $data_volume_id " ]; then
128+ error_exit " Could not find 'Data' volume identifier in diskutil output"
129+ fi
130+
131+ info " Found data volume identifier: $data_volume_id "
132+
133+ local volume_status
134+ volume_status=$( diskutil apfs list 2>&1 | grep -A 15 " Volume $data_volume_id " | head -20)
135+ debug " Volume status:\n$volume_status "
136+
137+ if echo " $volume_status " | grep -E " (FileVault.*Yes|Locked.*Yes)" > /dev/null; then
138+ warn " FileVault-encrypted Data volume detected — unlock required"
139+
140+ local unlock_success=0
141+ local unlock_attempts=0
142+ while [ $unlock_success -eq 0 ] && [ $unlock_attempts -lt 3 ]; do
143+ unlock_attempts=$(( unlock_attempts + 1 ))
144+ echo " " >&2
145+ if [ $unlock_attempts -eq 1 ]; then
146+ echo -e " ${YEL} Enter your FileVault password (the one used at startup)${NC} " >&2
147+ read -s -p " Password: " filevault_pass
148+ else
149+ echo -e " ${RED} Password incorrect. Attempt $unlock_attempts of 3${NC} " >&2
150+ read -s -p " Try again: " filevault_pass
151+ fi
152+ echo " " >&2
153+
154+ local unlock_output
155+ unlock_output=$( diskutil apfs unlockVolume " $data_volume_id " -passphrase " $filevault_pass " 2>&1 )
156+ if [ $? -eq 0 ]; then
157+ success " Volume unlocked"
158+ unlock_success=1
159+ else
160+ warn " Unlock failed: $unlock_output "
161+ fi
162+ done
163+
164+ if [ $unlock_success -eq 0 ]; then
165+ error_exit " Failed to unlock volume after $unlock_attempts attempts"
166+ fi
167+ fi
168+
169+ info " Mounting data volume..."
170+ local mount_output
171+
172+ # Method 1: standard mount
173+ mount_output=$( diskutil mount " $data_volume_id " 2>&1 )
174+ debug " Method 1 (mount) output: $mount_output "
175+ if echo " $mount_output " | grep -q " mounted" ; then
176+ sleep 1
177+ if [ -d " /Volumes/Data" ]; then
178+ success " Data volume mounted"
179+ return 0
180+ fi
181+ fi
182+
183+ # Method 2: mountDisk
184+ mount_output=$( diskutil mountDisk " $data_volume_id " 2>&1 )
185+ debug " Method 2 (mountDisk) output: $mount_output "
186+ if echo " $mount_output " | grep -q " mounted" ; then
187+ sleep 1
188+ if [ -d " /Volumes/Data" ]; then
189+ success " Data volume mounted (method 2)"
190+ return 0
191+ fi
192+ fi
193+
194+ # Method 3: explicit mount point
195+ mkdir -p /Volumes/Data 2> /dev/null
196+ mount_output=$( diskutil mount -mountPoint /Volumes/Data " $data_volume_id " 2>&1 )
197+ debug " Method 3 (explicit mountPoint) output: $mount_output "
198+ if echo " $mount_output " | grep -q " mounted" ; then
199+ sleep 1
200+ if [ -d " /Volumes/Data" ]; then
201+ success " Data volume mounted (method 3)"
202+ return 0
203+ fi
204+ fi
205+
206+ # Method 4: raw mount(8)
207+ local device_path=" /dev/$data_volume_id "
208+ if [ -e " $device_path " ]; then
209+ mount_output=$( mount -t apfs " $device_path " /Volumes/Data 2>&1 )
210+ if [ $? -eq 0 ] && [ -d " /Volumes/Data" ]; then
211+ success " Data volume mounted (method 4)"
212+ return 0
213+ fi
214+ debug " Method 4 failed: $mount_output "
215+ fi
216+
217+ error_exit " All mount methods failed. Could not mount data volume."
218+ }
219+
97220# Function to detect system volumes with multiple fallback strategies (Restored Original)
98221detect_volumes () {
99222 local system_vol=" "
@@ -148,6 +271,12 @@ detect_volumes() {
148271 echo " $system_vol |$data_vol "
149272}
150273
274+ # Mount & unlock the Data volume first (Recovery Mode doesn't auto-mount APFS)
275+ mount_data_volume
276+ if [ ! -d " /Volumes/Data" ]; then
277+ error_exit " Mount process reported success but /Volumes/Data does not exist"
278+ fi
279+
151280# Detect volumes at startup
152281volume_info=$( detect_volumes)
153282system_volume=$( echo " $volume_info " | cut -d' |' -f1)
@@ -175,12 +304,6 @@ select opt in "${options[@]}"; do
175304 echo -e " ${YEL} ═══════════════════════════════════════${NC} "
176305 echo " "
177306
178- # FileVault Check (Integrated from decryption research)
179- if ! diskutil mount " $data_volume " 2> /dev/null; then
180- warn " Data volume is locked (FileVault). Please enter your login password to unlock."
181- diskutil apfs unlockVolume " $data_volume " || error_exit " Failed to unlock Data volume."
182- fi
183-
184307 # Normalize data volume name if needed
185308 if [ " $data_volume " != " Data" ]; then
186309 info " Renaming data volume to 'Data' for consistency..."
0 commit comments