summaryrefslogtreecommitdiff
path: root/initramfs-init
blob: 99ca23673b24b34f508e1de09ec07ff2f08bcda1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
#!/bin/busybox sh

# this is the init script version
VERSION=1.0
NEWROOT=/newroot
SINGLEMODE=no

/bin/busybox --install -s

# basic environment
export PATH=/usr/bin:/bin:/usr/sbin:/sbin

# needed devs
[ -c /dev/null ] || mknod -m 666 /dev/null c 1 3

# basic mounts
mount -t proc -o noexec,nosuid,nodev proc /proc
mount -t sysfs -o noexec,nosuid,nodev sysfs /sys

# some helpers
ebegin() {
	echo -n " * $*: "
}
eend() {
	local msg
	if [ "$1" = 0 ] || [ $# -lt 1 ] ; then
		echo "ok."
	else
		shift
		echo "failed. $*"
		echo "initramfs emergency recovery shell launched"
		exec /bin/busybox sh
	fi
}

scan_drivers() {
	if [ "$AUTODETECT" != no ] ; then
		find /sys -name modalias | xargs sort -u | xargs modprobe -a 2> /dev/null
	fi
}

find_ovl() {
	local mnt="$1"
	local ovl
	local lines

	# look for apkovl's on mounted media
	ovl=$( ls -1 "$mnt"/*.apkovl.tar.gz* 2>/dev/null ) || return 1
	lines=$(echo "$ovl" | wc -l)

	if [ $lines -gt 1 ] ; then
		echo "ERROR: More than one apkovl file was found on $(basename $mnt). None will be read." >&2
		return 1
	fi
	echo "$ovl"
}

retry_mount() {
	# usb might need some time to settle so we retry a few times
	for i in $(seq 0 19); do
		mount $@ 2>&1 && return 0
		sleep 1
	done
	return 1
}

unpack_apkovl() {
	local ovl="$1"
	local dest="$2"
	local suffix=${ovl##*.}
	local i
	if [ "$suffix" = "gz" ]; then
		tar -C "$dest" -zxf "$ovl"
		return $?
	fi

	for i in $ALPINE_MNT/*/*/openssl-[0-9]*.apk $ALPINE_MNT/*/openssl-[0-9]*.apk; do
		[ -f "$i" ] && tar -C / -zxf $i && break
	done

	if ! openssl list-cipher-commands | grep "^$suffix$" > /dev/null; then
		errstr="Cipher $suffix is not supported"
		return 1
	fi
	local count=0
	# beep
	echo -e "\007"
	while [ $count -lt 3 ]; do
		openssl enc -d -$suffix -in "$ovl" | tar -C "$dest" -zx \
			2>/dev/null && return 0
		count=$(( $count + 1 ))
	done
	return 1
}

# gotta start from somewhere :)
echo "Alpine Init $VERSION"

# read the kernel options
for i in `cat /proc/cmdline` ; do
	case $i in
		s|single|1)
			SINGLEMODE=yes ;;
		modules=*)
			MODULES="`echo ${i#modules=} | tr ',' ' '`";;
		noautodetect)
			AUTODETECT=no;;
		*=*)    eval KOPT_$i ;;
		*)      eval KOPT_$i=yes ;;
	esac
done

# start bootcharting if wanted
if [ -n "$KOPT_chart" ]; then
	ebegin "Starting bootchart logging"
	/sbin/bootchartd start-initfs "$NEWROOT"
	eend 0
fi

ALPINE_DEV=${KOPT_alpine_dev%%:*}
ALPINE_DEV_FS=${KOPT_alpine_dev##*:}
if [ "$ALPINE_DEV_FS" = "$ALPINE_DEV" ]; then
	unset ALPINE_DEV_FS
fi
ALPINE_MNT=/media/$ALPINE_DEV

# hide kernel messages
dmesg -n 1

# setup /dev
ebegin "Starting mdev"
mount -t tmpfs -o exec,nosuid,mode=0755 mdev /dev
ln -s sr0 /dev/cdrom
echo "/sbin/mdev" > /proc/sys/kernel/hotplug
mdev -s
RC=$?
[ -d /dev/pts ] || mkdir -m 755 /dev/pts
[ -c /dev/ptmx ] || mknod -m 666 /dev/ptmx c 5 2
mount -t devpts -o gid=5,mode=0620,noexec,nosuid devpts /dev/pts
[ -d /dev/shm ] || mkdir /dev/shm
mount -t tmpfs -o nodev,nosuid,noexec shm /dev/shm
eend $RC

# load available drivers to get access to modloop media
ebegin "Loading boot drivers"
[ "$MODULES" ] && modprobe -a $MODULES 2> /dev/null
if [ -f /etc/modules ] ; then
	sed 's/\#.*//g' < /etc/modules |
	while read module args; do
		modprobe -q $module $args
	done
fi
scan_drivers
scan_drivers
eend 0

# check if root=... was set
if [ -n "$KOPT_root" ]; then
	if [ "$SINGLEMODE" = "yes" ]; then
		echo "Entering single mode. Type 'exit' to continue booting."
		sh
	fi
	case "$KOPT_root" in
		/dev/md*) 
			mknod $KOPT_root b 9 ${KOPT_root#/dev/md}
			raidautorun "$KOPT_root"
			;;
	esac
	ebegin "Mounting root"
	retry_mount $KOPT_root $NEWROOT 2>/dev/null
	eend $?
	cat /proc/mounts | while read DEV DIR TYPE OPTS ; do
		if [ "$DIR" != "/" -a "$DIR" != "$NEWROOT" -a -d "$DIR" ]; then
			mkdir -p $NEWROOT/$DIR
			mount -o move $DIR $NEWROOT/$DIR
		fi
	done
	sync
	exec /bin/busybox switch_root $NEWROOT $chart_init /sbin/init $KOPT_init_args
	echo "initramfs emergency recovery shell launched"
	exec /bin/busybox sh
fi

# locate boot media and mount it
ebegin "Mounting boot media"
mkdir -p $ALPINE_MNT
if [ -n "$ALPINE_DEV_FS" ]; then
	mount_opts="-t $ALPINE_DEV_FS"
fi

retry_mount $mount_opts /dev/$ALPINE_DEV $ALPINE_MNT >/dev/null 2>&1
eend $?

ebegin "Mounting loopback device for kernel modules"
modprobe loop
if [ -n "$KOPT_modloop" ]; then
	modloop=$KOPT_modloop
else
	modloop=$KOPT_BOOT_IMAGE.cmg
fi
mount -o loop,ro -t cramfs $ALPINE_MNT/$modloop /.modloop
rc=$?
if [ "$rc" = 0 ]; then
	rm -rf /lib/modules
	ln -sf /.modloop/modules /lib
fi
eend $?

if [ -d $ALPINE_MNT/firmware ]; then
	ebegin "Copying firmware from $ALPINE_MNT/firmware"
	mkdir -p /lib
	cp -R -a $ALPINE_MNT/firmware /lib/
	eend $?
fi

mkdir -p /etc/apk
for i in $ALPINE_MNT/*/APK_INDEX.gz $ALPINE_MNT/*/*/APK_INDEX.gz; do
	[ -r "$i" ] && echo ${i%/APK_INDEX.gz} >> /etc/apk/repositories
done

# early console?
if [ "$SINGLEMODE" = "yes" ]; then
	echo "Entering single mode. Type 'exit' to continue booting."
	sh
fi

# more drivers
ebegin "Loading hardware drivers"
scan_drivers
eend 0

mount -t tmpfs tmpfs $NEWROOT

# look for apkovl
if dmesg | grep '^usb-storage: waiting' >/dev/null; then
	ebegin "Waiting for USB device to settle"
	while ! dmesg | grep 'usb-storage: device scan complete' >/dev/null; do
		sleep 1
	done
	eend 0
fi
for i in usb floppy cdrom; do
	mount /media/$i 2>/dev/null || continue
	ovl=$(find_ovl /media/$i)
	[ -f "$ovl" ] && break
	umount /media/$i 2>/dev/null
done
if ! [ -f "$ovl" ]; then
	ovl=$(find_ovl $ALPINE_MNT)
fi

if [ -f "$ovl" ]; then
	ebegin "Loading user settings from $ovl"
	unpack_apkovl "$ovl" $NEWROOT
	eend $? $errstr
	umount /media/$i 2>/dev/null &
	pkgs=$(sed 's/\#.*//' $NEWROOT/etc/lbu/packages.list 2>/dev/null)
fi

# install new root
ebegin "Installing packages to root filesystem"
if [ -n "$KOPT_chart" ]; then
	pkgs="$pkgs acct"
fi
apkflags="--initdb --quiet --progress --force"
if [ -z "$KOPT_keep_apk_new" ]; then
	apkflags="$apkflags --clean-protected"
fi
apk add --root /newroot $apkflags $pkgs >/dev/null
eend $?

# copy alpine release info
cp $ALPINE_MNT/.alpine-release $NEWROOT/
ln -sf /.alpine-release $NEWROOT/etc/alpine-release

# if there is no repositories file, then use the default
if ! [ -f $NEWROOT/etc/apk/repositories ]; then
	cp /etc/apk/repositories $NEWROOT/etc/apk/repositories
fi

# setup bootchart for switch_root
chart_init=""
if [ -n "$KOPT_chart" ]; then
	/sbin/bootchartd stop-initfs "$NEWROOT"
	chart_init="/sbin/bootchartd start-rootfs"
fi

# switch over to new root
cat /proc/mounts | while read DEV DIR TYPE OPTS ; do
	if [ "$DIR" != "/" -a "$DIR" != "$NEWROOT" -a -d "$DIR" ]; then
		mkdir -p $NEWROOT/$DIR
		mount -o move $DIR $NEWROOT/$DIR
	fi
done
ln -sf /.modloop/modules $NEWROOT/lib/modules
sync

echo ""
if [ -x $NEWROOT/sbin/init ]; then
	exec /bin/busybox switch_root $NEWROOT $chart_init /sbin/init $KOPT_init_args
fi

echo "initramfs emergency recovery shell launched"
exec /bin/busybox sh
reboot