1#!/bin/sh
2
3fslist="proc sys dev run"
4rodir=run/initramfs/ro
5rwdir=run/initramfs/rw
6upper=$rwdir/cow
7work=$rwdir/work
8
9cd /
10mkdir -p $fslist
11mount dev dev -tdevtmpfs
12mount sys sys -tsysfs
13mount proc proc -tproc
14if ! grep run proc/mounts
15then
16	mount tmpfs run -t tmpfs -o mode=755,nodev
17fi
18
19mkdir -p $rodir $rwdir
20
21cp -rp init shutdown update whitelist bin sbin usr lib etc var run/initramfs
22
23# To start a interactive shell with job control at this point, run
24# getty 38400 ttyS4
25
26findmtd() {
27	m=$(grep -xl "$1" /sys/class/mtd/*/name)
28	m=${m%/name}
29	m=${m##*/}
30	echo $m
31}
32
33blkid_fs_type() {
34	# Emulate util-linux's `blkid -s TYPE -o value $1`
35	# Example busybox blkid output:
36	#    # blkid /dev/mtdblock5
37	#    /dev/mtdblock5: TYPE="squashfs"
38	# Process output to extract TYPE value "squashfs".
39	blkid $1 | sed -e 's/^.*TYPE="//' -e 's/".*$//'
40}
41
42probe_fs_type() {
43	fst=$(blkid_fs_type $1)
44	echo ${fst:=jffs2}
45}
46
47# This fw_get_env_var is a possibly broken version of fw_printenv that
48# does not check the crc or flag byte.
49# The u-boot environment starts with a crc32, followed by a flag byte
50# when a redundannt environment is configured, followed by var=value\0 sets.
51# The flag byte for nand is a 1 byte counter; for nor it is a 1 or 0 byte.
52
53get_fw_env_var() {
54	# do we have 1 or 2 copies of the environment?
55	# count non-blank non-comment lines
56	# copies=$(grep -v ^# /etc/fw_env.config | grep -c [::alnum::])
57	# ... we could if we had the fw_env.config in the initramfs
58	copies=2
59
60	# * Change \n to \r and \0 to \n
61	# * Skip to the 5th byte to skip over crc
62	# * then skip to the first or 2nd byte to skip over flag if it exists
63	# * stop parsing at first empty line corresponding to the
64	#   double \0 at the end of the environment.
65	# * print the value of the variable name passed as argument
66
67	envdev=$(findmtd u-boot-env)
68	if test -n $envdev
69	then
70		cat /dev/$envdev |
71		tr '\n\000' '\r\n' |
72		tail -c +5 | tail -c +${copies-1} |
73		sed -ne '/^$/,$d' -e "s/^$1=//p"
74	fi
75}
76
77setup_resolv() {
78	runresolv=/run/systemd/resolve/resolv.conf
79	etcresolv=/etc/resolv.conf
80
81	if test ! -e $etcresolv -a ! -L $etcresolv
82	then
83		mkdir -p ${runresolv%/*}
84		ln -s $runresolv $etcresolv
85	fi
86	if test ! -f $runresolv
87	then
88		cat  /proc/net/pnp > $runresolv
89	fi
90
91	return 0
92}
93
94try_tftp() {
95	# split into  tftp:// host:port/ path/on/remote
96	# then spilt off / and then :port from the end of host:port/
97	# and : from the beginning of port
98
99	rest="${1#tftp://}"
100	path=${rest#*/}
101	host=${rest%$path}
102	host="${host%/}"
103	port="${host#${host%:*}}"
104	host="${host%$port}"
105	port="${port#:}"
106
107	setup_resolv
108
109	if test -z "$host" -o -z "$path"
110	then
111		debug_takeover "Invalid tftp download url '$url'."
112	elif echo "Downloading '$url' from $host ..."  &&
113		! tftp -g -r "$path" -l /run/image-rofs "$host" ${port+"$port"}
114	then
115		debug_takeover "Download of '$url' failed."
116	fi
117}
118
119try_wget() {
120	setup_resolv
121
122	echo "Downloading '$1' ..."
123	if ! wget -O /run/image-rofs "$1"
124	then
125		debug_takeover "Download of '$url' failed."
126	fi
127}
128
129debug_takeover() {
130	echo "$@"
131
132	if ! grep -w enable-initrd-debug-sh "$optfile"
133	then
134		echo "Fatal error, triggering kernel panic!"
135		exit 1
136	fi
137
138	test -n "$@" && echo Try to manually fix.
139	cat << HERE
140After fixing run exit to continue this script, or reboot -f to retry, or
141touch /takeover and exit to become PID 1 allowing editing of this script.
142HERE
143
144	while ! /bin/sh && ! test -f /takeover
145	do
146		echo /bin/sh failed, retrying
147	done
148
149	# Touch /takeover in the above shell to become pid 1
150	if test -e /takeover
151	then
152		cat << HERE
153
154Takeover of init requested.  Executing /bin/sh as PID 1.
155When finished exec new init or cleanup and run reboot -f.
156
157Warning: No job control!  Shell exit will panic the system!
158HERE
159		export PS1=init#\
160		exec /bin/sh
161	fi
162}
163
164rofs=$(findmtd rofs)
165rwfs=$(findmtd rwfs)
166
167rodev=/dev/mtdblock${rofs#mtd}
168rwdev=/dev/mtdblock${rwfs#mtd}
169
170# Set to y for yes, anything else for no.
171force_rwfst_jffs2=y
172flash_images_before_init=n
173consider_download_files=y
174consider_download_tftp=y
175consider_download_http=y
176consider_download_ftp=y
177
178rofst=squashfs
179rwfst=$(probe_fs_type $rwdev)
180roopts=ro
181rwopts=rw
182
183image=/run/initramfs/image-
184trigger=${image}rwfs
185
186init=/sbin/init
187fsckbase=/sbin/fsck.
188fsck=$fsckbase$rwfst
189fsckopts=-a
190optfile=/run/initramfs/init-options
191optbase=/run/initramfs/init-options-base
192urlfile=/run/initramfs/init-download-url
193update=/run/initramfs/update
194
195if test -e /${optfile##*/}
196then
197	cp /${optfile##*/} $optfile
198fi
199
200if test -e /${optbase##*/}
201then
202	cp /${optbase##*/} $optbase
203else
204	touch $optbase
205fi
206
207if test ! -f $optfile
208then
209	cat /proc/cmdline $optbase > $optfile
210	get_fw_env_var openbmcinit >> $optfile
211	get_fw_env_var openbmconce >> $optfile
212fi
213
214echo rofs = $rofs $rofst   rwfs = $rwfs $rwfst
215
216if grep -w debug-init-sh $optfile
217then
218	if grep -w enable-initrd-debug-sh "$optfile"
219	then
220		debug_takeover "Debug initial shell requested by command line."
221	else
222		echo "Need to also add enable-initrd-debug-sh for debug shell."
223	fi
224fi
225
226if test "x$consider_download_files" = xy &&
227	grep -w openbmc-init-download-files $optfile
228then
229	if test -f ${urlfile##*/}
230	then
231		cp ${urlfile##*/} $urlfile
232	fi
233	if test ! -f $urlfile
234	then
235		get_fw_env_var openbmcinitdownloadurl > $urlfile
236	fi
237	url="$(cat $urlfile)"
238	rest="${url#*://}"
239	proto="${url%$rest}"
240
241	if test -z "$url"
242	then
243		echo "Download url empty.  Ignoring download request."
244	elif test -z "$proto"
245	then
246		echo "Download failed."
247	elif test "$proto" = tftp://
248	then
249		if test "x$consider_download_tftp" = xy
250		then
251			try_tftp "$url"
252		else
253			echo "Download failed."
254		fi
255	elif test "$proto" = http://
256	then
257		if test "x$consider_download_http" = xy
258		then
259			try_wget "$url"
260		else
261			echo "Download failed."
262		fi
263	elif test "$proto" = ftp://
264	then
265		if test "x$consider_download_ftp" = xy
266		then
267			try_wget "$url"
268		else
269			echo "Download failed."
270		fi
271	else
272		echo "Download failed."
273	fi
274fi
275
276# If there are images in root move them to /run/initramfs/ or /run/ now.
277imagebasename=${image##*/}
278if test -n "${imagebasename}" && ls /${imagebasename}* > /dev/null 2>&1
279then
280	if test "x$flash_images_before_init" = xy
281	then
282		echo "Flash images found, will update before starting init."
283		mv /${imagebasename}* ${image%$imagebasename}
284	else
285		echo "Flash images found, will use but deferring flash update."
286		mv /${imagebasename}* /run/
287	fi
288fi
289
290if grep -w clean-rwfs-filesystem $optfile
291then
292	echo "Cleaning of read-write overlay filesystem requested."
293	touch $trigger
294fi
295
296if grep -w factory-reset $optfile
297then
298	echo "Factory reset requested."
299	touch $trigger
300	do_save=--no-save-files
301else
302	do_save=--save-files
303fi
304
305if test "x$force_rwfst_jffs2" = xy -a $rwfst != jffs2 -a ! -f $trigger
306then
307	echo "Converting read-write overlay filesystem to jffs2 forced."
308	touch $trigger
309fi
310
311if ls $image* > /dev/null 2>&1
312then
313	if ! test -x $update
314	then
315		debug_takeover "Flash update requested but $update missing!"
316	elif test -f $trigger -a ! -s $trigger
317	then
318		if [ $do_save = "--save-files" ]
319		then
320			echo "Saving selected files from read-write overlay filesystem."
321		else
322			echo "No files will be selected for save."
323		fi
324		$update --no-restore-files $do_save
325		echo "Clearing read-write overlay filesystem."
326		flash_eraseall /dev/$rwfs
327		echo "Restoring saved files to read-write overlay filesystem."
328		touch $trigger
329		$update --no-save-files --clean-saved-files
330	else
331		$update --clean-saved-files $do_save
332	fi
333
334	rwfst=$(probe_fs_type $rwdev)
335	fsck=$fsckbase$rwfst
336fi
337
338if grep -w overlay-filesystem-in-ram $optfile
339then
340	rwfst=none
341fi
342
343copyfiles=
344if grep -w copy-files-to-ram $optfile
345then
346	rwfst=none
347	copyfiles=y
348fi
349
350# It would be nice to do this after fsck but that mean rofs is mounted
351# which triggers the mtd is mounted check
352if test "$rwfst$copyfiles" = noney
353then
354	touch $trigger
355	$update --copy-files --clean-saved-files --no-restore-files
356fi
357
358if grep -w copy-base-filesystem-to-ram $optfile &&
359	test ! -e /run/image-rofs && ! cp $rodev /run/image-rofs
360then
361	# Remove any partial copy to avoid attempted usage later
362	if test -e  /run/image-rofs
363	then
364		ls -l /run/image-rofs
365		rm -f /run/image-rofs
366	fi
367	debug_takeover "Copying $rodev to /run/image-rofs failed."
368fi
369
370if test -s /run/image-rofs
371then
372	rodev=/run/image-rofs
373	roopts=$roopts,loop
374fi
375
376mount $rodev $rodir -t $rofst -o $roopts
377
378if test -x $rodir$fsck
379then
380	for fs in $fslist
381	do
382		mount --bind $fs $rodir/$fs
383	done
384	chroot $rodir $fsck $fsckopts $rwdev
385	rc=$?
386	for fs in $fslist
387	do
388		umount $rodir/$fs
389	done
390	if test $rc -gt 1
391	then
392		debug_takeover "fsck of read-write fs on $rwdev failed (rc=$rc)"
393	fi
394elif test "$rwfst" != jffs2 -a "$rwfst" != none
395then
396	echo "No '$fsck' in read only fs, skipping fsck."
397fi
398
399if test "$rwfst" = none
400then
401	echo "Running with read-write overlay in RAM for this boot."
402	echo "No state will be preserved unless flash update performed."
403elif ! mount $rwdev $rwdir -t $rwfst -o $rwopts
404then
405	msg="$(cat)" << HERE
406
407Mounting read-write $rwdev filesystem failed.  Please fix and run
408	mount $rwdev $rwdir -t $rwfst -o $rwopts
409or perform a factory reset with the clean-rwfs-filesystem option.
410HERE
411	debug_takeover "$msg"
412fi
413
414rm -rf $work
415mkdir -p $upper $work
416
417mount -t overlay -o lowerdir=$rodir,upperdir=$upper,workdir=$work cow /root
418
419while ! chroot /root /bin/sh -c "test -x '$init' -a -s '$init'"
420do
421	msg="$(cat)" << HERE
422
423Unable to confirm /sbin/init is an executable non-empty file
424in merged file system mounted at /root.
425
426Change Root test failed!
427HERE
428	debug_takeover "$msg"
429done
430
431for f in $fslist
432do
433	mount --move $f root/$f
434done
435
436# switch_root /root $init
437exec chroot /root $init
438
439