Skip to content

Instantly share code, notes, and snippets.

@bkahlert

bkahlert/copy-out.sh

Created Jan 17, 2021
Embed
What would you like to do?
POSIX shell script to copy-out / extract files and directories from img files, works with EXT4
#!/bin/sh
# Abort script at first error, when a command exits with non-zero status
# (except in until or while loops, if-tests, list constructs)
set -e
# Attempt to use undefined variable outputs error message, and forces an exit
set -u
# Similar to verbose mode (-v), but expands commands
#set -x
# Causes a pipeline to return the exit status of the last command in the pipe
# that returned a non-zero return value.
set -o pipefail
# Causes libguestfs to display (very verbose) debug information
LIBGUESTFS_DEBUG=0
# Causes libguestfs to display a few dozens of traces
LIBGUESTFS_TRACE=0
_confirmOrQuit() {
QUESTION="${1:-"Do you want to continue?":}"
read -n1 -s -r -p "${QUESTION}" key
printf "\n\e[1A\e[K\e[2m%s\e[m" "${QUESTION}"
if [ "$key" = '' ]; then
printf "\e[1;32m✔\e[m\n"
else
printf "\e[1;91m✘\e[m\n"
exit 0
fi
}
_isAbsolute() {
case "$1" in
/*)
return 0
;;
*)
return 1
;;
esac
}
GUESTFISH_IMAGE="$(find -s . -iname "*.img" -not -path "./shared/*" | head -n 1)"
if [ ! -f "${GUESTFISH_IMAGE}" ]; then
printf "\e[1;31mNo image found to copy out from.\e[39m\n"
printf "Please run \e[1;96m%s\e[39m in a directory containing an \e[1;96m%s\e[39m file.\n" "$(basename "$0")" ".img"
exit 1
fi
printf "\e[40;90m░\e[49;39m\e[46;96m░\e[49;39m\e[44;94m░\e[49;39m\e[42;92m░\e[49;39m\e[43;93m\e[49;39m\e[45;95m░\e[49;39m\e[41;91m░\e[49;39m \e[96m%s\e[39m \e[36m%s\e[39m\n" "COPY-OUT" "from ${GUESTFISH_IMAGE}"
PATH_TO_COPY="${1:-/}"
if ! _isAbsolute "${PATH_TO_COPY}"; then
_confirmOrQuit "$(printf "An absolute path is required. Use \e[1;96m/%s\e[m instead? " "${PATH_TO_COPY}")"
PATH_TO_COPY="/${PATH_TO_COPY}"
fi
if [ "${PATH_TO_COPY}" = "/" ] && [ -n "$(find "${GUESTFISH_IMAGE}" -prune -size +200000000c)" ]; then
_confirmOrQuit "$(printf "The image is rather big. Are you sure you want to copy-out \e[1;96m%s\e[39m ? " "${PATH_TO_COPY}")"
fi
PATH_TO_COPY_TO=$(dirname "${PATH_TO_COPY}")
if [ "${PATH_TO_COPY_TO}" = "/" ]; then
PATH_TO_COPY_TO=""
fi
printf "Copying out \e[1;96m%s\e[m to \e[1;96m%s\e[m ...\n" "${PATH_TO_COPY}" "shared${PATH_TO_COPY_TO}"
GUESTFISH_SHARED_DIR="$(pwd)/shared"
if [ ! -e "${GUESTFISH_SHARED_DIR}" ]; then
mkdir "${GUESTFISH_SHARED_DIR}"
fi
docker 2>&1 run \
--env LIBGUESTFS_DEBUG="${LIBGUESTFS_DEBUG}" \
--env LIBGUESTFS_TRACE="${LIBGUESTFS_TRACE}" \
--rm \
-i \
--mount type=bind,source="${GUESTFISH_SHARED_DIR}",target=/shared \
--mount type=bind,source="$(pwd)/${GUESTFISH_IMAGE}",target=/images/disk.img \
-w / \
bkahlert/libguestfs \
--ro \
--add /images/disk.img \
--mount /dev/sda2:/ \
--mount /dev/sda1:/boot \
<<COMMANDS
!mkdir -p "shared${PATH_TO_COPY}"
-copy-out "${PATH_TO_COPY}" "shared${PATH_TO_COPY_TO}"
umount-all
exit
COMMANDS
if [ -z "$(ls -A "${GUESTFISH_SHARED_DIR}")" ]; then
rmdir "${GUESTFISH_SHARED_DIR}"
fi
printf "Successfully copied out \e[1;96m%s\e[39m to \e[1;96m%s\e[39m\n" \
"${PATH_TO_COPY}" \
"shared${PATH_TO_COPY_TO}"
@bkahlert

This comment has been minimized.

Copy link
Owner Author

@bkahlert bkahlert commented Jan 17, 2021

copy-out

Simply type copy-out.
This script searches the current directory automatically for an .img file and copies its content to a newly created directory shared.

Type copy-out <path> to only copy a specific directory or file.

Uses a dockerized guestfish to do its magic. Should work on all POSIX platforms with installed Docker but only tested on macOS.

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