poky/scripts/contrib/ddimage
Paul Eggleton d3a9f43305 scripts/contrib/ddimage: replace blacklist with mount check
The blacklist, whilst previously useful for safety, is now becoming
obsolete - on my current system, the main storage is at /dev/nvme* and
if I plug in a USB stick it shows up as /dev/sdb which was previously
blacklisted. To make this more flexible, remove the blacklist and
instead check if the specified device is mounted, has a partition
that is mounted, or is otherwise in use according to the kernel, and
show an appropriate error and quit if so.

To make this robust, also ensure we handle where the specified device is
a symlink to another device.

(From OE-Core rev: 49043de1a7716ad612fb92a2e8a52e43d253c800)

Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2019-07-03 17:00:57 +01:00

166 lines
3.5 KiB
Bash
Executable File

#!/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 [ "$(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 does not exist or is not writable"
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