setup-bootable.in 6.94 KB
Newer Older
1
2
#!/bin/sh

3
prog=${0##*/}
4
version=@VERSION@
5

6
cleanup() {
7
	local i=
8
	cd /
9
	if [ -n "$uninstalls" ]; then
10
11
		apk del -q syslinux
	fi
12
13
	sync
	sleep 1
14
15
16
	for i in $read_only_mounts; do
		mount -o remount,ro "$i"
	done
17
18
	if [ -n "$umounts" ]; then
		umount $umounts
19
20
21
22
23
24
25
26
27
	fi
}

die() {
	echo "$@" >&2
	cleanup
	exit 1
}

28
29
30
31
32
33
34
35
36
37
38
39
40
41
# find device for mountpoint
find_dev() {
	local mnt="${1%/}" # strip trailing /
	awk "\$2 == \"$mnt\" {print \$1}" /proc/mounts
}

# check if given device is on usb bus
on_usb_bus() {
	local dev="$1"
	[ -e /sys/block/$dev ] || return 1
	local sysdev=$(readlink -f /sys/block/$dev/device)
	test "${sysdev##*/usb[0-9]}" != "$sysdev"
}

42
43
44
45
46
47
48
49
50
51
52
# mount source as loopback and set srcdir
mount_srcdir() {
	local srcmnt=${MNT:-/mnt}
	mount -o loop -t iso9660 "$src" $srcmnt \
		|| die "Failed to mount loopback $src"
	umounts="$srcmnt"
	srcdir="$srcmnt"
	if ! [ -f "$srcdir"/.alpine-release ]; then
		die "No .alpine-release found on image $src"
	fi
}
53

54
55
56
57
58
vecho() {
	[ -z "$verbose" ] && return 0
	echo "$@"
}

59
60
61
62
63
64
65
66
# check if given dir is read-only
is_read_only() {
	local tmpfile=$(mktemp -p "$1" 2>/dev/null)
	[ -z "$tmpfile" ] && return 0
	rm -f "$tmpfile"
	return 1
}

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# find what disk this partition belongs to
find_disk_dev() {
	local i= sysfsname=${1#/dev/}
	sysfsname=${sysfsname//\/!}	# cciss/c0d0 -> cciss!c0d0
	if [ -e /sys/block/$sysfsname ]; then
		echo "/dev/${sysfsname//!/'/'}"
		return 0
	fi
	for i in /sys/block/*/$sysfsname; do
		[ -e "$i" ] || continue
		echo "$i" | cut -d/ -f4 | sed -e 's:!:/:g' -e 's:^:/dev/:'
		return 0
	done
	return 1
}

83
84
usage() {
	cat <<__EOF__
85
$prog $version
86
usage: $prog [-hu] SOURCE [DEST]
87

88
89
90
Copy the contents of SOURCE to DEST and make DEST bootable.

SOURCE can be a directory or a ISO image. DEST can be a mounted directory 
91
or a device. If DEST is ommitted /media/usb will be used.
92
93

Options:
94
95
 -f  Force overwrite existing files. Will overwrite syslinux.cfg if upgrade.
 -h  Show this help.
96
97
 -k  Keep current alpine_dev in syslinux.cfg. Without this it will be replaced
     with the UUID.
98
99
 -u  Upgrade mode. Keep existing syslinux.cfg and don't run syslinux.
 -s  Force run syslinux, even if upgrade mode.
100
101
102
103
104
 -v  Verbose mode. Display whats going on.

__EOF__
	exit 1
}
105

106
while getopts "fhkusv" opt; do
107
	case "$opt" in
108
109
	f) force=1;;
	h) usage;;
110
	k) keep_alpine_dev=1;;
111
112
113
	u) upgrade=1;;
	s) syslinux=1;;
	v) verbose=1;;
114
115
	esac
done
116

117
shift $(($OPTIND - 1))
118

119
src=${1}
120
121
dest=${2:-/media/usb}

122

123
124
[ -z "$src" ] && usage

125
126
srcdir=
# Find the srcdir or srcurl. mount loopback if needed
127
if [ -f "$src"/.alpine-release ]; then
128
	srcdir="`echo $src | sed -r 's,/$,,'`"
129
else
130
131
132
133
134
135
136
137
	case "$src" in
	http://*|ftp://*) srcurl="$src";;
	*) mount_srcdir;;
	esac
fi

if [ -n "$srcdir" ]; then
	to_version=$(cat "$srcdir"/.alpine-release)
138
139
140
141
fi

# find target device
if [ -d "$dest" ]; then
142
	dest=${dest%/} # strip trailing /
143
144
145
146
147
	if ! awk '{print $2}' /proc/mounts | grep -q "^$dest\$"; then
		mount "$dest" || die "Failed to mount $dest"
		umounts="$umounts $dest"
	fi
	destdir="$dest"
148
	dest=$(find_dev "$destdir")
149
150
151
152
elif [ -b "$dest" ]; then
	destdir="/media/${dest##*/}"
	mkdir -p "$destdir"
	mount "$dest" "$destdir" || die "Failed to mount $dest on $destdir"
153
	umounts="$umounts $destdir"
154
fi
155

156
157
158
159
160
161
162
# remount as rw if needed
if is_read_only "$destdir"; then
	vecho "Remounting $destdir as read/write"
	mount -o remount,rw "$dest" || die "Failed to remount $destdir as rw"
	read_only_mounts="$read_only_mounts $destdir"
fi

163
164
165
# fish out label, uuid and type
eval $(blkid $dest | cut -d: -f2-)

166
vecho "Using $dest as target (mounted on $destdir)"
167
168
169
170
171
172

# find parent device (i.e sda)
dev="$dest"
while [ -L "$dev" ]; do
	dev=$(readlink -f $dev)
done
173
parent_dev=$(find_disk_dev)
174

175
176
177
178
179
180
181
# check if this files exist and not in upgrade mode
if [ -z "$upgrade" ] && [ -z "$force" ]; then
	for i in boot apks syslinux.cfg .alpine-release; do
		[ -e "$destdir"/$i ] && die "$destdir/$i already exists. Aborting"
	done
fi

182
183
184
# check if its same version
if [ -n "$upgrade" ] && [ -e "$destdir"/.alpine-release ]; then
	from_version=$(cat "$destdir"/.alpine-release)
185
	if [ -z "$force" ] && [ -n "$to_version" ] && [ "$from_version" = "$to_version" ]; then
186
187
188
189
190
191
192
193
194
195
196
		die "Source and target seems to have same version ($from_version). Aborting."
	fi
fi

# Display what versions we are installing/upgrading
if [ -n "$from_version" ]; then
	echo "Upgrading $dest from $from_version to $to_version"
else
	echo "Copying $to_version to $dest (mounted on $destdir)"
fi

197
198
# remove partial upgrades if any.
rm -rf "$destdir"/.new "$destdir"/.old
199
mkdir -p "$destdir"/.new || die "Failed to create $destdir/.new"
200
201

# check that we have the space we need
202
203
204
205
206
207
# we calculate on MB since shell arthimetic gets problems with big disks
# and bytes.
free_blocks=$(stat -f -c "%f" "$destdir")
block_size=$(stat -f -c "%s" "$destdir")
blocks_per_mb=$(( 1024 * 1024 / $block_size))
available_space=$(( $free_blocks / $blocks_per_mb ))
208
vecho "Available space: $available_space MiB"
209

210
211
if [ -n "$srcdir" ]; then
	needed_space=$(cd "$srcdir" && du -m -s -c boot apks syslinux.cfg .alpine-release | awk '$2 == "total" {print $1}')
212
	vecho "Needed space:    $needed_space MiB"
213
214
215
216
217
	[ $available_space -lt $needed_space ] \
		&& die "Not enough space on $destdir. Aborting."

	# copy the files to .new
	for i in boot apks syslinux.cfg .alpine-release; do
218
		vecho "Copying $srcdir/$i to $destdir/.new/"
219
220
221
222
223
224
		cp -a "$srcdir"/$i "$destdir"/.new/
	done
elif [ -n "$srcurl" ]; then
	cd "$destdir"/.new
	${WGET:-wget} -O - "$srcurl" | uniso \
		|| die "Failed to download or extract $srcurl"
225
	echo ""
226
fi
227
228

# make sure files are really there before we replace existing
229
vecho "Flushing cache..."
230
231
sync

232
vecho "Replacing existing files..."
233
234
235
236
237
238
mkdir -p "$destdir"/.old || die "Failed to create $destdir/.old"

# do we want keep existing syslinux.cfg?
tomove="boot apks .alpine-release"
if [ -n "$force" ] || ! [ -e "$destdir"/syslinux.cfg ]; then
	tomove="$tomove syslinux.cfg"
239
240
241
	# update syslinux.cfg unless device is on usb bus
	# this is so we can boot from CF's and harddisk 
	if ! on_usb_bus $parent_dev; then
242
		vecho "Updating syslinux.cfg to use $dest"
243
244
245
		sed -i -e "s/usbdisk/${dest##*/}/g" \
			"$destdir"/.new/syslinux.cfg
	fi
246
247
fi

248
249
250
251
252
253
254
255
256
257
258
259
# move current files to .old
for i in $tomove; do
	if [ -e "$destdir"/$i ]; then
		mv "$destdir"/$i "$destdir"/.old/ || die "Failed to move $destdir/$i to $destdir/.old/"
	fi
done

# move .new to current
for i in $tomove; do
	mv "$destdir"/.new/$i "$destdir"/ || die "Failed to move $destdir/.new/ to $destdir"
done

260
if [ -z "$keep_alpine_dev" ] && [ -n "$UUID" ]; then
261
	sed -i -e "s/alpine_dev=[^ \t:]\+/alpine_dev=UUID=$UUID/" \
262
263
264
		"$destdir"/syslinux.cfg
fi

265
266
267
268
# cleanup
[ -z "$keep_old" ] && rm -rf "$destdir"/.old "$destdir"/.new

# If we only copy then we are done.
269
if [ -n "$upgrade" ] && [ -z "$syslinux" ]; then
270
271
272
	cleanup
	exit 0
fi
273

274
275
276
echo "Making $dest bootable..."

if ! [ -x "$(which syslinux)" ]; then
277
278
279
	apk add -q syslinux || die "Failed to install syslinux"
	uninstalls="syslinux"
fi
280

281
syslinux $dest
282

283
284
if [ -b $parent_dev ]; then
	dd if=/usr/share/syslinux/mbr.bin of=$parent_dev
285
else
286
	echo "Warning: Could not find the parent device for $dest"
287
288
289
fi

cleanup