1#!/bin/sh
2
3echo update: "$@"
4
5echoerr() {
6	echo 1>&2 "ERROR: $@"
7}
8
9cd /
10if ! test -r /proc/mounts || ! test -f /proc/mounts
11then
12	mkdir -p /proc
13	mount -t proc proc proc
14fi
15if ! test -d /sys/class
16then
17	mkdir -p /sys
18	mount -t sysfs sys sys
19fi
20if ! test -c /dev/null
21then
22	mkdir -p /dev
23	mount -t devtmpfs dev dev
24fi
25
26# mtd number N with mtd name Name can be mounted via mtdN, or mtd:Name
27# (with a mtd aware fs) or by /dev/mtdblockN (with a mtd or block fs).
28mtdismounted() {
29	m=${1##mtd}
30	if grep -s "mtdblock$m " /proc/mounts || grep -s "mtd$m " /proc/mounts
31	then
32		return 0
33	fi
34	n=$(cat /sys/class/mtd/mtd$m/name)
35	if test -n "$n" && grep -s "mtd:$n " /proc/mounts
36	then
37		return 0
38	fi
39	return 1
40}
41
42# Detect child partitions when the whole flash is to be updated.
43# Ignore mtdNro and mtdblockN names in the class subsystem directory.
44childmtds() {
45	for m in /sys/class/mtd/$1/mtd*
46	do
47		m=${m##*/}
48		if test "${m%ro}" = "${m#mtdblock}"
49		then
50			echo $m
51		fi
52	done
53}
54
55toobig() {
56	if test $(stat -L -c "%s" "$1") -gt $(cat /sys/class/mtd/"$2"/size)
57	then
58		return 0
59	fi
60	return 1
61}
62
63findmtd() {
64	m=$(grep -xl "$1" /sys/class/mtd/*/name)
65	m=${m%/name}
66	m=${m##*/}
67	echo $m
68}
69
70blkid_fs_type() {
71	# Emulate util-linux's `blkid -s TYPE -o value $1`
72	# Example busybox blkid output:
73	#    # blkid /dev/mtdblock5
74	#    /dev/mtdblock5: TYPE="squashfs"
75	# Process output to extract TYPE value "squashfs".
76	blkid $1 | sed -e 's/^.*TYPE="//' -e 's/".*$//'
77}
78
79probe_fs_type() {
80	fst=$(blkid_fs_type $1)
81	echo ${fst:=jffs2}
82}
83
84rwfs=$(findmtd rwfs)
85
86rwdev=/dev/mtdblock${rwfs#mtd}
87rwopts=rw
88rorwopts=ro${rwopts#rw}
89
90rwdir=/run/initramfs/rw
91upper=$rwdir/cow
92save=/run/save/${upper##*/}
93
94mounted=
95doflash=y
96doclean=
97dosave=y
98dorestore=y
99toram=
100checksize=y
101checkmount=y
102
103whitelist=/run/initramfs/whitelist
104image=/run/initramfs/image-
105imglist=
106
107while test "$1" != "${1#-}"
108do
109	case "$1" in
110	--help)
111		cat <<HERE
112Usage: $0 [options] -- Write images in /run/initramfs to flash (/dev/mtd*)
113    --help                    Show this message
114    --no-flash                Don't attempt to write images to flash
115    --ignore-size             Don't compare image size to mtd device size
116    --ignore-mount            Don't check if destination is mounted
117    --save-files              Copy whitelisted files to save directory in RAM
118    --no-save-files           Don't copy whitelisted files to save directory
119    --copy-files              Copy files from save directory to rwfs mountpoint
120    --restore-files           Restore files from save directory to rwfs layer
121    --no-restore-files        Don't restore saved files from ram to rwfs layer
122    --clean-saved-files       Delete saved whitelisted files from RAM
123    --no-clean-saved-files    Retain saved whitelisted files in RAM
124HERE
125
126	    exit 0 ;;
127
128	--no-clean-saved-files)
129		doclean=
130		shift ;;
131	--clean-saved-files)
132		doclean=y
133		shift ;;
134	--no-save-files)
135		dosave=
136		shift ;;
137	--save-files)
138		dosave=y
139		shift ;;
140	--no-restore-files)
141		dorestore=
142		shift ;;
143	--restore-files)
144		dorestore=y
145		shift ;;
146	--no-flash)
147		doflash=
148		shift ;;
149	--ignore-size)
150		checksize=
151		shift ;;
152	--ignore-mount)
153		checkmount=
154		doflash=
155		shift ;;
156	--copy-files)
157		toram=y
158		shift ;;
159	*)
160		echoerr "Unknown option $1.  Try $0 --help."
161		exit 1 ;;
162	esac
163done
164
165if test "x$dosave" = xy
166then
167	if test ! -d $upper -a -n "$rwfs"
168	then
169		mkdir -p $rwdir
170		mount $rwdev $rwdir -t $(probe_fs_type $rwdev) -o $rorwopts
171		mounted=$rwdir
172	fi
173
174	while read f
175	do
176		# Entries shall start with /, no trailing /.. or embedded /../
177		if test "/${f#/}" != "$f" -o "${f%/..}" != "${f#*/../}"
178		then
179			echo 1>&2 "WARNING: Skipping bad whitelist entry $f."
180			continue
181		fi
182		if ! test -e "$upper/$f"
183		then
184			continue
185		fi
186		d="$save/$f"
187		while test "${d%/}" != "${d%/.}"
188		do
189			d="${d%/.}"
190			d="${d%/}"
191		done
192		mkdir -p "${d%/*}"
193		cp -rp "$upper/$f" "${d%/*}/"
194	done < $whitelist
195
196	if test -n "$mounted"
197	then
198		umount $mounted
199	fi
200fi
201
202imglist=$(echo $image*)
203if test "$imglist" = "$image*" -a ! -e "$imglist"
204then
205	# shell didn't expand the wildcard, so no files exist
206	echo "No images found to update."
207	imglist=
208fi
209
210for f in $imglist
211do
212	m=$(findmtd ${f#$image})
213	if test -z "$m"
214	then
215		echoerr "Unable to find mtd partition for ${f##*/}."
216		exit 1
217	fi
218	if test -n "$checksize" && toobig "$f" "$m"
219	then
220		echoerr "Image ${f##*/} too big for $m."
221		exit 1
222	fi
223	for s in $m $(childmtds $m)
224	do
225		if test -n "$checkmount" && mtdismounted $s
226		then
227			echoerr "Device $s is mounted, ${f##*/} is busy."
228			exit 1
229		fi
230	done
231done
232
233if test -n "$doflash"
234then
235	for f in $imglist
236	do
237		if test ! -s $f
238		then
239			echo "Skipping empty update of ${f#$image}."
240			rm $f
241			continue
242		fi
243		m=$(findmtd ${f#$image})
244		echo "Updating ${f#$image}..."
245		flashcp -v $f /dev/$m && rm $f
246	done
247fi
248
249if test -d $save -a "x$toram" = xy
250then
251	mkdir -p $upper
252	cp -rp $save/. $upper/
253fi
254
255if test -d $save -a "x$dorestore" = xy
256then
257	odir=$rwdir
258	rwdir=/run/rw
259	upper=$rwdir${upper#$odir}
260
261	mkdir -p $rwdir
262	mount $rwdev $rwdir -t $(probe_fs_type $rwdev) -o $rwopts
263	mkdir -p $upper
264	cp -rp $save/. $upper/
265	umount $rwdir
266	rmdir $rwdir
267fi
268
269if test "x$doclean" = xy
270then
271	rm -rf $save
272fi
273
274exit
275