Skip to content

Instantly share code, notes, and snippets.

@JayBrown
Last active June 4, 2023 22:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JayBrown/da7da1ef88cdce264fb47495a0fd34c4 to your computer and use it in GitHub Desktop.
Save JayBrown/da7da1ef88cdce264fb47495a0fd34c4 to your computer and use it in GitHub Desktop.
Ejecta: correctly eject APFS-formatted DMGs (raw version)
#!/bin/zsh
# shellcheck shell=bash
# ejecta v0.11
# https://gist.github.com/JayBrown/da7da1ef88cdce264fb47495a0fd34c4
export PATH=/usr/bin:/usr/sbin:/bin:/sbin
_beep () {
osascript -e 'beep' -e 'delay 0.5' &>/dev/null
}
for filepath in "$@"
do
echo "Input: $filepath"
apfs=false
device_all=$(df "$filepath" | grep "^/")
if [[ $device_all == "//"* ]] ; then
device1=$(echo "$device_all" | awk '{print substr($0, index($0,$9))}')
devinfo=$(echo "$device_all" | awk '{print $1}')
echo "Target: $device1 ($devinfo)"
if [[ -f "$device_path/.volume_never_unmount" ]] ; then
echo "Volume blocked!"
_beep
continue
fi
else
if [[ $(echo "$device_all" | awk '{print $NF}') == "/" ]] ; then
echo -e "Target: /\nInternal volume blocked by default!"
_beep
continue
fi
device_path=$(echo "$device_all" | awk '{print substr($0, index($0,$9))}')
if [[ $device_path == "/System/Volumes/Data" ]] ; then
echo -e "Target: /System/Volumes/Data\nInternal volume blocked by default!"
_beep
continue
fi
echo "Target: $device_path"
if [[ -f "$device_path/.volume_never_unmount" ]] ; then
echo "Volume blocked!"
_beep
continue
fi
device1=$(echo "$device_all" | awk '{print $1}')
dev1info=$(diskutil list "$device1")
vol1info=$(echo "$dev1info" | grep "$device1$")
echo "$vol1info" | grep -q "APFS" &>/dev/null && apfs=true
device1=$(echo "$dev1info" | head -1 | awk '{print $1}')
echo "Target device: $device1"
fi
if ! $apfs ; then
echo "Volume is not APFS-formatted: detaching..."
hdiutil detach "$device1"
else
echo "Volume is APFS-formatted"
dev2info=$(echo "$dev1info" | grep "Physical Store")
dev2base=$(echo "$dev2info" | awk -F"Physical Store " '{print $2}')
dev2path="/dev/$dev2base"
device2=$(diskutil list "$dev2path" | head -1 | awk '{print $1}')
echo -e "Secondary target device: $device2\nDetaching all..."
hdiutil detach "$device1" && hdiutil detach "$device2"
fi
done
exit
@JayBrown
Copy link
Author

JayBrown commented Feb 14, 2021

v0.10: now with more checks, incl. internal volumes plus a check for a .volume_never_unmount dotfile in the volume's root.

@JayBrown
Copy link
Author

v0.11: additional checks for local SMB-mounted volumes with leading //

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment