setup-bootable.in 7.02 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
		apk del --quiet syslinux
11
	fi
12 13
	sync
	sleep 1
14
	for i in $read_only_mounts; do
15
		mount -o remount,ro "$i" || echo "Warning: Failed to remount as read-only. Is modloop mounted?"
16
	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 [-fhUusv] SOURCE [DEST]
87

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

90
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
 -U  Replace current alpine_dev in syslinux.cfg with UUID if UUID found.
97 98
 -u  Upgrade mode. Keep existing syslinux.cfg and don't run syslinux.
 -s  Force run syslinux, even if upgrade mode.
99 100 101 102 103
 -v  Verbose mode. Display whats going on.

__EOF__
	exit 1
}
104

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

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

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

121

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

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

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

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

155 156 157 158 159 160 161
# 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

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

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

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

174 175 176 177 178 179 180
# 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

181 182 183
# check if its same version
if [ -n "$upgrade" ] && [ -e "$destdir"/.alpine-release ]; then
	from_version=$(cat "$destdir"/.alpine-release)
184
	if [ -z "$force" ] && [ -n "$to_version" ] && [ "$from_version" = "$to_version" ]; then
185 186 187 188 189 190 191 192 193 194 195
		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

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

# check that we have the space we need
201 202 203 204 205 206
# 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 ))
207
vecho "Available space: $available_space MiB"
208

209 210
if [ -n "$srcdir" ]; then
	needed_space=$(cd "$srcdir" && du -m -s -c boot apks syslinux.cfg .alpine-release | awk '$2 == "total" {print $1}')
211
	vecho "Needed space:    $needed_space MiB"
212 213 214 215 216
	[ $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
217
		vecho "Copying $srcdir/$i to $destdir/.new/"
218 219 220 221 222 223
		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"
224
	echo ""
225
fi
226 227

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

231
vecho "Replacing existing files..."
232 233 234 235 236 237
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"
238 239 240
	# 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
241
		vecho "Updating syslinux.cfg to use $dest"
242 243 244
		sed -i -e "s/usbdisk/${dest##*/}/g" \
			"$destdir"/.new/syslinux.cfg
	fi
245 246
fi

247 248 249 250 251 252 253 254 255 256 257 258
# 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

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

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

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

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

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

280
syslinux $dest
281

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

cleanup