update-kernel.in 5.58 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 17
SUPERUSER=
[ $(id -u) -eq 0 ] && SUPERUSER=Y

18
ARCH=
19
BUILDDIR=
20
FLAVOR=
21
MNTDIR=
22
PACKAGES=
23 24
MKINITFS_ARGS=
REPOSITORIES_FILE=/etc/apk/repositories
25 26 27 28
SIGNALS="HUP INT TERM"
TMPDIR=
features=

29
error() {
30
	echo "$SCRIPT: $1" >&2
31 32 33
}

usage() {
34 35 36 37
	[ "$2" ] && error "$2"
	local opts="[-F <feature>]... [-p <package>]..."
	local dest_args="[-a <arch>] <dest_dir>"
	cat >&2 <<EOF
38

39 40 41
Syntax: $SCRIPT $opts [$dest_args]
        $SCRIPT -f <flavor> $opts $dest_args
        $SCRIPT -b <build_dir> $opts [$dest_args]
42

43 44
Options: -a|--arch <arch>        Install kernel for specified architecture
         -b|--build <build_dir>  Install custom-built kernel
45 46 47
         -f|--flavor <flavor>    Install kernel of specified flavor
         -F|--feature <feature>  Enable initfs feature
         -p|--package <package>  Additional module or firmware package
48
         -v|--verbose            Verbose output
49 50
         -K|--hostkeys           Include host keys in initramfs
         --repositories-file <f> apk repositories file
51 52

EOF
53
	exit $1
54 55
}

56
QUIET_OPT="--quiet"
57
OPTS=$(getopt -l arch:,build-dir:,flavor:,feature:,help,package:,verbose,hostkeys,repositories-file: \
58
	-n $SCRIPT -o a:b:f:F:hp:vK -- "$@") || usage 1
59 60
eval set -- "$OPTS"
while :; do
61
	case "$1" in
62
	-a|--arch)
63 64 65
		shift
		ARCH=$1
		;;
66
	-b|--build-dir)
67 68 69
		shift
		BUILDDIR=$1
		;;
70
	-f|--flavor)
71 72 73
		shift
		FLAVOR=$1
		;;
74
	-F|--feature)
75 76 77
		shift
		features="$features $1"
		;;
78
	-h|--help)
79 80 81
		echo "$SCRIPT @VERSION@" >&2
		usage 0
		;;
82
	-p|--package)
83 84 85
		shift
		PACKAGES="$PACKAGES $1"
		;;
86
	-v|--verbose)
87 88
		QUIET_OPT=
		;;
89
	-K|--hostkeys)
90 91 92 93 94 95
		MKINITFS_ARGS="$MKINITFS_ARGS -K"
		;;
	--repositories-file)
		shift
		REPOSITORIES_FILE=$1
		;;
96
	--)
97 98 99 100
		break
		;;
	esac
	shift
101 102 103 104 105
done

DESTDIR=$2


106
[ "$BUILDDIR" -a "$FLAVOR" ] && \
107
	usage 1 "Cannot specify both build directory and flavor"
108

109
if [ -z "$DESTDIR" ]; then
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
	[ "$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
		DESTDIR=$(dirname $(losetup $1 | cut -d " " -f 3))
		MNTDIR=$(dirname "$DESTDIR")
		break
	done < /proc/mounts

	if [ -z "$MNTDIR" ]; then
		error "Module loopback device not mounted"
		exit 1
	fi
131 132 133
fi

remount() {
134
	mount $1 -o remount "$MNTDIR"
135 136 137 138
}


ignore_sigs() {
139
	trap "" $SIGNALS
140 141 142
}

clean_up() {
143 144
	set +e
	ignore_sigs
145

146 147
	[ "$SUPERUSER" ] && apk del $QUIET_OPT $VIRTUAL
	rm -fr $TMPDIR
148 149 150 151 152
}

trap clean_up EXIT $SIGNALS


153
if [ "$SUPERUSER" ]; then
154
	apk add $QUIET_OPT --update-cache -t $VIRTUAL mkinitfs squashfs-tools kmod
155
fi
156

157
if [ -z "$features" ]; then
158
	. /etc/mkinitfs/mkinitfs.conf
159
fi
160

161
if [ -z "$FLAVOR" ]; then
162 163
	FLAVOR=$(uname -r | cut -d - -f 3-)
	[ "$FLAVOR" ] || FLAVOR=vanilla
164 165
fi

166 167
[ "$ARCH" ] || ARCH=$(apk --print-arch)

168
TMPDIR=$(mktemp -d /tmp/$SCRIPT.XXXXXX)
169
ROOT=$TMPDIR/root
170
BOOT=$ROOT/boot
171
WRAPPER=
172 173

_exec() {
174
	$WRAPPER "$@"
175
}
176

177
_apk() {
178 179 180 181 182 183 184 185 186 187 188 189
	local cmd=$1
	shift

	local wrapper=
	if [ -z "$SUPERUSER" ]; then
		local opt=
		local fake_env=$TMPDIR/fake-env
		if [ -f $fake_env ]; then
			opt="-i $fake_env"
			WRAPPER="fakeroot $opt --"
		fi
		wrapper="fakeroot $opt -s $fake_env --"
190 191
	fi

192 193 194
	$wrapper apk $cmd $QUIET_OPT -p $ROOT --arch "$ARCH" \
		--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
KVER_FLAVOR=
[ "$FLAVOR" = vanilla ] || KVER_FLAVOR=-$FLAVOR
230
KVER=$(basename $(ls -d $ROOT/lib/modules/*"$KVER_FLAVOR"))
231
DTBDIR=$ROOT/usr/lib/linux-$KVER
232
depmod -b $ROOT "$KVER"
233 234 235 236


STAGING=$TMPDIR/boot
MODLOOP=$TMPDIR/modloop
237
MODIMG=modloop-$FLAVOR
238
DTB_STAGING=$TMPDIR/dtbs
239

240
mkdir $DTB_STAGING $MODLOOP $STAGING
241
cp -a $ROOT/lib/modules $MODLOOP
242 243
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
244 245 246
	if [ -e "$ROOT/lib/firmware/$FW" ]; then
		install -pD $ROOT/lib/firmware/$FW $MODLOOP/modules/firmware/$FW
	fi
247
done
248
_exec mksquashfs $MODLOOP "$STAGING/$MODIMG" -comp xz
249

250
_exec mkinitfs $MKINITFS_ARGS -q -b $ROOT -F "$features base squashfs" \
251
	-o "$STAGING/initramfs-$FLAVOR" "$KVER"
252 253

for file in System.map config vmlinuz; do
254
	cp "$BOOT/$file$KVER_FLAVOR" $STAGING
255
done
256

257
if [ "$MNTDIR" ]; then
258 259 260
	ignore_sigs
	umount /.modloop
	remount -w
261
fi
262

263
mv $STAGING/* "$DESTDIR"
264

265
if [ -d "$DTBDIR" ]; then
266 267 268 269 270 271 272 273 274 275
	_opwd=$PWD
	case "$FLAVOR" in
		rpi*) _dtb="$DESTDIR" ;;
		*) _dtb="$DESTDIR/dtbs" ;;
	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"
276 277
fi

278
if [ "$MNTDIR" ]; then
279 280 281 282
	set +e
	sync
	remount -r
	mount -o loop "$DESTDIR/$MODIMG" /.modloop
283
fi
284 285

exit 0