Last active
May 25, 2017 04:05
-
-
Save adrolter/5072827b71e27661263a5cfba651b859 to your computer and use it in GitHub Desktop.
Mount the partitions of a block device image to a temporary location
This file contains hidden or 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
#!/usr/bin/sh | |
# mount-image.sh – Mount the partitions of a block device image ($1) to a temporary location | |
# Copyright (c) 2017 Adrian Günter | |
# | |
# @Authors Adrian Günter <adrian|gntr/me> | |
# @URL https://gist.github.com/adrianguenter/5072827b71e27661263a5cfba651b859 | |
# @License http://opensource.org/licenses/MIT | |
# @Shells Bash >=4.4, Dash >=0.5 | |
# @Usage mount-image.sh <image-path> | |
# @Example | |
# mountpoint="$(sudo mount-image.sh ~/sda-backup.img)" | |
# ls "$mountpoint" "$mountpoint"/p1 | |
# sudo "$mountpoint"/remove | |
# | |
# $GLOBAL_VAR_NAME / $CONSTANT_NAME | |
# $local_var_name | |
# $CommandName | |
# FunctionName | |
# | |
# Put Bash in POSIX mode (ignored for other shells) | |
POSIXLY_CORRECT=y | |
# Enable nounset and noclobber | |
set -uf | |
# Set a conservative umask | |
umask 0027 | |
# No path searching | |
# shellcheck disable=SC2123 | |
PATH= | |
# Commands | |
readonly Cat='/usr/bin/cat' | |
readonly Chmod='/usr/bin/chmod' | |
readonly Chown='/usr/bin/chown' | |
readonly Date='/usr/bin/date' | |
readonly Grep='/usr/bin/grep' | |
readonly Id='/usr/bin/id' | |
readonly Ln='/usr/bin/ln' | |
readonly Logname='/usr/bin/logname' | |
readonly Losetup='/usr/bin/losetup' | |
readonly Mkdir='/usr/bin/mkdir' | |
readonly Mktemp='/usr/bin/mktemp' | |
readonly Mktempd='/usr/bin/mktemp --directory' | |
readonly Mount='/usr/bin/mount' | |
readonly Nano='/usr/bin/nano' | |
readonly Perl='/usr/bin/perl' | |
readonly Printf='/usr/bin/printf' | |
readonly Readlink='/usr/bin/readlink' | |
# printf to STDERR | |
Printferr(){ >&2 $Printf "${@}";} | |
if ! $Perl -e'$ARGV[0]=~/ built-?in$/||exit 1' "$(command -V local)" ; then | |
Printferr "Shell does not support the 'local' builtin\n" | |
exit 2 | |
fi | |
# Global parameters w/ default values (can be set from parent environment) | |
readonly EDITOR="${EDITOR:-${Nano}}" | |
readonly TMPDIR="${TMPDIR:-/tmp}" | |
# Set INTERACTIVE if fd 0 is associated with a terminal device | |
[ -t 0 ] && readonly INTERACTIVE=INTERACTIVE | |
[ ${EUID+X} ] || readonly EUID="$($Id -u)" | |
readonly LOGNAME="$($Logname)" | |
readonly MOUNT_BASE_PATH="${TMPDIR}/image-mounts" | |
readonly MOUNT_USER_PATH="${MOUNT_BASE_PATH}/${LOGNAME}" | |
__main() { | |
local file_path file_name file_link_path file_mtime_iso8601 \ | |
mountpoint partcount remscript_path | |
file_path="$($Readlink -f "${1}")" | |
if ! [ -f "${file_path}" ]; then | |
Printferr "Image file path '%s' does not exist\n" "${file_path}" | |
exit 1 | |
fi | |
file_name="${file_path##*/}" | |
file_mtime_iso8601="$($Date --iso-8601=ns -ur "${file_path}")" | |
$Mkdir -p "${MOUNT_USER_PATH}" | |
$Chmod 0700 "${MOUNT_USER_PATH}" | |
$Chown "${LOGNAME}" "${MOUNT_USER_PATH}" | |
$Chmod 0755 "${MOUNT_BASE_PATH}" | |
# shellcheck disable=SC2016 | |
mountpoint="$($Mktempd --tmpdir="${MOUNT_USER_PATH}" \ | |
"$($Perl -e'print$ARGV[0]=~s/\s+/-/rg' "${file_name}")--${file_mtime_iso8601}--XXXX")" | |
$Chown "${LOGNAME}" "${mountpoint}" | |
loopdev="$($Losetup --show -LPrf "${file_path}")" | |
# shellcheck disable=SC2181 | |
if [ $? -ne 0 ] || [ -z "${loopdev}" ]; then | |
Printferr 'losetup failed for image %s\n' "${file_path}" | |
exit 1 | |
fi | |
partcount=$($Grep -c " ${loopdev##*/}p[0-9]\+\$" /proc/partitions) | |
local i=1; while [ "${i}" -le "${partcount}" ]; do | |
$Mkdir "${mountpoint}/p${i}" | |
$Mount -o ro "${loopdev}p${i}" "${mountpoint}/p${i}" | |
i=$((i+1)); done | |
file_link_path="${mountpoint}/image-file.link" | |
$Ln -s "${file_path}" "${file_link_path}" | |
remscript_path="${mountpoint}/remove" | |
$Cat << EOF > "${remscript_path}" | |
#!/usr/bin/sh | |
set -e | |
/usr/bin/umount '${mountpoint}'/p* | |
/usr/bin/rmdir '${mountpoint}'/p* | |
/usr/bin/rm -f '${mountpoint}'/* | |
/usr/bin/rmdir '${mountpoint}' | |
EOF | |
$Chmod 0755 "${remscript_path}" | |
$Printf '%s\n' "${mountpoint}" | |
} | |
if ! [ ${1+X} ]; then | |
Printferr 'Missing image file path (Argument #1)\n' | |
exit 1 | |
fi | |
__main "${@}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment