Last active
March 16, 2024 10:31
-
-
Save joevt/a99e3af71343d8242e0078ab4af39b6c to your computer and use it in GitHub Desktop.
A script to help with diagnosing legacy BIOS boot issues on Macs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# Get Partition Info from all disks | |
# | |
# Written by joevt updated March 16, 2024 | |
# Patches marked "rgh" July, 2010, to dump information beyond the | |
# four bios partitions | |
# | |
# sudo ./dumpvols.sh > dumpvols_result.txt 2>&1 | |
# | |
# Based on johnsock's AHCI Master Boot Record Patch. | |
# | |
# This script is freely distributable. | |
# | |
if [ ! "$USER" = "root" ]; then | |
echo WARNING: This script must be run as root. | |
exit | |
fi | |
INPUTDISK="$1" | |
INPUTDISK="${INPUTDISK#/dev/}" | |
INPUTSLICE=$(expr "$INPUTDISK" : 'disk[0-9]*s\([0-9]*\)') | |
if [[ -n $INPUTDISK ]]; then | |
disklist="$(diskutil list "$INPUTDISK" | perl -p -e 's|^/|\n/|')" | |
apfslist="$(diskutil apfs list | sed -nE "/^\|/s// /; /^ $/s///; /\+.*$1 /,/^$/ { /^$/d ; p ; }" 2> /dev/null)" | |
ALLDISKS=0 | |
else | |
disklist="$(diskutil list | perl -p -e 's|^/|\n/|')" | |
apfslist="$(diskutil apfs list 2> /dev/null)" | |
ALLDISKS=1 | |
fi | |
[[ "${apfslist:0:4}" == "Disk" ]] && apfslist="" | |
MBRHASHES=" | |
Windows_XP=d88d4f2dbc2c662db7d7d60ebf9e3e00 | |
Windows_Vista=12c9d7ff4914c88a7f9eadf9211b861b | |
Windows_7=118eb70c44cb69284e5d8aa93096831e | |
None_all_zeros=4ebc676ce4896613a3a9df6e2a1c77ae | |
MSDOS_or_FreeDOS_on_FreeDOS=93dd2ee87a995e36cbab0c2d5c2f041a | |
Windows_XP_On_BootCamp2_with_AHCI_patch=c3fb54174bc479899d4ef6e45308dc18 | |
Windows_XP_On_BootCamp2=cb4dabdd862da0508083b05814e198b8 | |
Windows_Vista_on_XP_with_AHCI_patch=4979e1b9d70738759280f6962c2ad298 | |
Windows_7_on_XP=7db43c1425e9ff3077dd62b776a50419 | |
Windows_7_with_AHCI_patch=a243d3475531b0f6f0d7199043c2eb5c | |
Windows_7_on_XP_with_AHCI_patch=24977c27865adec9ac8298f1a8d214bf | |
Apple_Partition_Map_Block0_Driver_Descriptor_Map_390721968_blocks_and_Tiger_OS_9_drivers=087f35e49a39d52a46e3a94882869f51 | |
" | |
#All VBR hashes use all the bytes starting from offset 0x60. It may be better to use a different range for each type of VBR... | |
# GRUB2 hash was incorrectly named GRUB #rgh | |
# added GRUB hash from observation of kununtu 9.04 #rgh | |
# added Windows 8 | |
VBRHASHES=" | |
None_all_zeros=acf496fff71230daa6985a701f83ce49 | |
NTFS_No_Loader=3be27456483746abb85cd614381dac5e | |
NTFS_Windows_XP_NTLDR=dd1728a59343b9fa9458d80657f68771 | |
NTFS_Windows_Vista_BOOTMGR=d1c278b56eeea9536d0eb5898fe6a0b5 | |
NTFS_Windows_8_BOOTMGR=771df8b803f96296854316d3d5918812 | |
GRUB_from_Ubuntu=332469fa146db809f58d6392e2e0bdce | |
GRUB2_from_Ubuntu=9c249066e1eb9c842d8acdfe6d23a2e3 | |
FAT32_FRDOS4.1=98050815221ee147066f99f806c23203 | |
FAT32_FRDOS4.1_or_MSWIN4.1_BOOTMGR=aec608de8ac709d91e6f3340b643ab4d | |
FAT32_NTFS_NTLDR=d9c3d66e975d2b3b122353951a598b32 | |
FAT12_BSD_4.4_BOOTMGR=4cc92970d5a3350bc72d2b975e28b915 | |
FAT16_Non_system_disk=2a3d0f51ad246f115aa7d37891788857 | |
FAT32_Non_system_disk_or_EFI=34f2d1f3c3ecce5c00cae8f0b82c922b | |
HFS_boot_block_0=28f5bc1563fbaedeb8dabbd4ef9eb4c2 | |
APM_Driver_SCSI_patch=44dc8729f17b4de891fc93d8db04e393 | |
APM_Driver_SCSI_chained_real=f13d0837e944353d07121dcda47f01c0 | |
APM_Driver_ATA_patch=e1dd2732d4f0cfc3f79357f1bae992c7 | |
APM_Driver_ATA_chained_real=4ccc33e59537e50e7831fc499a8672a5 | |
" | |
# APM drivers created by Leopard Install Mac OS 9 Drivers | |
FindHash () { | |
# $1: name of hashed contents | |
# $2: list of known hashes | |
# $3: the hash to search for | |
DIDFIND=0 | |
for CURHASH in $2; do | |
THEHASH=$(expr "$CURHASH" : '[^=]*=\(.*\)') | |
THEOS=$(expr "$CURHASH" : '^\([^=]*\)=') | |
if [ "$3" = "$THEHASH" ]; then | |
DIDFIND=1 | |
break | |
fi | |
done | |
echo "" | |
if [ $DIDFIND = 1 ]; then | |
echo "$1: $THEOS" | |
else | |
echo "$1: Unrecognized (hash=$3)" | |
fi | |
} | |
pascalstring () { | |
# $1 pascal string bytes | |
local thebytes; | |
local thechars; | |
local thelen; | |
thebytes="$1" | |
thelen=$((0x${thebytes:0:2})) | |
thechars=$(sed -E 's/(00)+$//' <<< "${thebytes:2}" | xxd -p -r | tr '\0' '.') | |
if (( thelen != ${#thechars} )); then | |
printf "len:%d? " "$thelen" | |
fi | |
printf "\"%s\"" "$thechars" | |
} | |
GetFileInfo="GetFileInfo" | |
command -v GetFileInfo > /dev/null 2>&1 || { | |
GetFileInfo="/Developer/Tools/GetFileInfo" | |
} | |
inodetopath () { | |
"$GetFileInfo" -P "/.vol/$1/$2" 2> /dev/null | sed -nE '/^(file|directory): "(.*)"/s//\2/p' | |
} | |
inodestring () { | |
local deviceid="$1" | |
local inode="$2" | |
local thepath; | |
thepath="$(inodetopath "$deviceid" "$inode")" | |
printf "%d" "$inode" | |
[[ -n $thepath ]] && printf " => \"%s\"" "$thepath" | |
} | |
forkdatastring () { | |
local forkdata="$1" | |
local extentslist | |
if [[ -n ${forkdata//0/} ]]; then | |
extentslist=$( | |
extents="${forkdata:32}" | |
while [[ -n $extents ]]; do | |
if ((0x${extents:0:16})); then | |
printf "(%d,%d)," $((0x${extents:0:8})) $((0x${extents:8:8})) | |
else | |
printf "," | |
fi | |
extents="${extents:16}" | |
done | |
) | |
printf "logicalSize:%d clumpSize:%d totalBlocks:%d extents:(%s)" $((0x${forkdata:0:16})) $((0x${forkdata:16:8})) $((0x${forkdata:24:8})) "${extentslist%"${extentslist##*[!,]}"}" | |
fi | |
} | |
extentstring () { | |
extents="$1" | |
extentslist=$( | |
while [[ -n $extents ]]; do | |
if ((0x${extents:0:16})); then | |
printf "(%d,%d)," $((0x${extents:0:4})) $((0x${extents:4:4})) | |
else | |
printf "," | |
fi | |
extents="${extents:8}" | |
done | |
) | |
printf "(%s)" "${extentslist%"${extentslist##*[!,]}"}" | |
} | |
dumpencoding () { | |
local message="$1" | |
local encoding="$2" | |
((encoding)) && { | |
printf "%s 0x%08x" "$message" "$encoding" | |
(( (encoding & 0x656e6300) == 0x656e6300 )) && { | |
case $((encoding & 0xff)) in | |
0) printf " = kTextEncodingMacRoman" ;; | |
1) printf " = kTextEncodingMacJapanese" ;; | |
2) printf " = kTextEncodingMacChineseTrad" ;; | |
3) printf " = kTextEncodingMacKorean" ;; | |
4) printf " = kTextEncodingMacArabic" ;; | |
5) printf " = kTextEncodingMacHebrew" ;; | |
6) printf " = kTextEncodingMacGreek" ;; | |
7) printf " = kTextEncodingMacCyrillic" ;; | |
9) printf " = kTextEncodingMacDevanagari" ;; | |
10) printf " = kTextEncodingMacGurmukhi" ;; | |
11) printf " = kTextEncodingMacGujarati" ;; | |
12) printf " = kTextEncodingMacOriya" ;; | |
13) printf " = kTextEncodingMacBengali" ;; | |
14) printf " = kTextEncodingMacTamil" ;; | |
15) printf " = kTextEncodingMacTelugu" ;; | |
16) printf " = kTextEncodingMacKannada" ;; | |
17) printf " = kTextEncodingMacMalayalam" ;; | |
18) printf " = kTextEncodingMacSinhalese" ;; | |
19) printf " = kTextEncodingMacBurmese" ;; | |
20) printf " = kTextEncodingMacKhmer" ;; | |
21) printf " = kTextEncodingMacThai" ;; | |
22) printf " = kTextEncodingMacLaotian" ;; | |
23) printf " = kTextEncodingMacGeorgian" ;; | |
24) printf " = kTextEncodingMacArmenian" ;; | |
25) printf " = kTextEncodingMacChineseSimp" ;; | |
26) printf " = kTextEncodingMacTibetan" ;; | |
27) printf " = kTextEncodingMacMongolian" ;; | |
28) printf " = kTextEncodingMacEthiopic" ;; | |
29) printf " = kTextEncodingMacCentralEurRoman" ;; | |
30) printf " = kTextEncodingMacVietnamese" ;; | |
31) printf " = kTextEncodingMacExtArabic" ;; | |
33) printf " = kTextEncodingMacSymbol" ;; | |
34) printf " = kTextEncodingMacDingbats" ;; | |
35) printf " = kTextEncodingMacTurkish" ;; | |
36) printf " = kTextEncodingMacCroatian" ;; | |
37) printf " = kTextEncodingMacIcelandic" ;; | |
38) printf " = kTextEncodingMacRomanian" ;; | |
39) printf " = kTextEncodingMacCeltic" ;; | |
40) printf " = kTextEncodingMacGaelic" ;; | |
41) printf " = kTextEncodingMacKeyboardGlyphs" ;; | |
esac | |
} | |
printf "\n" | |
} | |
} | |
command -v python > /dev/null 2>&1 && python=python || python=python3 | |
vsdbtouuid0 () { | |
"$python" -c ' | |
import uuid ; from hashlib import md5 | |
kFSUUIDNamespaceSHA1 = uuid.UUID("b3e20f39-f292-11d6-97a4-00306543ecac") | |
digest = md5(kFSUUIDNamespaceSHA1.bytes + bytes.fromhex("'"$1"'"), usedforsecurity=False).digest() | |
print ("%s" % uuid.UUID(bytes=digest[:16], version=3)) | |
' | |
} | |
vsdbtouuid () { | |
local theuuid="" | |
theuuid=$(printf "b3e20f39f29211d697a400306543ecac%s" "$1" | xxd -p -r | md5 | tr "a-f" "A-F" ) | |
printf "%s" "${theuuid:0:8}-${theuuid:8:4}-3${theuuid:13:3}-$(printf "%X" $(((0x${theuuid:16:1} & 3) | 8)))${theuuid:17:3}-${theuuid:20:12}" | |
} | |
(( ALLDISKS )) && echo "$disklist" | |
echo "$apfslist" | |
DRIVELIST="$(sed -n -E "/^[ ]*0: [ ]{0,25}([A-Za-z_]+)[ ]*[+*][0-9.]+ [TGMK][iB][ ]+(disk[0-9]+)$/s//\1_\2/p;/^[ ]*0: [ ]{0,26} .* \*[0-9.]+ [TGMK][iB][ ]+(disk[0-9]+)$/s//whole_\1/p" <<< "$disklist")" | |
for PARTDRIVE in $(echo $DRIVELIST); do | |
DRIVE=$(expr "$PARTDRIVE" : '.*_\([^_]*\)') | |
DTYPE=$(expr "$PARTDRIVE" : '\(.*\)_[^_]*') | |
echo "===============================================================================" | |
diskutiloutput="$(sed -nE '/\/dev\/'"$DRIVE"'( |$)/,/^$/ p' <<< "${disklist}")" | |
echo "$diskutiloutput" | |
echo "---------------------------------------------" | |
diskinfo="$(diskutil info "$DRIVE")" | |
echo "$diskinfo" | |
BLOCKSIZE=$(sed -nE '/^ *Device Block Size: +([0-9]+).*/s//\1/p' <<< "$diskinfo") | |
if [[ -z $BLOCKSIZE ]]; then | |
BLOCKSIZE=512 | |
fi | |
MOUNTPOINTS="" | |
if [[ -n $INPUTSLICE ]]; then | |
DEVLIST="$(echo "$diskutiloutput" | sed -n -E "/^.* (disk[0-9]+s${INPUTSLICE})$/s//\1/p")" | |
else | |
DEVLIST="$(echo "$diskutiloutput" | sed -n -E "/^.* (disk[0-9]+s[0-9]+)$/s//\1/p")" | |
fi | |
for THEDEV in $(echo $DEVLIST); do | |
echo "---------------------------------------------" | |
partinfo="$(diskutil info "$THEDEV")" | |
echo "$partinfo" | |
MOUNTPOINTS="${MOUNTPOINTS}${THEDEV}_$(sed -nE '/ *Mount Point: *(.*)/s//\1/p' <<< "$partinfo")"$'\n' | |
done | |
echo "---------------------------------------------" | |
PARTLIST="" | |
blockbytes=$(dd if="/dev/$DRIVE" bs=512 count=1 2> /dev/null | xxd -p -c 9999) | |
if [ "$DTYPE" = "Apple_partition_scheme" ]; then | |
pdiskoutput="$(pdisk -r -l "/dev/$DRIVE" 2>&1)" | |
pdiskoutput2="$(pdisk -r -l -f "/dev/$DRIVE" 2>&1)" | |
echo "$pdiskoutput" | |
[[ "$pdiskoutput" != "$pdiskoutput2" ]] && echo "$pdiskoutput2" | |
i=0 | |
if [[ ${blockbytes:0:4} == "4552" ]]; then # 'ER' | |
sbBlkSize=$((0x${blockbytes:4:4})) | |
sbBlkCount=$((0x${blockbytes:8:8})) | |
sbDevType=$((0x${blockbytes:16:4})) | |
sbDevId=$((0x${blockbytes:20:4})) | |
sbData=$((0x${blockbytes:24:8})) | |
sbDrvrCount=$((0x${blockbytes:32:4})) | |
echo | |
echo "APM Block 0 contents" | |
printf "000: sbSig : 'ER' = sbSIGWord\n" | |
printf "002: sbBlkSize : %d\n" "$sbBlkSize" | |
printf "004: sbBlkCount : %d = %d MB\n" "$sbBlkCount" $((sbBlkCount*sbBlkSize / 1000 / 1000)) | |
((sbDevType != 0)) && printf "008: sbDevType : %d\n" "$sbDevType" | |
((sbDevId != 0)) && printf "00a: sbDevId : %d\n" "$sbDevId" | |
((sbData != 0)) && printf "00c: sbData : %d\n" "$sbData" | |
((sbDrvrCount > 10)) && printf "010: sbDrvrCount: %d\n" "$sbDrvrCount" | |
for ((i=0; i < sbDrvrCount; i++)); do | |
ddBlock=$((0x${blockbytes:36+i*16:8})) | |
ddSize=$((0x${blockbytes:44+i*16:4})) | |
ddType=$((0x${blockbytes:48+i*16:4})) | |
printf "%03x: DDMap[%d]:%4d @ %-4d 0x%04x = %-27s\n" $((0x012 + i*8)) "$i" "$ddSize" "$ddBlock" "$ddType" "$( | |
{ | |
((ddType == 0x0001)) && printf "kDriverTypeMacSCSI" ; } || | |
{ | |
((ddType == 0x0701)) && printf "kDriverTypeMacATA" ; } || | |
{ | |
((ddType == 0xFFFF)) && printf "kDriverTypeMacSCSIChained"; } || | |
{ | |
((ddType == 0xF8FF)) && printf "kDriverTypeMacATAChained" ; } || | |
printf "?" | |
)" | |
done | |
ddPad="${blockbytes:52+i*16}" | |
[[ -n ${ddPad//0/} ]] && printf "ddPad: %s\n" "$ddPad" | |
echo | |
xxd -p -r <<< "$blockbytes" | xxd -c 16 | |
else | |
# use the same bytes as MBR hash even though Block0 contents are totally different | |
HASH=$(xxd -p -r <<< "${blockbytes:0:440*2}" | xxd -p | md5) | |
FindHash "Block0 contents" "$MBRHASHES" "$HASH" | |
xxd -p -r <<< "$blockbytes" | xxd -c 16 | |
fi | |
PARTTYPE="APM" | |
PARTLIST=$(echo "$pdiskoutput" | sed -nE "/ *[0-9]+: +Apple_Free /d; /[0-9]+: +[0-9]+ @ [0-9]+, type=0x/d; / *([0-9]+): +([^ ]+) .* ([0-9]+) @ ([0-9]+).*/s//\1_\4_\3_\2/p") | |
elif [ "$DTYPE" = "GUID_partition_scheme" ] || [ "$DTYPE" = "FDisk_partition_scheme" ]; then | |
gptoutput="$(gpt -r show "$DRIVE" 2>&1)" | |
gptoutput2="$(gpt -r show -l "$DRIVE" 2>&1)" | |
fdiskoutput="$(fdisk "/dev/r$DRIVE")" | |
echo | |
echo "$gptoutput" | |
! grep -q "illegal option -- l" <<< "$gptoutput2" && { | |
echo | |
echo "$gptoutput2" | |
} | |
echo | |
echo "$fdiskoutput" | |
HASH=$(xxd -p -r <<< "${blockbytes:0:440*2}" | xxd -p | md5) | |
FindHash "MBR contents" "$MBRHASHES" "$HASH" | |
xxd -p -r <<< "$blockbytes" | xxd -c 16 | |
if [ "$DTYPE" = "FDisk_partition_scheme" ]; then | |
PARTLIST=$(echo "$fdiskoutput" | sed -n -E "/^[ \*]+([0-9])\: ([0-9A-F]{2}) .*\[[ ]*([0-9]+) \-[ ]+([1-9][0-9]*)\].*$/s//\1_\3_\4_\2/p") | |
PARTTYPE="MBR" | |
else | |
blockbytes=$(dd if="/dev/$DRIVE" bs="$BLOCKSIZE" skip=1 count=1 2> /dev/null | xxd -p -c 9999) | |
HASH=$(xxd -p -r <<< "${blockbytes:96*2:416*2}" | xxd -p | md5) | |
FindHash "GPT Header @ 1: GPT Header contents" "$VBRHASHES" "$HASH" | |
xxd -p -r <<< "$blockbytes" | xxd -c 16 | |
PARTLIST=$(echo "$gptoutput" | sed -n -E "/^[ ]+([0-9]+)[ ]+([0-9]+)[ ]+([0-9]+)[ ]+GPT part \- (.*)$/s//\3_\1_\2_\4/p") | |
PARTTYPE="GPT" | |
fi | |
elif [ "$DTYPE" = "whole" ]; then | |
HASH=$(xxd -p -r <<< "${blockbytes:0:416*2}" | xxd -p | md5) | |
FindHash "0 @ 0: VBR contents" "$VBRHASHES" "$HASH" | |
xxd -p -r <<< "$blockbytes" | xxd -c 16 | |
else | |
echo "Unknown partition scheme" | |
fi | |
if [[ -n $INPUTSLICE ]]; then | |
PARTLIST="$(sed -nE "/^${INPUTSLICE}_/p" <<< "$PARTLIST")" | |
fi | |
for THEPART in $(echo $PARTLIST); do | |
PNUM=$( expr "$THEPART" : '\([0-9]*\)_') | |
PSTART=$( expr "$THEPART" : '[0-9]*_\([0-9]*\)_[0-9]*') | |
PLENGTH=$(expr "$THEPART" : '[0-9]*_[0-9]*_\([0-9]*\)') | |
PTYPE=$( expr "$THEPART" : '[0-9]*_[0-9]*_[0-9]*_\(.*\)') | |
DEVICEID=$(stat -f "%r" "/dev/${DRIVE}s$PNUM") | |
POFFSETS="_0" | |
while [[ -n $POFFSETS ]]; do | |
POFFSET=$( expr "$POFFSETS" : '_\([0-9]*\)') | |
POFFSETS=$( expr "$POFFSETS" : '_[0-9]*\(_.*\)') | |
if (( POFFSET >= PLENGTH )); then | |
continue | |
fi | |
blockbytes=$(dd if="/dev/$DRIVE" bs="$BLOCKSIZE" skip=$((PSTART + POFFSET)) count=1 2> /dev/null | xxd -p -c 9999) | |
if [[ $PTYPE = "Apple_Patches" ]]; then | |
# Patches # https://developer.apple.com/library/archive/technotes/tn/tn1189.html#SecretsOfThePartitionMap | |
echo | |
echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): Driver Patches" | |
numPatchBlocks=$((0x${blockbytes:0:4})) | |
numPatches=$((0x${blockbytes:4:4})) | |
printf "000: numPatchBlocks: %d\n" "$numPatchBlocks" | |
byteoffset=4; | |
for (( i=0; i < numPatches; i++ )); do | |
printf "%03x: PatchDescriptor[%d]:\n" "$byteoffset" "$i" | |
patchSig=$(sed -E 's/(00)+$//' <<< "${blockbytes:$byteoffset*2:8}" | xxd -p -r | tr '\0' '.') | |
majorVers=$((0x${blockbytes:$byteoffset*2+8:4})); | |
minorVers=$((0x${blockbytes:$byteoffset*2+12:4})); | |
flags=$((0x${blockbytes:$byteoffset*2+16:8})); | |
patchOffset=$((0x${blockbytes:$byteoffset*2+24:8})); | |
patchSize=$((0x${blockbytes:$byteoffset*2+32:8})); | |
patchCRC=$((0x${blockbytes:$byteoffset*2+40:8})); | |
patchDescriptorLen=$((0x${blockbytes:$byteoffset*2+48:8})); | |
patchNameLen=$((0x${blockbytes:$byteoffset*2+56:2})); | |
patchName=$(pascalstring "${blockbytes:$byteoffset*2+56:$patchNameLen*2+2}") | |
patchVendorLen=$((0x${blockbytes:$byteoffset*2+122:2})); | |
patchVendor=$(pascalstring "${blockbytes:$byteoffset*2+122:$patchVendorLen*2+2}") | |
patchPad="${blockbytes:$byteoffset*2+124+$patchVendorLen*2:$patchDescriptorLen*2 - (124+$patchVendorLen*2)}" | |
printf "%03x: patchSig : '%s'\n" $((byteoffset+ 0)) "$patchSig" | |
printf "%03x: majorVers : %d\n" $((byteoffset+ 4)) "$majorVers" | |
printf "%03x: minorVers : %d\n" $((byteoffset+ 6)) "$minorVers" | |
printf "%03x: flags : 0x%08x" $((byteoffset+ 8)) "$flags" | |
if (( flags )); then | |
flagtext=$( | |
((flags & 1)) && printf ",kRequiredPatch" | |
((flags & ~1)) && printf ",0x%08x?" $((flags & ~1)) | |
) | |
printf " = %s" "${flagtext:1}" | |
fi | |
printf "\n" | |
printf "%03x: patchOffset : %d\n" $((byteoffset+12)) "$patchOffset" | |
printf "%03x: patchSize : %d\n" $((byteoffset+16)) "$patchSize" | |
printf "%03x: patchCRC : 0x%08x\n" $((byteoffset+20)) "$patchCRC" | |
printf "%03x: patchDescriptorLen : %d\n" $((byteoffset+24)) "$patchDescriptorLen" | |
printf "%03x: patchName : %s\n" $((byteoffset+28)) "$patchName" | |
printf "%03x: patchVendor : %s\n" $((byteoffset+61)) "$patchVendor" | |
[[ -n $patchPad ]] && printf "%03x: patchPad : %s\n" $((byteoffset+62+patchVendorLen)) "$patchPad" | |
((byteoffset+=patchDescriptorLen)) | |
done # for numPatches | |
echo | |
xxd -p -r <<< "$blockbytes" | xxd -c 16 | |
elif [[ ${blockbytes:0:4} == "504d" ]]; then # 'PM' | |
first_pmMapBlkCnt=$((0x${blockbytes:8:8})) | |
echo | |
echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): Partition Map contents (${first_pmMapBlkCnt} partitions)" | |
for ((i=0;i<PLENGTH;i++)); do | |
if (( i > 0 )); then | |
blockbytes=$(dd if="/dev/$DRIVE" bs="$BLOCKSIZE" skip=$((PSTART + POFFSET + i)) count=1 2> /dev/null | xxd -p -c 9999) | |
fi | |
if [[ -n ${blockbytes//0/} ]]; then | |
# Partition | |
pmSig="${blockbytes:0:4}" | |
pmSigPad=$((0x${blockbytes:4:4})) | |
pmMapBlkCnt=$((0x${blockbytes:8:8})) | |
pmPyPartStart=$((0x${blockbytes:16:8})) | |
pmPartBlkCnt=$((0x${blockbytes:24:8})) | |
pmPartName=$(sed -E 's/(00)+$//' <<< "${blockbytes:32:64}" | xxd -p -r | tr '\0' '.') | |
pmParType=$(sed -E 's/(00)+$//' <<< "${blockbytes:96:64}" | xxd -p -r | tr '\0' '.') | |
pmLgDataStart=$((0x${blockbytes:160:8})) | |
pmDataCnt=$((0x${blockbytes:168:8})) | |
pmPartStatus=$((0x${blockbytes:176:8})) | |
pmLgBootStart=$((0x${blockbytes:184:8})) | |
pmBootSize=$((0x${blockbytes:192:8})) | |
pmBootAddr=$((0x${blockbytes:200:8})) | |
pmBootAddr2=$((0x${blockbytes:208:8})) | |
pmBootEntry=$((0x${blockbytes:216:8})) | |
pmBootEntry2=$((0x${blockbytes:224:8})) | |
pmBootCksum=$((0x${blockbytes:232:8})) | |
pmProcessor=$(sed -E 's/(00)+$//' <<< "${blockbytes:240:32}" | xxd -p -r | tr '\0' '.') | |
pmPad1="${blockbytes:272:256}" | |
pmPad2=$(sed -E 's/(00)+$//' <<< "${blockbytes:528}") | |
printf "%2d:" "$((i+1))" | |
printf " %10d @ %-10d" \ | |
"$pmPartBlkCnt" \ | |
"$pmPyPartStart" | |
[[ $pmSig != 504d ]] && printf " Sig:0x%s?" "$pmSig" | |
[[ -n $pmParType ]] && printf " Type:\"%s\"" "$pmParType" | |
[[ -n $pmPartName ]] && printf " Name:\"%s\"" "$pmPartName" | |
(( pmSigPad )) && printf " SigPad:0x%04X" "$pmSigPad" | |
(( pmMapBlkCnt != first_pmMapBlkCnt )) && printf " MapBlkCnt:%d" "$pmMapBlkCnt" | |
(( pmLgDataStart )) && printf " LgDataStart:%d" "$pmLgDataStart" | |
blockbytes2=${blockbytes:160} | |
if [[ -n ${blockbytes2//0/} ]]; then | |
(( pmDataCnt != pmPartBlkCnt )) && printf " DataCnt:%d" "$pmDataCnt" | |
(( pmPartStatus )) && { | |
statustext=$( | |
(( pmPartStatus & 0x00000001 )) && printf ",Valid" # AUX | |
(( pmPartStatus & 0x00000002 )) && printf ",Allocated" # AUX | |
(( pmPartStatus & 0x00000004 )) && printf ",InUse" # AUX | |
(( pmPartStatus & 0x00000008 )) && printf ",Bootable" # AUX | |
(( pmPartStatus & 0x00000010 )) && printf ",Readable" # AUX | |
(( pmPartStatus & 0x00000020 )) && printf ",Writeable" # AUX and Mac OS | |
(( pmPartStatus & 0x00000040 )) && printf ",BootCodePositionIndependent" # AUX | |
(( pmPartStatus & 0x00000080 )) && printf ",OSSpecific2" # ? | |
(( pmPartStatus & 0x00000100 )) && printf ",ChainCompatible" # driver | |
(( pmPartStatus & 0x00000200 )) && printf ",RealDeviceDriver" # driver | |
(( pmPartStatus & 0x00000400 )) && printf ",CanChainToNext" # driver | |
(( pmPartStatus & 0x40000000 )) && printf ",MountedAtStartup" # Mac OS | |
(( pmPartStatus & 0x80000000 )) && printf ",Startup" # Mac OS | |
(( pmPartStatus & 0x3FFFF800 )) && printf ",0x%x?" $((pmPartStatus & 0x3FFFF800)) | |
) | |
printf " Status:%08X=%s" "$pmPartStatus" "${statustext:1}" | |
} | |
(( pmLgBootStart )) && printf " LgBootStart:%d" "$pmLgBootStart" | |
(( pmBootSize )) && printf " BootSize:%d" "$pmBootSize" | |
(( pmBootAddr )) && printf " BootAddr:0x%08X" "$pmBootAddr" | |
(( pmBootAddr2 )) && printf " BootAddr2:0x%08X" "$pmBootAddr2" | |
(( pmBootEntry )) && printf " BootEntry:0x%08X" "$pmBootEntry" | |
(( pmBootEntry2 )) && printf " BootEntry2:0x%08X" "$pmBootEntry2" | |
(( pmBootCksum )) && printf " BootCksum:0x%08X" "$pmBootCksum" | |
[[ -n $pmProcessor ]] && printf " Processor:\"%s\"" "$pmProcessor" | |
[[ -n ${pmPad1//0/} ]] && { | |
printf " Pad1:%s" "$(sed -E 's/(00)+$//' <<< "${pmPad1}")" | |
[ "${pmPad1:0:8}" = 70744452 ] && printf " = 'ptDR' = kPatchDriverSignature" | |
[ "${pmPad1:0:8}" = 00010600 ] && printf "00 = kSCSIDriverSignature" | |
[ "${pmPad1:0:8}" = 77696b69 ] && printf " = 'wiki' = kATADriverSignature" | |
[ "${pmPad1:0:8}" = 43447672 ] && printf " = 'CDvr' = kSCSICDDriverSignature" | |
[ "${pmPad1:0:8}" = 41545049 ] && printf " = 'ATPI' = kATAPIDriverSignature" | |
[ "${pmPad1:0:8}" = 44535531 ] && printf " = 'DSU1' = kDriveSetupHFSSignature" | |
} | |
[[ -n $pmPad2 ]] && printf " Pad2:%s" "$pmPad2" | |
fi | |
printf "\n" | |
fi | |
done # for APM block | |
elif [[ ${blockbytes:0:4} == "4c4b" ]]; then # 'LK' | |
# Boot Blocks # https://developer.apple.com/library/archive/documentation/mac/pdf/Files/File_Manager.pdf | |
# BootBlkHdr | |
#bbID=$((0x${blockbytes:0:4})) | |
bbEntry=$((0x${blockbytes:4:8})) | |
bbVersion=$((0x${blockbytes:12:4})) | |
bbPageFlags=$((0x${blockbytes:16:4})) | |
bbSysName=$( pascalstring "${blockbytes:20:32}" ) | |
bbShellName=$( pascalstring "${blockbytes:52:32}" ) | |
bbDbg1Name=$( pascalstring "${blockbytes:84:32}" ) | |
bbDbg2Name=$( pascalstring "${blockbytes:116:32}" ) | |
bbScreenName=$(pascalstring "${blockbytes:148:32}" ) | |
bbHelloName=$( pascalstring "${blockbytes:180:32}" ) | |
bbScrapName=$( pascalstring "${blockbytes:212:32}" ) | |
bbCntFCBs=$((0x${blockbytes:244:4})) | |
bbCntEvts=$((0x${blockbytes:248:4})) | |
bb128KSHeap=$((0x${blockbytes:252:8})) | |
bb256KSHeap=$((0x${blockbytes:260:8})) | |
bbSysHeapSize=$((0x${blockbytes:268:8})) | |
filler=$((0x${blockbytes:276:4})) | |
bbSysHeapExtra=$((0x${blockbytes:280:8})) | |
bbSysHeapFract=$((0x${blockbytes:288:8})) | |
echo | |
echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): Boot Block Header contents" | |
CODESTART=$((0x94)) | |
printf "000: bbID : 'LK'\n" | |
printf "002: bbEntry : 0x%08x" "$bbEntry" | |
if (( (bbEntry & 0xffff0000) == 0x60000000 )); then | |
CODESTART=$(((bbEntry & 0xffff) + 4)) | |
printf " = BRA.S *+$%X to offset 0x%03x" $(( CODESTART - 2)) "$CODESTART" | |
(( CODESTART - 2 == 0x8a )) && printf " (after old header)" | |
(( CODESTART - 2 == 0x94 )) && printf " (after new header)" | |
fi | |
printf "\n" | |
printf "006: bbVersion : 0x%04x" "$bbVersion" | |
(( bbVersion )) && { | |
printf " =" | |
(( bbVersion & 0xff00 )) && { | |
printf " flags:(" | |
if (( bbVersion & 0x8000 )); then | |
printf "new header" | |
(( bbVersion & 0x4000 )) && printf ", execute boot code" | |
(( bbVersion & 0x2000 )) && printf ", use relative system heap - bbSysHeapExtra and bbSysHeapFract instead of bbSysHeapSize" | |
(( bbVersion & 0x1f00 )) && printf ", 0x%02x?" $(( (bbVersion & 0x1f00) >> 8 )) | |
else | |
printf "old header" | |
(( bbVersion & 0x7f00 )) && printf ", 0x%02x?" $(( (bbVersion & 0x7f00) >> 8 )) | |
fi | |
printf ")" | |
} | |
(( bbVersion & 0xff )) && { | |
(( bbVersion & 0xff00 )) && printf "," | |
printf " version:%d.%d:(" $(( (bbVersion >> 4) & 15 )) $(( bbVersion & 15 )) | |
(( (bbVersion & 0xff) < 0x15 )) && printf "ignore bb128KSHeap and bb256KSHeap and use default of bbSysHeapSize" | |
(( (bbVersion & 0xff) >= 0x15 )) && printf "use bbSysHeapSize" # How is this different than < 0x15? the documentation for this is bad | |
(( (bbVersion & 0xff) == 0xD )) && printf ", don't execute boot code" # I don't know if this is correct; the documentation for this is bad | |
printf ")" | |
} | |
printf "\n" | |
} | |
((bbPageFlags)) && { | |
# https://developer.apple.com/library/archive/technotes/dv/dv_03.html#//apple_ref/doc/uid/DTS10002393 | |
printf "008: bbPageFlags : 0x%04x =" "$bbPageFlags" | |
if ((bbPageFlags & 0x8000)); then | |
printf "allocate both video and sound buffers" | |
else | |
((bbPageFlags > 0)) && printf "allocate only the secondary sound buffer" | |
fi | |
printf "\n" | |
} | |
printf "00a: bbSysName : %s\n" "$bbSysName" | |
printf "01a: bbShellName : %s\n" "$bbShellName" | |
printf "02a: bbDbg1Name : %s\n" "$bbDbg1Name" | |
printf "03a: bbDbg2Name : %s\n" "$bbDbg2Name" | |
printf "04a: bbScreenName : %s\n" "$bbScreenName" | |
printf "05a: bbHelloName : %s\n" "$bbHelloName" | |
printf "06a: bbScrapName : %s\n" "$bbScrapName" | |
printf "07a: bbCntFCBs : %d\n" "$bbCntFCBs" | |
printf "07c: bbCntEvts : %d\n" "$bbCntEvts" | |
printf "07e: bb128KSHeap : %d\n" "$bb128KSHeap" | |
printf "082: bb256KSHeap : %d\n" "$bb256KSHeap" | |
printf "086: bbSysHeapSize : %d\n" "$bbSysHeapSize" | |
((CODESTART > 0x8a)) && printf "08a: filler : 0x%08x\n" "$filler" | |
((CODESTART > 0x8c)) && printf "08c: bbSysHeapExtra: 0x%08x\n" "$bbSysHeapExtra" | |
((CODESTART > 0x90)) && printf "090: bbSysHeapFract: 0x%08x\n" "$bbSysHeapFract" | |
printf "%03x: boot code\n" "$CODESTART" | |
echo | |
xxd -p -r <<< "$blockbytes" | xxd -c 16 | |
((POFFSET++)) | |
blockbytes=$(dd if="/dev/$DRIVE" bs="$BLOCKSIZE" skip=$((PSTART + POFFSET)) count=1 2> /dev/null | xxd -p -c 9999) | |
echo | |
echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): 2nd Boot Block contents" | |
xxd -p -r <<< "$blockbytes" | xxd -c 16 | |
((POFFSET++)) | |
POFFSETS="_${POFFSET}${POFFSETS}" | |
#printf "queued first MDB after boot blocks: $POFFSETS\n" | |
elif [[ ${blockbytes:0:4} == "4244" ]]; then # 'BD' | |
# Master Directory Blocks # https://developer.apple.com/library/archive/documentation/mac/pdf/Files/File_Manager.pdf | |
# MDB | |
#drSigWord=${blockbytes:0x000*2:4} | |
drCrDate=$((0x${blockbytes:0x002*2:8})) | |
drLsMod=$((0x${blockbytes:0x006*2:8})) | |
drAtrb=$((0x${blockbytes:0x00a*2:4})) | |
drNmFls=$((0x${blockbytes:0x00c*2:4})) | |
drVBMSt=$((0x${blockbytes:0x00e*2:4})) | |
drAllocPtr=$((0x${blockbytes:0x010*2:4})) | |
drNmAlBlks=$((0x${blockbytes:0x012*2:4})) | |
drAlBlkSiz=$((0x${blockbytes:0x014*2:8})) | |
drClpSiz=$((0x${blockbytes:0x018*2:8})) | |
drAlBlSt=$((0x${blockbytes:0x01c*2:4})) | |
drNxtCNID=$((0x${blockbytes:0x01e*2:8})) | |
drFreeBks=$((0x${blockbytes:0x022*2:4})) | |
drVN="$(pascalstring "${blockbytes:0x024*2:28*2}")" | |
drVolBkUp=$((0x${blockbytes:0x040*2:8})) | |
drVSeqNum=$((0x${blockbytes:0x044*2:4})) | |
drWrCnt=$((0x${blockbytes:0x046*2:8})) | |
drXTClpSiz=$((0x${blockbytes:0x04a*2:8})) | |
drCTClpSiz=$((0x${blockbytes:0x04e*2:8})) | |
drNmRtDirs=$((0x${blockbytes:0x052*2:4})) | |
drFilCnt=$((0x${blockbytes:0x054*2:8})) | |
drDirCnt=$((0x${blockbytes:0x058*2:8})) | |
drFndrInfo="${blockbytes:0x05c*2:64}" | |
drVCSize=$((0x${blockbytes:0x07c*2:4})) | |
drVBMCSize=$((0x${blockbytes:0x07e*2:4})) | |
drCtlCSize=$((0x${blockbytes:0x080*2:4})) | |
drEmbedSigWord="$drVCSize" | |
drEmbedExtent_startBlock="$drVBMCSize" | |
drEmbedExtent_blockCount="$drCtlCSize" | |
drXTFlSize=$((0x${blockbytes:0x082*2:8})) | |
drXTExtRec="${blockbytes:0x086*2:24}" | |
drCTFlSize=$((0x${blockbytes:0x092*2:8})) | |
drCTExtRec="${blockbytes:0x096*2:24}" | |
echo | |
echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): Master Directory Block contents" | |
printf "000: drSigWord : 'BD' = kHFSSigWord\n" | |
printf "002: drCrDate : %s\n" "$( ((drCrDate)) && date -r $((drCrDate-2082844800)))" | |
printf "006: drLsMod : %s\n" "$( ((drLsMod )) && date -r $((drLsMod -2082844800)))" | |
((drAtrb)) && { | |
attributestext=$( | |
((drAtrb & 0x0080)) && printf ",VolumeHardwareLock" | |
((drAtrb & 0x0100)) && printf ",VolumeUnmounted" | |
((drAtrb & 0x0200)) && printf ",VolumeSparedBlocks" | |
((drAtrb & 0x0400)) && printf ",VolumeNoCacheRequired" | |
((drAtrb & 0x0800)) && printf ",BootVolumeInconsistent" | |
((drAtrb & 0x1000)) && printf ",CatalogNodeIDsReused" | |
((drAtrb & 0x2000)) && printf ",VolumeJournaled" | |
((drAtrb & 0x4000)) && printf ",VolumeInconsistent" | |
((drAtrb & 0x8000)) && printf ",VolumeSoftwareLock" | |
((drAtrb & 0x007f)) && printf ",0x%04x?" $((drAtrb & 0x007f)) | |
) | |
printf "00a: drAtrb : 0x%04x = %s\n" "$drAtrb" "${attributestext:1}" | |
} | |
printf "00c: drNmFls : %d\n" "$drNmFls" | |
printf "00e: drVBMSt : %d\n" "$drVBMSt" | |
printf "010: drAllocPtr : %d\n" "$drAllocPtr" | |
printf "012: drNmAlBlks : %d\n" "$drNmAlBlks" | |
printf "014: drAlBlkSiz : %d\n" "$drAlBlkSiz" | |
printf "018: drClpSiz : %d\n" "$drClpSiz" | |
printf "01c: drAlBlSt : %d\n" "$drAlBlSt" | |
printf "01e: drNxtCNID : %d\n" "$drNxtCNID" | |
printf "022: drFreeBks : %d\n" "$drFreeBks" | |
printf "024: drVN : %s\n" "$drVN" | |
printf "040: drVolBkUp : %s\n" "$( ((drVolBkUp)) && date -r $((drVolBkUp-2082844800)))" | |
printf "044: drVSeqNum : %d\n" "$drVSeqNum" | |
printf "046: drWrCnt : %d\n" "$drWrCnt" | |
printf "04a: drXTClpSiz : %d\n" "$drXTClpSiz" | |
printf "04e: drCTClpSiz : %d\n" "$drCTClpSiz" | |
printf "052: drNmRtDirs : %d\n" "$drNmRtDirs" | |
printf "054: drFilCnt : %d\n" "$drFilCnt" | |
printf "058: drDirCnt : %d\n" "$drDirCnt" | |
printf "05c: drFndrInfo:\n" | |
printf "05c: Blessed System Folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${drFndrInfo: 0: 8}))" )" | |
printf "060: Blessed System File : %s\n" "$(inodestring "$DEVICEID" "$((0x${drFndrInfo: 8: 8}))" )" | |
printf "064: Open-folder linked list : %s\n" "$(inodestring "$DEVICEID" "$((0x${drFndrInfo:16: 8}))" )" | |
printf "068: Alternate OS blessed file/folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${drFndrInfo:24: 8}))" )" | |
dumpencoding "06c: Text encoding :" "$((0x${drFndrInfo:32: 8}))" | |
printf "070: OS X blessed folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${drFndrInfo:40: 8}))" )" | |
printf "074: 64-bit VSDB volume id : 0x%016X => Volume UUID: %s\n" $((0x${drFndrInfo:48:16})) "$(vsdbtouuid "${drFndrInfo:48:16}")" | |
if (( drEmbedSigWord == 0x482b )); then | |
printf "07c: drEmbedSigWord: %d = 'H+' = kHFSPlusSigWord\n" "$drEmbedSigWord" | |
printf "07e: drEmbedExtent.startBlock : %d\n" "$drEmbedExtent_startBlock" | |
printf "080: drEmbedExtent.blockCount : %d\n" "$drEmbedExtent_blockCount" | |
else | |
printf "07c: drVCSize : %d\n" "$drVCSize" | |
printf "07e: drVBMCSize : %d\n" "$drVBMCSize" | |
printf "080: drCtlCSize : %d\n" "$drCtlCSize" | |
fi | |
printf "082: drXTFlSize : %d\n" "$drXTFlSize" | |
printf "086: drXTExtRec : %s\n" "$(extentstring "$drXTExtRec")" | |
printf "092: drCTFlSize : %d\n" "$drCTFlSize" | |
printf "096: drCTExtRec : %s\n" "$(extentstring "$drCTExtRec")" | |
echo | |
xxd -p -r <<< "$blockbytes" | xxd -c 16 | |
if ((POFFSET < drNmAlBlks * (drAlBlkSiz / 512) - 2)); then | |
# queue up location of alternate Master Directory Block | |
POFFSETS="_$((PLENGTH-2))_$((PLENGTH-1))${POFFSETS}" | |
#printf "queued 2alternate MDB: $POFFSETS \n" | |
if (( drEmbedSigWord == 0x482b )); then | |
# queue up location of wrapped HFS+ partition | |
hfsplusblock=$(( drAlBlSt + drEmbedExtent_startBlock * (drAlBlkSiz / 512) )) | |
POFFSETS="${POFFSETS}_$((hfsplusblock))_$((hfsplusblock+1))_$((hfsplusblock+2))" | |
#printf "queued 3wrapped: $POFFSETS \n" | |
fi | |
fi | |
elif [[ ${blockbytes:0:4} == "482b" ]] || [[ ${blockbytes:0:4} == "4858" ]]; then # 'H+' or 'HX' | |
# Master Directory Blocks # https://developer.apple.com/library/archive/documentation/mac/pdf/Files/File_Manager.pdf | |
# HFS Plus Volume Header | |
signature=$((0x${blockbytes:0x000*2:4})) | |
signatureChars=$(sed -E 's/(00)+$//' <<< "${blockbytes:0x000*2:4}" | xxd -p -r | tr '\0' '.') | |
version=$((0x${blockbytes:0x002*2:4})) | |
attributes=$((0x${blockbytes:0x004*2:8})) | |
lastMountedVersion=$((0x${blockbytes:0x008*2:8})) | |
lastMountedVersionChars=$(sed -E 's/(00)+$//' <<< "${blockbytes:0x008*2:8}" | xxd -p -r | tr '\0' '.') | |
journalInfoBlock=$((0x${blockbytes:0x00c*2:8})) | |
createDate=$((0x${blockbytes:0x010*2:8})) | |
modifyDate=$((0x${blockbytes:0x014*2:8})) | |
backupDate=$((0x${blockbytes:0x018*2:8})) | |
checkedDate=$((0x${blockbytes:0x01c*2:8})) | |
fileCount=$((0x${blockbytes:0x020*2:8})) | |
folderCount=$((0x${blockbytes:0x024*2:8})) | |
blockSize=$((0x${blockbytes:0x028*2:8})) | |
totalBlocks=$((0x${blockbytes:0x02c*2:8})) | |
freeBlocks=$((0x${blockbytes:0x030*2:8})) | |
nextAllocation=$((0x${blockbytes:0x034*2:8})) | |
rsrcClumpSize=$((0x${blockbytes:0x038*2:8})) | |
dataClumpSize=$((0x${blockbytes:0x03c*2:8})) | |
nextCatalogID=$((0x${blockbytes:0x040*2:8})) | |
writeCount=$((0x${blockbytes:0x044*2:8})) | |
encodingsBitmap=$((0x${blockbytes:0x048*2:16})) | |
finderInfo="${blockbytes:0x050*2:64}" | |
allocationFile="${blockbytes:0x070*2:160}" | |
extentsFile="${blockbytes:0x0c0*2:160}" | |
catalogFile="${blockbytes:0x110*2:160}" | |
attributesFile="${blockbytes:0x160*2:160}" | |
startupFile="${blockbytes:0x1b0*2:160}" | |
echo | |
echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): HFS Plus Volume Header contents" | |
printf "000: signature : '%s'" "$signatureChars" | |
((signature == 0x482b )) && printf " = kHFSPlusSigWord" | |
((signature == 0x4858 )) && printf " = kHFSXSigWord" | |
printf "\n" | |
printf "002: version : %d" "$version" | |
((version == 4 )) && printf " = kHFSPlusVersion" | |
((version == 5 )) && printf " = kHFSXVersion" | |
printf "\n" | |
((attributes)) && { | |
attributestext=$( | |
((attributes & 0x00000080)) && printf ",VolumeHardwareLock" | |
((attributes & 0x00000100)) && printf ",VolumeUnmounted" | |
((attributes & 0x00000200)) && printf ",VolumeSparedBlocks" | |
((attributes & 0x00000400)) && printf ",VolumeNoCacheRequired" | |
((attributes & 0x00000800)) && printf ",BootVolumeInconsistent" | |
((attributes & 0x00001000)) && printf ",CatalogNodeIDsReused" | |
((attributes & 0x00002000)) && printf ",VolumeJournaled" | |
((attributes & 0x00004000)) && printf ",VolumeInconsistent" | |
((attributes & 0x00008000)) && printf ",VolumeSoftwareLock" | |
((attributes & 0x40000000)) && printf ",ContentProtection" | |
((attributes & 0x80000000)) && printf ",UnusedNodeFix" | |
((attributes & 0x3fff007f)) && printf ",0x%08x?" $((drAtrb & 0x3fff007f)) | |
) | |
printf "004: attributes : 0x%08x = %s\n" "$attributes" "${attributestext:1}" | |
} | |
printf "008: lastMountedVersion : 0x%08x = '%s'" "$lastMountedVersion" "$lastMountedVersionChars" | |
((lastMountedVersion == 0x31302E30 )) && printf " = kHFSPlusMountVersion" # '10.0'; (Mac OS 8.1 to 9.2.2 is '8.10') | |
((lastMountedVersion == 0x4846534a )) && printf " = kHFSJMountVersion" | |
((lastMountedVersion == 0x46534b21 )) && printf " = kFSKMountVersion" | |
printf "\n" | |
((journalInfoBlock || (attributes & 0x00002000) )) && printf "00c: journalInfoBlock : %d\n" "$journalInfoBlock" | |
printf "010: createDate : %s\n" "$( ((createDate )) && date -r $((createDate -2082844800)))" | |
printf "014: modifyDate : %s\n" "$( ((modifyDate )) && date -r $((modifyDate -2082844800)))" | |
printf "018: backupDate : %s\n" "$( ((backupDate )) && date -r $((backupDate -2082844800)))" | |
printf "01c: checkedDate : %s\n" "$( ((checkedDate)) && date -r $((checkedDate-2082844800)))" | |
printf "020: fileCount : %d\n" "$fileCount" | |
printf "024: folderCount : %d\n" "$folderCount" | |
printf "028: blockSize : %d\n" "$blockSize" | |
printf "02c: totalBlocks : %d\n" "$totalBlocks" | |
printf "030: freeBlocks : %d\n" "$freeBlocks" | |
printf "034: nextAllocation : %d\n" "$nextAllocation" | |
printf "038: rsrcClumpSize : %d\n" "$rsrcClumpSize" | |
printf "03c: dataClumpSize : %d\n" "$dataClumpSize" | |
printf "040: nextCatalogID : %d\n" "$nextCatalogID" | |
printf "044: writeCount : %d\n" "$writeCount" | |
((encodingsBitmap)) && { | |
encodings=$( | |
((encodingsBitmap & (1<< 0))) && printf ",MacRoman" | |
((encodingsBitmap & (1<< 1))) && printf ",MacJapanese" | |
((encodingsBitmap & (1<< 2))) && printf ",MacChineseTrad" | |
((encodingsBitmap & (1<< 3))) && printf ",MacKorean" | |
((encodingsBitmap & (1<< 4))) && printf ",MacArabic" | |
((encodingsBitmap & (1<< 5))) && printf ",MacHebrew" | |
((encodingsBitmap & (1<< 6))) && printf ",MacGreek" | |
((encodingsBitmap & (1<< 7))) && printf ",MacCyrillic" | |
((encodingsBitmap & (1<< 9))) && printf ",MacDevanagari" | |
((encodingsBitmap & (1<<10))) && printf ",MacGurmukhi" | |
((encodingsBitmap & (1<<11))) && printf ",MacGujarati" | |
((encodingsBitmap & (1<<12))) && printf ",MacOriya" | |
((encodingsBitmap & (1<<13))) && printf ",MacBengali" | |
((encodingsBitmap & (1<<14))) && printf ",MacTamil" | |
((encodingsBitmap & (1<<15))) && printf ",MacTelugu" | |
((encodingsBitmap & (1<<16))) && printf ",MacKannada" | |
((encodingsBitmap & (1<<17))) && printf ",MacMalayalam" | |
((encodingsBitmap & (1<<18))) && printf ",MacSinhalese" | |
((encodingsBitmap & (1<<19))) && printf ",MacBurmese" | |
((encodingsBitmap & (1<<20))) && printf ",MacKhmer" | |
((encodingsBitmap & (1<<21))) && printf ",MacThai" | |
((encodingsBitmap & (1<<22))) && printf ",MacLaotian" | |
((encodingsBitmap & (1<<23))) && printf ",MacGeorgian" | |
((encodingsBitmap & (1<<24))) && printf ",MacArmenian" | |
((encodingsBitmap & (1<<25))) && printf ",MacChineseSimp" | |
((encodingsBitmap & (1<<26))) && printf ",MacTibetan" | |
((encodingsBitmap & (1<<27))) && printf ",MacMongolian" | |
((encodingsBitmap & (1<<28))) && printf ",MacEthiopic" | |
((encodingsBitmap & (1<<29))) && printf ",MacCentralEurRoman" | |
((encodingsBitmap & (1<<30))) && printf ",MacVietnamese" | |
((encodingsBitmap & (1<<31))) && printf ",MacExtArabic" | |
((encodingsBitmap & (1<<33))) && printf ",MacSymbol" | |
((encodingsBitmap & (1<<34))) && printf ",MacDingbats" | |
((encodingsBitmap & (1<<35))) && printf ",MacTurkish" | |
((encodingsBitmap & (1<<36))) && printf ",MacCroatian" | |
((encodingsBitmap & (1<<37))) && printf ",MacIcelandic" | |
((encodingsBitmap & (1<<38))) && printf ",MacRomanian" | |
((encodingsBitmap & (1<<48))) && printf ",MacUkrainian" | |
((encodingsBitmap & (1<<49))) && printf ",MacFarsi" | |
((encodingsBitmap & (0xfffcff81 << 32))) && printf ",0x%016x?" $((encodingsBitmap & (0xfffcff81 << 32))) | |
) | |
printf "048: encodingsBitmap : 0x%016x = %s" "$encodingsBitmap" "${encodings:1}" | |
} | |
printf "\n" | |
printf "050: finderInfo:\n" | |
printf "050: Blessed System Folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${finderInfo: 0: 8}))" )" | |
printf "054: Blessed System File : %s\n" "$(inodestring "$DEVICEID" "$((0x${finderInfo: 8: 8}))" )" | |
printf "058: Open-folder linked list : %s\n" "$(inodestring "$DEVICEID" "$((0x${finderInfo:16: 8}))" )" | |
printf "05c: Alternate OS blessed file/folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${finderInfo:24: 8}))" )" | |
dumpencoding "060: Text encoding :" "$((0x${finderInfo:32: 8}))" | |
printf "064: OS X blessed folder : %s\n" "$(inodestring "$DEVICEID" "$((0x${finderInfo:40: 8}))" )" | |
printf "068: 64-bit VSDB volume id : 0x%016X => Volume UUID: %s\n" $(((0x${finderInfo:48:8} << 32) | 0x${finderInfo:56:8} )) "$(vsdbtouuid "${finderInfo:48:16}")" | |
printf "070: allocationFile : %s\n" "$(forkdatastring "$allocationFile" )" | |
printf "0c0: extentsFile : %s\n" "$(forkdatastring "$extentsFile" )" | |
printf "110: catalogFile : %s\n" "$(forkdatastring "$catalogFile" )" | |
printf "160: attributesFile : %s\n" "$(forkdatastring "$attributesFile" )" | |
printf "1b0: startupFile : %s\n" "$(forkdatastring "$startupFile" )" | |
echo | |
xxd -p -r <<< "$blockbytes" | xxd -c 16 | |
if ((POFFSET < PLENGTH-4)); then | |
# queue up location of alternate HFS Plus Volume Header | |
# HFS+ volume starts at POFFSET - 2 | |
endoffset=$((POFFSET - 2 + totalBlocks * (blockSize / 512))) | |
POFFSETS="_$((endoffset - 2))_$((endoffset - 1))${POFFSETS}" | |
#printf "queued alternate HFS+ Header: $POFFSETS\n" | |
fi | |
else | |
if (( 0x${blockbytes:0x20*2:8} == 0x4e585342 )); then # 'NXSB' | |
echo | |
echo "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): APFS Container contents" | |
else | |
HASH=$(xxd -p -r <<< "${blockbytes:96*2:416*2}" | xxd -p | md5) | |
FindHash "$PARTTYPE $PNUM @ ${PSTART}$( ((POFFSET > 0)) && printf "+%d" "$POFFSET" ): $( | |
((POFFSET==0)) && printf "VBR " | |
)contents" "$VBRHASHES" "$HASH" | |
fi | |
if [[ -n ${blockbytes//0/} ]]; then | |
xxd -p -r <<< "$blockbytes" | xxd -c 16 | |
elif [[ -z $POFFSETS ]] && (( POFFSET < 2 )); then | |
POFFSETS="_$((POFFSET+1))" | |
#printf "queued after zero block: $POFFSETS\n" | |
fi | |
fi | |
done # while POFFSETS | |
done # while THEPART | |
done | |
#exit | |
if [[ -n $INPUTDISK ]]; then | |
echo "===============================================================================" | |
ioreg -w 0 -c IOMedia | sed -n -E "/^[ \|]*\+\-o (.*) <class IOMedia[^a-zA-Z]/,/^[ \|]+ }$/p" | { | |
sed -n -E "/^[ \|]*\+\-o (.*)/s//\1/p;/^[ \|]* \| (.*)/s//\1/p;" | |
} | { | |
perl -0777 -n -e 'while (/(^.*? <class IOMedia.*\n\{\n( .*\n)*^ "BSD Name" = "('"$INPUTDISK"'[^\d]|'"${INPUTDISK/s[0-9]*/}"'").*\n( .*\n)*?^}\n)/mg) { printf "$1\n" }' | |
} | |
echo "===============================================================================" | |
else | |
echo "===============================================================================" | |
ioreg -w 0 -c IOMedia | sed -n -E "/^[ \|]*\+\-o (.*) <class IOMedia[^a-zA-Z]/,/^[ \|]+ }$/p" | sed -n -E "/^[ \|]*\+\-o (.*)/s//\1/p;/^[ \|]* \| (.*)/s//\1/p;" | |
echo "===============================================================================" | |
bless --verbose --getBoot | |
echo "===============================================================================" | |
bless --verbose --info | |
echo "===============================================================================" | |
#ioreg -rw 0 -n AppleEFINVRAM 2> /dev/null | sed -n -E "/^[ \|]+[ ]+(\".*)$/s//\1/p;" | |
ioreg -lw0 -p IODeviceTree 2> /dev/null | sed -nE '/o chosen/,/}$/p ; /o option/,/}$/p ; /o aliases/,/}$/p ' | sed -nE "/^[ \|]+[ ]+(\".*)$/s// \1/p; / +\+\-o (.*) +<class ([^,]+).*/s//\1 <\2>/p" | |
echo "===============================================================================" | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Updates
March 16, 2024:
July 28, 2023:
May 20, 2023:
Dec 2, 2022:
disk0
) or a disk slice (e.g.disk0s2
) to reduce the output to a single drive or partition.