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