update-kernel.in 5.89 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 13 14


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

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

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

33
error() {
34
	echo "$SCRIPT: $1" >&2
35 36 37
}

usage() {
38 39 40
	[ "$2" ] && error "$2"
	local opts="[-F <feature>]... [-p <package>]..."
	local dest_args="[-a <arch>] <dest_dir>"
41
	cat >&2 <<-__EOF__
42

43 44 45
		Syntax: $SCRIPT $opts [$dest_args]
		        $SCRIPT -f <flavor> $opts $dest_args
		        $SCRIPT -b <build_dir> $opts [$dest_args]
46

47 48 49 50 51 52
		Options: -a|--arch <arch>        Install kernel for specified architecture
		         -b|--build <build_dir>  Install custom-built kernel
		         -f|--flavor <flavor>    Install kernel of specified flavor
		         -F|--feature <feature>  Enable initfs feature
		         -p|--package <package>  Additional module or firmware package
		         -v|--verbose            Verbose output
53
			 -k|--apk-pubkey <key>   Include given key in initramfs
54
		         -K|--hostkeys           Include host keys in initramfs
55
		         -M|--media              Boot media directory layout
56
		         --repositories-file <f> apk repositories file
57

58
	__EOF__
59
	exit $1
60 61
}

62
QUIET_OPT="--quiet"
63 64
OPTS=$(getopt -l arch:,build-dir:,flavor:,feature:,help,package:,verbose,apk-pubkey:,hostkeys,media,repositories-file: \
	-n $SCRIPT -o a:b:f:F:hp:vk:KM -- "$@") || usage 1
65

66 67
eval set -- "$OPTS"
while :; do
68
	case "$1" in
69
	-a|--arch)
70 71 72
		shift
		ARCH=$1
		;;
73
	-b|--build-dir)
74 75 76
		shift
		BUILDDIR=$1
		;;
77
	-f|--flavor)
78 79 80
		shift
		FLAVOR=$1
		;;
81
	-F|--feature)
82 83 84
		shift
		features="$features $1"
		;;
85
	-h|--help)
86 87 88
		echo "$SCRIPT @VERSION@" >&2
		usage 0
		;;
89
	-p|--package)
90 91 92
		shift
		PACKAGES="$PACKAGES $1"
		;;
93
	-v|--verbose)
94 95
		QUIET_OPT=
		;;
96 97 98 99
	-k|--apk-pubkey)
		shift
		APK_PUBKEY="$1"
		;;
100
	-K|--hostkeys)
101 102
		MKINITFS_ARGS="$MKINITFS_ARGS -K"
		;;
103 104 105
	-M|--media)
		MEDIA=yes
		;;
106 107 108 109
	--repositories-file)
		shift
		REPOSITORIES_FILE=$1
		;;
110
	--)
111 112 113 114
		break
		;;
	esac
	shift
115 116 117 118 119
done

DESTDIR=$2


120
[ "$BUILDDIR" -a "$FLAVOR" ] && \
121
	usage 1 "Cannot specify both build directory and flavor"
122

123
if [ -z "$DESTDIR" ]; then
124 125 126 127 128 129 130 131 132 133 134 135
	[ "$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
136
		DESTDIR=$(dirname $(busybox losetup $1 | cut -d " " -f 3))
137 138 139 140 141 142 143 144
		MNTDIR=$(dirname "$DESTDIR")
		break
	done < /proc/mounts

	if [ -z "$MNTDIR" ]; then
		error "Module loopback device not mounted"
		exit 1
	fi
145 146 147
fi

remount() {
148
	mount $1 -o remount "$MNTDIR"
149 150 151 152
}


ignore_sigs() {
153
	trap "" $SIGNALS
154 155 156
}

clean_up() {
157 158
	set +e
	ignore_sigs
159

160 161 162
	if [ "$SUPERUSER" ] && [ -z "$FAKEROOTKEY" ]; then
		apk del $QUIET_OPT $VIRTUAL
	fi
163
	rm -fr $TMPDIR
164 165 166 167 168
}

trap clean_up EXIT $SIGNALS


169
if [ "$SUPERUSER" ] && [ -z "$FAKEROOTKEY" ]; then
170
	apk add $QUIET_OPT --update-cache -t $VIRTUAL mkinitfs squashfs-tools kmod
171
fi
172

173
if [ -z "$features" ]; then
174
	. /etc/mkinitfs/mkinitfs.conf
175
fi
176

177
if [ -z "$FLAVOR" ]; then
178 179
	FLAVOR=$(uname -r | cut -d - -f 3-)
	[ "$FLAVOR" ] || FLAVOR=vanilla
180 181
fi

182 183
[ "$ARCH" ] || ARCH=$(apk --print-arch)

184
TMPDIR=$(mktemp -d /tmp/$SCRIPT.XXXXXX)
185
ROOT=$TMPDIR/root
186
BOOT=$ROOT/boot
187

188
_apk() {
189 190 191
	local cmd=$1
	shift

192
	apk $cmd $QUIET_OPT -p $ROOT --arch "$ARCH" \
193 194
		--keys-dir /etc/apk/keys \
		--repositories-file "$REPOSITORIES_FILE" $*
195 196
}

197
extra_pkgs() {
198 199 200 201
	local res=$(_apk search -x $1)
	if [ "$res" ]; then
		echo $*
	fi
202 203
}

204
# set up the root and get the APKINDEX for search
205
_apk add --initdb --update-cache
206

207
if [ "$BUILDDIR" ]; then
208 209 210 211 212 213 214 215 216 217
	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)'
