summaryrefslogtreecommitdiffstats
path: root/scripts/contrib/ddimage
blob: a7dc5f7487bee23f3c17f28eab28032972b4e3ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#!/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