1#!/bin/sh 2# 3# SPDX-License-Identifier: GPL-2.0-only 4# 5 6# 1MB blocksize 7BLOCKSIZE=1048576 8 9usage() { 10 echo "Usage: $(basename $0) IMAGE DEVICE" 11} 12 13image_details() { 14 IMG=$1 15 echo "Image details" 16 echo "=============" 17 echo " image: $(basename $IMG)" 18 # stat format is different on Mac OS and Linux 19 if [ "$(uname)" = "Darwin" ]; then 20 echo " size: $(stat -L -f '%z bytes' $IMG)" 21 echo " modified: $(stat -L -f '%Sm' $IMG)" 22 else 23 echo " size: $(stat -L -c '%s bytes' $IMG)" 24 echo " modified: $(stat -L -c '%y' $IMG)" 25 fi 26 echo " type: $(file -L -b $IMG)" 27 echo "" 28} 29 30device_details() { 31 BLOCK_SIZE=512 32 33 echo "Device details" 34 echo "==============" 35 36 # Collect disk info using diskutil on Mac OS 37 if [ "$(uname)" = "Darwin" ]; then 38 diskutil info $DEVICE | egrep "(Device Node|Media Name|Total Size)" 39 return 40 fi 41 42 # Default / Linux information collection 43 ACTUAL_DEVICE=`readlink -f $DEVICE` 44 DEV=`basename $ACTUAL_DEVICE` 45 if [ "$ACTUAL_DEVICE" != "$DEVICE" ] ; then 46 echo " device: $DEVICE -> $ACTUAL_DEVICE" 47 else 48 echo " device: $DEVICE" 49 fi 50 if [ -f "/sys/class/block/$DEV/device/vendor" ]; then 51 echo " vendor: $(cat /sys/class/block/$DEV/device/vendor)" 52 else 53 echo " vendor: UNKNOWN" 54 fi 55 if [ -f "/sys/class/block/$DEV/device/model" ]; then 56 echo " model: $(cat /sys/class/block/$DEV/device/model)" 57 else 58 echo " model: UNKNOWN" 59 fi 60 if [ -f "/sys/class/block/$DEV/size" ]; then 61 echo " size: $(($(cat /sys/class/block/$DEV/size) * $BLOCK_SIZE)) bytes" 62 else 63 echo " size: UNKNOWN" 64 fi 65 echo "" 66} 67 68check_mount_device() { 69 if cat /proc/self/mounts | awk '{ print $1 }' | grep /dev/ | grep -q -E "^$1$" ; then 70 return 0 71 fi 72 return 1 73} 74 75is_mounted() { 76 if [ "$(uname)" = "Darwin" ]; then 77 if df | awk '{ print $1 }' | grep /dev/ | grep -q -E "^$1(s[0-9]+)?$" ; then 78 return 0 79 fi 80 else 81 if check_mount_device $1 ; then 82 return 0 83 fi 84 DEV=`basename $1` 85 if [ -d /sys/class/block/$DEV/ ] ; then 86 PARENT_BLKDEV=`basename $(readlink -f "/sys/class/block/$DEV/..")` 87 if [ "$PARENT_BLKDEV" != "block" ] ; then 88 if check_mount_device $PARENT_BLKDEV ; then 89 return 0 90 fi 91 fi 92 for CHILD_BLKDEV in `find /sys/class/block/$DEV/ -mindepth 1 -maxdepth 1 -name "$DEV*" -type d` 93 do 94 if check_mount_device /dev/`basename $CHILD_BLKDEV` ; then 95 return 0 96 fi 97 done 98 fi 99 fi 100 return 1 101} 102 103is_inuse() { 104 HOLDERS_DIR="/sys/class/block/`basename $1`/holders" 105 if [ -d $HOLDERS_DIR ] && [ `ls -A $HOLDERS_DIR` ] ; then 106 return 0 107 fi 108 return 1 109} 110 111if [ $# -ne 2 ]; then 112 usage 113 exit 1 114fi 115 116IMAGE=$1 117DEVICE=$2 118 119if [ ! -e "$IMAGE" ]; then 120 echo "ERROR: Image $IMAGE does not exist" 121 usage 122 exit 1 123fi 124 125if [ ! -e "$DEVICE" ]; then 126 echo "ERROR: Device $DEVICE does not exist" 127 usage 128 exit 1 129fi 130 131if [ "$(uname)" = "Darwin" ]; then 132 # readlink doesn't support -f on MacOS, just assume it isn't a symlink 133 ACTUAL_DEVICE=$DEVICE 134else 135 ACTUAL_DEVICE=`readlink -f $DEVICE` 136fi 137if is_mounted $ACTUAL_DEVICE ; then 138 echo "ERROR: Device $DEVICE is currently mounted - check if this is the right device, and unmount it first if so" 139 device_details 140 exit 1 141fi 142if is_inuse $ACTUAL_DEVICE ; then 143 echo "ERROR: Device $DEVICE is currently in use (possibly part of LVM) - check if this is the right device!" 144 device_details 145 exit 1 146fi 147 148if [ ! -w "$DEVICE" ]; then 149 echo "ERROR: Device $DEVICE is not writable - possibly use sudo?" 150 usage 151 exit 1 152fi 153 154image_details $IMAGE 155device_details 156 157printf "Write $IMAGE to $DEVICE [y/N]? " 158read RESPONSE 159if [ "$RESPONSE" != "y" ]; then 160 echo "Write aborted" 161 exit 0 162fi 163 164echo "Writing image..." 165if which pv >/dev/null 2>&1; then 166 pv "$IMAGE" | dd of="$DEVICE" bs="$BLOCKSIZE" 167else 168 dd if="$IMAGE" of="$DEVICE" bs="$BLOCKSIZE" 169fi 170sync 171