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 "$dosave" = "y"
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 -r f
175	do
176		if ! test -e "$upper/$f"
177		then
178			continue
179		fi
180		d="$save/$f"
181		mkdir -p "${d%/*}"
182		cp -rp "$upper/$f" "${d%/*}/"
183	done < $whitelist
184
185	if test -n "$mounted"
186	then
187		umount $mounted
188	fi
189fi
190
191imglist=$(echo $image*)
192if test "$imglist" = "$image*" -a ! -e "$imglist"
193then
194	# shell didn't expand the wildcard, so no files exist
195	echo "No images found to update."
196	imglist=
197fi
198
199for f in $imglist
200do
201	m=$(findmtd "${f#"$image"}")
202	if test -z "$m"
203	then
204		echoerr "Unable to find mtd partition for ${f##*/}."
205		exit 1
206	fi
207	if test -n "$checksize" && toobig "$f" "$m"
208	then
209		echoerr "Image ${f##*/} too big for $m."
210		exit 1
211	fi
212	for s in $m $(childmtds "$m")
213	do
214		if test -n "$checkmount" && mtdismounted "$s"
215		then
216			echoerr "Device $s is mounted, ${f##*/} is busy."
217			exit 1
218		fi
219	done
220done
221
222if test -n "$doflash"
223then
224	for f in $imglist
225	do
226		if test ! -s "$f"
227		then
228			echo "Skipping empty update of ${f#"$image"}."
229			rm "$f"
230			continue
231		fi
232		m=$(findmtd "${f#"$image"}")
233		echo "Updating ${f#"$image"}..."
234		flashcp -v "$f" "/dev/$m" && rm "$f"
235	done
236fi
237
238if test -d "$save" -a "$toram" = "y"
239then
240	mkdir -p $upper
241	cp -rp "$save/." "$upper/"
242fi
243
244if test -d "$save" -a "$dorestore" = "y"
245then
246	odir=$rwdir
247	rwdir=/run/rw
248	upper=$rwdir${upper#"$odir"}
249
250	mkdir -p $rwdir
251	mount "$rwdev" $rwdir -t "$(probe_fs_type "$rwdev")" -o $rwopts
252	mkdir -p "$upper"
253	cp -rp "$save/." "$upper/"
254	umount $rwdir
255	rmdir $rwdir
256fi
257
258if test "$doclean" = "y"
259then
260	rm -rf "$save"
261fi
262
263exit
264