218
else
219 220 221 222 223
	if [ -z "$PACKAGES" ]; then
		PACKAGES="$(extra_pkgs "dahdi-linux-$FLAVOR" dahdi-linux)
			$(extra_pkgs "xtables-addons-$FLAVOR")"
	fi
	PACKAGES="$PACKAGES linux-$FLAVOR linux-firmware"
224
fi
225
_apk add --no-scripts alpine-base $PACKAGES
226

227 228 229 230
if [ -n "$APK_PUBKEY" ]; then
	mkdir -p "$ROOT"/etc/apk/keys
	cp "$APK_PUBKEY" "$ROOT"/etc/apk/keys/
fi
231

232 233
KVER_FLAVOR=
[ "$FLAVOR" = vanilla ] || KVER_FLAVOR=-$FLAVOR
234
KVER=$(basename $(ls -d $ROOT/lib/modules/*"$KVER_FLAVOR"))
235
DTBDIR=$ROOT/usr/lib/linux-$KVER
236
depmod -b $ROOT "$KVER"
237 238 239 240


STAGING=$TMPDIR/boot
MODLOOP=$TMPDIR/modloop
241
MODIMG=modloop-$FLAVOR
242

243
mkdir $MODLOOP $STAGING
244
cp -a $ROOT/lib/modules $MODLOOP
245 246
mkdir -p $MODLOOP/modules/firmware
find $ROOT/lib/modules -type f -name "*.ko" | xargs modinfo -F firmware | sort -u | while read FW; do
247 248 249
	if [ -e "$ROOT/lib/firmware/$FW" ]; then
		install -pD $ROOT/lib/firmware/$FW $MODLOOP/modules/firmware/$FW
	fi
250
done
251
mksquashfs $MODLOOP "$STAGING/$MODIMG" -comp xz -exit-on-error
252

253
mkinitfs $MKINITFS_ARGS -q -b $ROOT -F "$features base squashfs" \
254
	-o "$STAGING/initramfs-$FLAVOR" "$KVER"
255 256

for file in System.map config vmlinuz; do
257
	cp "$BOOT/$file$KVER_FLAVOR" $STAGING
258
done
259

260
if [ "$MNTDIR" ]; then
261 262 263
	ignore_sigs
	umount /.modloop
	remount -w
264
fi
265

266 267
mkdir -p "$DESTDIR"/${MEDIA:+boot/}
mv $STAGING/* "$DESTDIR"/${MEDIA:+boot/}
268

269
if [ -d "$DTBDIR" ]; then
270
	_opwd=$PWD
271 272 273 274
	case "$MEDIA,$FLAVOR" in
	yes,rpi*) _dtb="$DESTDIR/" ;;
	yes,*)    _dtb="$DESTDIR/boot/dtbs" ;;
	*,*)      _dtb="$DESTDIR/dtbs" ;;
275 276 277 278 279 280
	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"
281 282
fi

283
if [ "$MNTDIR" ]; then
284 285 286 287
	set +e
	sync
	remount -r
	mount -o loop "$DESTDIR/$MODIMG" /.modloop
288
fi
289 290

exit 0