#!/bin/sh
|
#
|
# SPDX-License-Identifier: GPL-2.0-only
|
#
|
|
# 1MB blocksize
|
BLOCKSIZE=1048576
|
|
usage() {
|
echo "Usage: $(basename $0) IMAGE DEVICE"
|
}
|
|
image_details() {
|
IMG=$1
|
echo "Image details"
|
echo "============="
|
echo " image: $(basename $IMG)"
|
# stat format is different on Mac OS and Linux
|
if [ "$(uname)" = "Darwin" ]; then
|
echo " size: $(stat -L -f '%z bytes' $IMG)"
|
echo " modified: $(stat -L -f '%Sm' $IMG)"
|
else
|
echo " size: $(stat -L -c '%s bytes' $IMG)"
|
echo " modified: $(stat -L -c '%y' $IMG)"
|
fi
|
echo " type: $(file -L -b $IMG)"
|
echo ""
|
}
|
|
device_details() {
|
BLOCK_SIZE=512
|
|
echo "Device details"
|
echo "=============="
|
|
# Collect disk info using diskutil on Mac OS
|
if [ "$(uname)" = "Darwin" ]; then
|
diskutil info $DEVICE | egrep "(Device Node|Media Name|Total Size)"
|
return
|
fi
|
|
# Default / Linux information collection
|
ACTUAL_DEVICE=`readlink -f $DEVICE`
|
DEV=`basename $ACTUAL_DEVICE`
|
if [ "$ACTUAL_DEVICE" != "$DEVICE" ] ; then
|
echo " device: $DEVICE -> $ACTUAL_DEVICE"
|
else
|
echo " device: $DEVICE"
|
fi
|
if [ -f "/sys/class/block/$DEV/device/vendor" ]; then
|
echo " vendor: $(cat /sys/class/block/$DEV/device/vendor)"
|
else
|
echo " vendor: UNKNOWN"
|
fi
|
if [ -f "/sys/class/block/$DEV/device/model" ]; then
|
echo " model: $(cat /sys/class/block/$DEV/device/model)"
|
else
|
echo " model: UNKNOWN"
|
fi
|
if [ -f "/sys/class/block/$DEV/size" ]; then
|
echo " size: $(($(cat /sys/class/block/$DEV/size) * $BLOCK_SIZE)) bytes"
|
else
|
echo " size: UNKNOWN"
|
fi
|
echo ""
|
}
|
|
check_mount_device() {
|
if cat /proc/self/mounts | awk '{ print $1 }' | grep /dev/ | grep -q -E "^$1$" ; then
|
return 0
|
fi
|
return 1
|
}
|
|
is_mounted() {
|
if [ "$(uname)" = "Darwin" ]; then
|
if df | awk '{ print $1 }' | grep /dev/ | grep -q -E "^$1(s[0-9]+)?$" ; then
|
return 0
|
fi
|
else
|
if check_mount_device $1 ; then
|
return 0
|
fi
|
DEV=`basename $1`
|
if [ -d /sys/class/block/$DEV/ ] ; then
|
PARENT_BLKDEV=`basename $(readlink -f "/sys/class/block/$DEV/..")`
|
if [ "$PARENT_BLKDEV" != "block" ] ; then
|
if check_mount_device $PARENT_BLKDEV ; then
|
return 0
|
fi
|
fi
|
for CHILD_BLKDEV in `find /sys/class/block/$DEV/ -mindepth 1 -maxdepth 1 -name "$DEV*" -type d`
|
do
|
if check_mount_device /dev/`basename $CHILD_BLKDEV` ; then
|
return 0
|
fi
|
done
|
fi
|
fi
|
return 1
|
}
|
|
is_inuse() {
|
HOLDERS_DIR="/sys/class/block/`basename $1`/holders"
|
if [ -d $HOLDERS_DIR ] && [ `ls -A $HOLDERS_DIR` ] ; then
|
return 0
|
fi
|
return 1
|
}
|
|
if [ $# -ne 2 ]; then
|
usage
|
exit 1
|
fi
|
|
IMAGE=$1
|
DEVICE=$2
|
|
if [ ! -e "$IMAGE" ]; then
|
echo "ERROR: Image $IMAGE does not exist"
|
usage
|
exit 1
|
fi
|
|
if [ ! -e "$DEVICE" ]; then
|
echo "ERROR: Device $DEVICE does not exist"
|
usage
|
exit 1
|
fi
|
|
if [ "$(uname)" = "Darwin" ]; then
|
# readlink doesn't support -f on MacOS, just assume it isn't a symlink
|
ACTUAL_DEVICE=$DEVICE
|
else
|
ACTUAL_DEVICE=`readlink -f $DEVICE`
|
fi
|
if is_mounted $ACTUAL_DEVICE ; then
|
echo "ERROR: Device $DEVICE is currently mounted - check if this is the right device, and unmount it first if so"
|
device_details
|
exit 1
|
fi
|
if is_inuse $ACTUAL_DEVICE ; then
|
echo "ERROR: Device $DEVICE is currently in use (possibly part of LVM) - check if this is the right device!"
|
device_details
|
exit 1
|
fi
|
|
if [ ! -w "$DEVICE" ]; then
|
echo "ERROR: Device $DEVICE is not writable - possibly use sudo?"
|
usage
|
exit 1
|
fi
|
|
image_details $IMAGE
|
device_details
|
|
printf "Write $IMAGE to $DEVICE [y/N]? "
|
read RESPONSE
|
if [ "$RESPONSE" != "y" ]; then
|
echo "Write aborted"
|
exit 0
|
fi
|
|
echo "Writing image..."
|
if which pv >/dev/null 2>&1; then
|
pv "$IMAGE" | dd of="$DEVICE" bs="$BLOCKSIZE"
|
else
|
dd if="$IMAGE" of="$DEVICE" bs="$BLOCKSIZE"
|
fi
|
sync
|