Skip to content

Instantly share code, notes, and snippets.

@nyteshade
Created January 11, 2025 00:46
Show Gist options
  • Save nyteshade/d964db0da6539d3709c04da9d4a77038 to your computer and use it in GitHub Desktop.
Save nyteshade/d964db0da6539d3709c04da9d4a77038 to your computer and use it in GitHub Desktop.
unpkg - For extracting .pkg files on the macintosh
#!/bin/zsh
# A functon that shows users how to use the script. It describes
# and offers some help text that appears when invoked without
# parameters.
showUsage() {
local tool="\x1b[1;35munpkg\x1b[22;39m"
printf "${tool} <path-to-package.pkg> <destination-directory>\n\n"
printf "${tool} will attempt to unpackage the \x1b[1m.pkg\x1b[0m file provided,\n"
printf "however, if certain expectations are not met, it will stop and inform\n"
printf "to the best of its ability, what you should do to continue manually.\n"
}
# Print a message when a file (first parameter) is missing from an
# indicated path
missingFile() {
printf "The file specified ${1}, cannot be found.\n"
}
# Print a message when a directory (first parameter) is missing from
# an indicated path
missingDir() {
printf "The directory ${1}, cannot be found.\n"
}
# Generate a random string of the supplied length, defaults to 8
# characters long.
randString() {
local -a alpha
local string=""
local count="${1:-8}"
local r=0
for i in {a..z} {A..Z} {0..9}; do
alpha+=( "${i}" )
done
for ((i = 0; i < count; i++)); do
r=$(($RANDOM % 62))
string="${string}${alpha[$r]}"
done
printf "${string}"
}
# If we don't have at least two parameters, show the usage
# text and quit
if [[ "${#}" -lt 2 ]]; then
showUsage
exit 0
fi
# If the file cannot be found, show the missing file text
# and quit
if ! [[ -f "${1}" ]]; then
missingFile "${1}"
exit 1
fi
# If the output directory cannot be found, show the missing
# directory text and quit
if ! [[ -d "${2}" ]]; then
missingDir "${2}"
exit 1
fi
# Declare some local variables for file, output directory,
# temporary directory, and the current directory
local file="${1}"
local outDir="${2}"
local tmpDir="/tmp/$(randString)"
local curDir="$(pwd)"
# Remove the temporary directory and contents, if possible,
# return to the original directory and exit with the status
# code supplied (or defaults to 0)
cleanup() {
cd "${curDir}"
rm 2>&1 >/dev/null -rf "${tmpDir}"
if ! [[ "${?}" -eq 0 ]]; then
printf "Could not remove temp directory '${tmpDir}'\n"
fi
exit ${1:-0}
}
# Create the temporary directory
mkdir -p "${tmpDir}"
# If we cannot create the temp directory, print a message,
# and cleanup with a status of 1
if ! [[ "$?" -eq 0 ]]; then
printf "Could not create temporary directory ${tmpDir}\n"
cleanup 1
fi
# Move to the temporary directory
cd "${tmpDir}"
# Extract, using xar, the package file
xar -xf "${file}"
# Within the extracted files, should be a file called Payload.
# Find the path to this file.
local payload="$(realpath $(find . -type f -name 'Payload'))"
# If we cannot find the Payload file, then stop and instruct the
# caller on what to do. At this point, we should not try to proceed
if [[ "${#payload}" -eq 0 ]]; then
printf "Could not find a file called 'Payload' in the extracted contents.\n"
printf "Find the file, move to your target directory, then run\n"
printf "cat ${tmpDir}/path/to/file | gunzip -dc | cpio -i\n"
exit 1
fi
# Move to the output directory
cd "${outDir}"
# Invoke the holy trinity of commands to extract the Payload file
cat "${payload}" | gunzip -dc | cpio -i
# Remove the temp directory as its contents are no longer needed
rm 2>&1 >/dev/null -rf "${tmpDir}"
# Let the user know if we could not clean up
if ! [[ "${?}" -eq 0 ]]; then
printf "Could not remove ${tmpDir}"
fi
# Clean up and exit with status 0
cleanup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment