update-kernel.in 8.08 KB
Newer Older
1 2 3 4 5 6 7 8
#!/bin/sh -e

# update-kernel
#
# Kernel and firmware update script for Alpine installations set up
# with setup-bootable
#
# Copyright (c) 2014 Timo Teräs
9
# Copyright (c) 2014-2015 Kaarle Ritvanen
10

11 12
PREFIX=
. $PREFIX/lib/libalpine.sh
13 14 15 16

SCRIPT=update-kernel
VIRTUAL=.tmp-$SCRIPT

17 18
SUPERUSER=
[ $(id -u) -eq 0 ] && SUPERUSER=Y
19 20 21
if [ -z "$SUPERUSER" ] && [ -z "$FAKEROOTKEY" ]; then
	exec fakeroot "$0" "$@"
fi
22

23
ARCH=
24
BUILDDIR=
25
FLAVOR=
26
MEDIA=
27
MNTDIR=
28
PACKAGES=
29 30
MKINITFS_ARGS=
REPOSITORIES_FILE=/etc/apk/repositories
31 32 33
SIGNALS="HUP INT TERM"
TMPDIR=
features=
34
modloopfw=
35

Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
36
error() {
37
	echo "$SCRIPT: $1" >&2
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
38 39 40
}

usage() {
41 42 43
	[ "$2" ] && error "$2"
	local opts="[-F <feature>]... [-p <package>]..."
	local dest_args="[-a <arch>] <dest_dir>"
44
	cat >&2 <<-__EOF__
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
45

46 47 48
		Syntax: $SCRIPT $opts [$dest_args]
		        $SCRIPT -f <flavor> $opts $dest_args
		        $SCRIPT -b <build_dir> $opts [$dest_args]
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
49

50 51 52 53 54 55 56 57 58 59 60 61 62
		Options: -a|--arch <arch>          Install kernel for specified architecture
		         -b|--build <build_dir>    Install custom-built kernel
		         -e|--modloopfw <firmware> Install extra firmware in modloop
		         -f|--flavor <flavor>      Install kernel of specified flavor
		         -F|--feature <feature>    Enable initfs feature
		         -p|--package <package>    Additional module or firmware package
		         -s|--modloopsign          Sign modloop with abuild key
		         -v|--verbose              Verbose output
		         -k|--apk-pubkey <key>     Include given key in initramfs
		         -K|--hostkeys             Include host keys in initramfs
		         -C|--compression          Initramfs compression (see mkinitfs for options)
		         -M|--media                Boot media directory layout
		         --repositories-file <f>   apk repositories file
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
63

64
	__EOF__
65
	exit $1
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
66 67
}

68
QUIET_OPT="--quiet"
69
OPTS=$(getopt -l arch:,build-dir:,flavor:,feature:,modloopfw:,help,package:,modloopsign,verbose,apk-pubkey:,hostkeys,compression:,media,repositories-file: \
70
	-n $SCRIPT -o a:b:f:F:hp:svk:KC:M -- "$@") || usage 1
71

72 73
eval set -- "$OPTS"
while :; do
74
	case "$1" in
75
	-a|--arch)
76 77 78
		shift
		ARCH=$1
		;;
79
	-b|--build-dir)
80 81 82
		shift
		BUILDDIR=$1
		;;
83
	-f|--flavor)
84 85 86
		shift
		FLAVOR=$1
		;;
87
	-F|--feature)
88 89 90
		shift
		features="$features $1"
		;;
91 92 93 94
	-e|--modloopfw)
		shift
		modloopfw="$modloopfw $1"
		;;
Kaarle Ritvanen's avatar
Kaarle Ritvanen committed
95
	-h|--help)
96 97 98
		echo "$SCRIPT @VERSION@" >&2
		usage 0
		;;
99
	-p|--package)
100 101 102
		shift
		PACKAGES="$PACKAGES $1"
		;;
103 104 105
	-s|--modloopsign)
		MODLOOPSIGN=1
		;;
106
	-v|--verbose)
107 108
		QUIET_OPT=
		;;
109 110 111 112
	-k|--apk-pubkey)
		shift
		APK_PUBKEY="$1"
		;;
113
	-K|--hostkeys)
114 115
		MKINITFS_ARGS="$MKINITFS_ARGS -K"
		;;
116 117 118 119
	-C|--compression)
		shift
		MKINITFS_ARGS="$MKINITFS_ARGS -C $1"
		;;
120 121 122
	-M|--media)
		MEDIA=yes
		;;
123 124 125 126
	--repositories-file)
		shift
		REPOSITORIES_FILE=$1
		;;
127
	--)
128 129 130 131
		break
		;;
	esac
	shift
132 133 134 135 136
done

DESTDIR=$2


137
[ "$BUILDDIR" -a "$FLAVOR" ] && \
138
	usage 1 "Cannot specify both build directory and flavor"
139

140
if [ -z "$DESTDIR" ]; then
141 142 143 144 145 146 147 148 149 150 151 152
	[ "$ARCH" ] && \
		usage 1 "Cannot specify architecture when updating the current kernel"

	[ "$FLAVOR" ] && \
		usage 1 "Cannot specify flavor when updating the current kernel"

	[ "$SUPERUSER" ] || \
		usage 1 "Specify destination directory or run as superuser"

	while read MOUNT; do
		set -- $MOUNT
		[ $2 = /.modloop ] || continue
153
		DESTDIR=$(dirname $(busybox losetup $1 | cut -d " " -f 3))
154 155 156 157 158 159 160 161
		MNTDIR=$(dirname "$DESTDIR")
		break
	done < /proc/mounts

	if [ -z "$MNTDIR" ]; then
		error "Module loopback device not mounted"
		exit 1
	fi
162 163 164
fi

remount() {
165
	mount $1 -o remount "$MNTDIR"
166 167 168 169
}


ignore_sigs() {
170
	trap "" $SIGNALS
171 172 173
}

clean_up() {
174 175
	set +e
	ignore_sigs
176

177 178 179
	if [ "$SUPERUSER" ] && [ -z "$FAKEROOTKEY" ]; then
		apk del $QUIET_OPT $VIRTUAL
	fi
180
	rm -fr $TMPDIR
181 182
}

183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
sign_modloop() {
	local in="$1"
	local abuild_conf=${ABUILD_CONF:-"/etc/abuild.conf"}
	local abuild_home=${ABUILD_USERDIR:-"$HOME/.abuild"}
	local abuild_userconf=${ABUILD_USERCONF:-"$abuild_home/abuild.conf"}
	[ -f "$abuild_userconf" ] && . "$abuild_userconf"
	local privkey="$PACKAGER_PRIVKEY"
	local pubkey=${PACKAGER_PUBKEY:-"${privkey}.pub"}
	MODLOOPSIG=${in##*/}.SIGN.RSA.${pubkey##*/}
	echo "Signing: $in"
	openssl dgst -sha1 -sign "$privkey" \
		-out "$TMPDIR/$MODLOOPSIG" \
		"$in"
}

198 199 200
trap clean_up EXIT $SIGNALS


201
if [ "$SUPERUSER" ] && [ -z "$FAKEROOTKEY" ]; then
202
	apk add $QUIET_OPT --update-cache -t $VIRTUAL mkinitfs squashfs-tools kmod
203
fi
204

205
if [ -z "$features" ]; then
206
	. /etc/mkinitfs/mkinitfs.conf
207
fi
208

209
if [ -z "$FLAVOR" ]; then
210 211
	FLAVOR=$(uname -r | cut -d - -f 3-)
	[ "$FLAVOR" ] || FLAVOR=vanilla
212 213
fi

214 215
[ "$ARCH" ] || ARCH=$(apk --print-arch)

216
TMPDIR=$(mktemp -d /tmp/$SCRIPT.XXXXXX)
217
ROOT=$TMPDIR/root
218
BOOT=$ROOT/boot
219

220
_apk() {
221 222 223
	local cmd=$1
	shift

224
	apk $cmd $QUIET_OPT -p $ROOT --arch "$ARCH" \
225 226
		--keys-dir /etc/apk/keys \
		--repositories-file "$REPOSITORIES_FILE" $*
227 228
}

229
extra_pkgs() {
230 231 232 233
	local res=$(_apk search -x $1)
	if [ "$res" ]; then
		echo $*
	fi
234 235
}

236
# set up the root and get the APKINDEX for search
237
_apk add --initdb --update-cache
238

239
if [ "$BUILDDIR" ]; then
240 241 242 243 244 245 246 247 248 249
	case "$ARCH" in
		arm*|aarch64*)	_install="zinstall dtbs_install" ;;
		*)		_install="install" ;;
	esac

	mkdir -p $BOOT
	make -C "$BUILDDIR" $_install firmware_install modules_install \
		INSTALL_MOD_PATH=$ROOT \
		INSTALL_PATH=$BOOT \
		INSTALL_DTBS_PATH='$ROOT/usr/lib/linux-$(KERNELRELEASE)'
250
else
251 252 253 254 255
	if [ -z "$PACKAGES" ]; then
		PACKAGES="$(extra_pkgs "dahdi-linux-$FLAVOR" dahdi-linux)
			$(extra_pkgs "xtables-addons-$FLAVOR")"
	fi
	PACKAGES="$PACKAGES linux-$FLAVOR linux-firmware"
256
fi
257
_apk add --no-scripts alpine-base $PACKAGES
258

259 260 261 262
if [ -n "$APK_PUBKEY" ]; then
	mkdir -p "$ROOT"/etc/apk/keys
	cp "$APK_PUBKEY" "$ROOT"/etc/apk/keys/
fi
263

264 265
KVER_FLAVOR=
[ "$FLAVOR" = vanilla ] || KVER_FLAVOR=-$FLAVOR
266
KVER=$(basename $(ls -d $ROOT/lib/modules/*"$KVER_FLAVOR"))
Natanael Copa's avatar
Natanael Copa committed
267
DTBDIR=$ROOT/boot/dtbs-$FLAVOR
268
[ -d "$DTBDIR" ] || DTBDIR=$ROOT/usr/lib/linux-$KVER
269
depmod -b $ROOT "$KVER"
270 271 272 273


STAGING=$TMPDIR/boot
MODLOOP=$TMPDIR/modloop
274
MODIMG=modloop-$FLAVOR
275

276
mkdir $MODLOOP $STAGING
277
cp -a $ROOT/lib/modules $MODLOOP
278 279
mkdir -p $MODLOOP/modules/firmware
find $ROOT/lib/modules -type f -name "*.ko" | xargs modinfo -F firmware | sort -u | while read FW; do
Timo Teräs's avatar
Timo Teräs committed
280 281
	if [ -e "$ROOT/lib/firmware/$FW" ]; then
		install -pD $ROOT/lib/firmware/$FW $MODLOOP/modules/firmware/$FW
282 283 284 285
		# copy also all potentially associated files
		for _file in "$ROOT"/lib/firmware/"${FW%.*}".*; do
			install -pD "$_file" "$MODLOOP/modules/firmware/${_file#*/lib/firmware/}"
		done
Timo Teräs's avatar
Timo Teräs committed
286
	fi
287
done
288

289 290 291 292 293 294 295 296 297 298
# install extra firmware files in modloop (i.e. not detected by modinfo)
for _xfw in "$modloopfw"; do
	if [ -f "$ROOT/lib/firmware/$_xfw" ]; then
		install -pD "$ROOT/lib/firmware/$_xfw" \
			"$MODLOOP"/modules/firmware/"$_xfw"
	else
		echo "Warning: extra firmware \"$_xfw\" not found!"
	fi
done

299 300 301 302 303 304 305
# wireless regulatory db
if [ -e "$ROOT"/lib/modules/*/kernel/net/wireless/cfg80211.ko ]; then
	for _regdb in "$ROOT"/lib/firmware/regulatory.db*; do
		[ -e "$_regdb" ] && install -pD "$_regdb" "$MODLOOP"/modules/firmware/"${_regdb##*/}"
	done
fi

306
# include bluetooth firmware in modloop
307
if [ -e "$ROOT"/lib/modules/*/kernel/drivers/bluetooth/btbcm.ko ]; then
308 309 310 311 312 313
	for _btfw in "$ROOT"/lib/firmware/brcm/*.hcd; do
		install -pD "$_btfw" \
			"$MODLOOP"/modules/firmware/brcm/"${_btfw##*/}"
	done
fi

314
mksquashfs $MODLOOP "$STAGING/$MODIMG" -comp xz -exit-on-error
315

316 317 318 319 320
if [ -n "$MODLOOPSIGN" ]; then
	sign_modloop "$STAGING/$MODIMG"
	MKINITFS_ARGS="$MKINITFS_ARGS -s $TMPDIR/$MODLOOPSIG"
fi

321
mkinitfs $MKINITFS_ARGS -q -b $ROOT -F "$features base squashfs" \
322
	-o "$STAGING/initramfs-$FLAVOR" "$KVER"
323 324

for file in System.map config vmlinuz; do
325 326 327 328 329
	if [ -f "$BOOT/$file-$FLAVOR" ]; then
		cp "$BOOT/$file-$FLAVOR" $STAGING
	else
		cp "$BOOT/$file" $STAGING
	fi
330
done
331

332
if [ "$MNTDIR" ]; then
333 334 335
	ignore_sigs
	umount /.modloop
	remount -w
336
fi
337

338 339
mkdir -p "$DESTDIR"/${MEDIA:+boot/}
mv $STAGING/* "$DESTDIR"/${MEDIA:+boot/}
340

341
if [ -d "$DTBDIR" ]; then
342
	_opwd=$PWD
343 344
	case "$MEDIA,$FLAVOR" in
	yes,rpi*) _dtb="$DESTDIR/" ;;
Natanael Copa's avatar
Natanael Copa committed
345 346
	yes,*)    _dtb="$DESTDIR/boot/dtbs-$FLAVOR" ;;
	*,*)      _dtb="$DESTDIR/dtbs/dtbs-$FLAVOR" ;;
347 348 349 350 351 352
	esac
	mkdir -p "$_dtb"
	_dtb=$(realpath "$_dtb")
	cd "$DTBDIR"
	find -type f \( -name "*.dtb" -o -name "*.dtbo" \) | cpio -pudm "$_dtb" 2> /dev/null
	cd "$_opwd"
353 354
fi

355
if [ "$MNTDIR" ]; then
356 357 358 359
	set +e
	sync
	remount -r
	mount -o loop "$DESTDIR/$MODIMG" /.modloop
360
fi
361 362

exit 0