3 # ensure the flash disk is not mounted
4 # save configuration files
7 # restore the saved configuration files
8 # the set of configuration files is described by
9 # /etc/default/conffiles.
11 # /etc/default/functions contains useful utility functions
12 . /etc/default/functions
14 # CHECKING FOR INPUT (ARGUMENTS ETC)
15 # ----------------------------------
17 # find the kernel and the new flash file system, an image file can
18 # be used to specify both images.
27 echo "reflash: -k: give the file containing the kernel image" >&2
34 echo "reflash: -j: give the file containing the root jffs2 image" >&2
41 echo "reflash: -i: give the file containing the complete flash image" >&2
46 *) echo "reflash: usage: $0 [-k kernel] [-j rootfs] [-i image]" >&2
47 echo " -k file: the new compressed kernel image ('zImage')" >&2
48 echo " -j file: the new root file system (jffs2)" >&2
49 echo " -i file: a complete flash image (gives both kernel and jffs2)" >&2
50 echo " The current jffs2 will be umounted if mounted." >&2
55 # Sanity check on the arguments
56 if test -n "$imgfile" -a -n "$ffsfile" -a -n "$kfile"
58 echo "reflash: -k,-j,-i: specify at most two files" >&2
59 echo " -i has both a kernel and rootfs, the kernel from -k and" >&2
60 echo " the rootfs from -j override the one in the image (if given)" >&2
62 elif test -z "$imgfile" -a -z "$ffsfile" -a -z "$kfile"
64 echo "reflash: -k,-j,-i: specify at least one file to flash" >&2
68 # Perform basic checks on the input (must exist, size must be ok).
73 # read the partition table and from this find the offset
74 # and size of Kernel and Flashdisk partitions. The following
75 # devio command just dumps the partition table in a format
76 # similar to /proc/mtd (but it outputs decimal values!)
77 #NOTE: this uses a here document because this allows the while
78 # loop to set the variables, a pipe would put the while in
79 # a sub-shell and the variable settings would be lost. This
80 # works in ash, no guarantees about other shells!
81 while read size base name
84 Kernel) imgksize="$size"
88 imgffsoffset="$base";;
91 $(devio "<<$imgfile" '
95 # 0xff byte in name[0] ends the partition table
97 # output size base name
111 test "$imgksize" -gt 0 -a "$imgkoffset" -ge 0 || {
112 echo "reflash: $imgfile: failed to find Kernel partition in image" >&2
115 # the kernel is after a 16 byte header which holds the
116 # values length,0,0,0 Get the true size.
117 ktmp="$(devio "<<$imgfile" "L=$imgksize" "O=$imgkoffset" '
125 test "$ktmp" -gt 0 || {
126 echo "reflash: $imgfile($imgkoffset,$imgksize): invalid kernel offset/size" >&2
129 # update the size and offset to these values (the offset is 16+ because
132 imgkoffset="$(devio "O=$imgkoffset" 'pr O16+')"
133 # just test the size for the rootfs
134 test "$imgffssize" -gt 0 -a "$imgffsoffset" -ge 0 || {
135 echo "reflash: $imgfile: failed to find Flashdisk" >&2
139 echo "reflash: $imgfile: image file not found" >&2
145 if test ! -r "$kfile"
147 echo "reflash: $kfile: kernel file not found" >&2
150 # the file values override anything from the image.
151 imgksize="$(devio "<<$kfile" 'pr$')"
156 if test -n "$ffsfile"
158 if test ! -r "$ffsfile"
160 echo "reflash: $ffsfile: root file system image file not found" >&2
163 # values override those from the image
164 imgffssize="$(devio "<<$ffsfile" 'pr$')"
170 # INPUTS OK, CHECKING THE ENVIRONMENT
171 # -----------------------------------
172 # basic setup. This could be parameterised to use different partitions!
180 # we have a new kernel
181 kdev="$(mtblockdev $kpart)"
182 test -n "$kdev" -a -b "$kdev" || {
183 echo "reflash: $kpart($kdev): cannot find $kpart mtd partition." >&2
184 echo " check /proc/mtd, either the partition does not exist or there is no" >&2
185 echo " corresponding block device." >&2
188 ksize="$(devio "<<$kdev" 'pr$')"
190 # check the input file size
191 test -n "$imgksize" -a "$imgksize" -gt 0 -a "$imgksize" -le "$ksize" || {
192 echo "reflash: $kfile: bad Kernel size ($s, max $ksize)" >&2
199 if test -n "$ffsfile"
201 ffsdev="$(mtblockdev $ffspart)"
202 test -n "$ffsdev" -a -b "$ffsdev" || {
203 echo "reflash: $ffspart($ffsdev): cannot find $ffspart mtd partition." >&2
204 echo " check /proc/mtd, either the partition does not exist or there is no" >&2
205 echo " corresponding block device." >&2
208 ffssize="$(devio "<<$ffsdev" 'pr$')"
210 # check the input file size
211 test -n "$imgffssize" -a "$imgffssize" -gt 0 -a "$imgffssize" -le "$ffssize" || {
212 echo "reflash: $ffsfile: bad Flashdisk size ($s, max $ffssize)" >&2
218 # INPUTS OK, ENVIRONMENT OK, UMOUNT ANY EXISTING MOUNT OF THE FLASHDISK
219 # ---------------------------------------------------------------------
220 # This is only required if the device is going to be used
223 # -r causes this to fail if the flash device is mounted on /
224 umountflash -r "$ffsdev" || exit 1
226 # Everything is umounted, now remount on a temporary directory.
227 ffsdir="/tmp/flashdisk.$$"
229 echo "reflash: $ffsdir: failed to create temporary directory" >&2
233 mountflash "$ffsdev" "$ffsdir" -o ro || {
238 # this is a utility function to make the cleanup easier
240 umount "$ffsdir" && rmdir "$ffsdir" ||
241 echo "reflash: $ffsdir: temporary directory cleanup failed" >&2
245 test -r "$ffsdir/etc/default/conffiles" || {
246 echo "reflash: [/initrd]/etc/default/conffiles: file not found" >&2
255 # PRESERVE EXISTING CONFIGURATION
256 # -------------------------------
257 # Only required if the flash partition will be written
260 echo "reflash: preserving existing configuration file" >&2
262 # This step produces /tmp/preserve.$$ and /tmp/cpio.$$, the former is
263 # a list of the preserved configuration files together with the processing
264 # option, the latter is a directory tree of the preserved files (a directory
265 # tree makes the restore step easier.)
267 list=/tmp/preserve.$$
269 echo "reflash: $saved: could not create save directory" >&2
274 find etc/*.conf $(sed 's!^/!!' usr/lib/ipkg/info/*.conffiles) ! -type d -newer etc/.configured -print |
276 exec sed 's/#.*$//;/^[ ]*$/d' etc/default/conffiles
277 ) | sed 's!^/*!!' | awk '{ op=$1; $1=""; file[$0]=op }
278 END{ for (f in file) if (file[f] != "ignore") print file[f] f }' |
281 if test -e "$ffsdir/$file"
286 done 3>"$list" | (cd "$ffsdir"; exec cpio -p -d -m -u "$saved") || {
287 echo "reflash: $saved: copy of saved configuration files failed" >&2
293 # If this umount fails do not try to continue...
294 umount "$ffsdir" || {
295 echo "reflash: $ffsdir: temporary mount point umount failed" >&2
296 echo " No changes have been made." >&2
303 # FLASH THE NEW IMAGES
304 # --------------------
305 echo "reflash: about to flash new image" >&2
307 # There are four possibilities here - kernel only, flashdisk only, then
308 # kernel&flashdisk in either one or two different files. The code used
309 # to attempt to do everything in one step, but this complicates it,
310 # so two steps are used (as required). A failure between the two
311 # steps is a problem, but then so is a failure in a partial write.
312 # Write the flashdisk first because this is larger (most likely to
314 # Temporarily check for devio progress indicator capability this way...
315 if devio -p '' 2>/dev/null
322 devio $progress "$@" "<<$kfile" ">>$kdev" '
323 # kernel is at imgkoffset[imgksize]
324 ' "<= $imgkoffset" "L=$imgksize" '
325 # kernel write length,0,0,0 header, then fill
334 devio $progress "$@" "<<$ffsfile" ">>$ffsdev" '
335 # rootfs is at imgffsoffset[imgffssize]
336 ' "<= $imgffsoffset" "cp $imgffssize" '
341 # check_status $? type file(offset,size) device
342 # check the devio status code (given in $1)
345 0) echo " done" >&2;;
346 1) echo " failed" >&2
347 echo "reflash: $3: flash $2 failed, no changes have been made to $4" >&2
348 if test "$2" = rootfs
354 echo "reflash: $2: continuing with rootfs changes" >&2
355 echo " NOTE: the old kernel is still in $4!" >&2
357 3) echo " failed" >&2
358 echo "reflash: $3: WARNING: partial flash of $2 to $4 the system is unbootable" >&2
359 echo " Reflash from RedBoot or correct the problem here." >&2
360 if test "$2" = rootfs
364 echo "reflash: $2: continuing with rootfs changes" >&2
365 echo " NOTE: the kernel in $4 must be reflashed!" >&2
367 *) echo " failed" >&2
368 echo "reflash($1): $3: internal error flashing $2 to $4" >&2
375 echo -n "reflash: writing rootfs to $ffsdev " >&2
377 check_status $? rootfs "$ffsfile($imgffsoffset,$imgffssize)" "$ffsdev"
382 echo -n "reflash: writing kernel to $kdev " >&2
384 check_status $? kernel "$kfile($imgkoffset,$imgksize)" "$kdev"
387 # verify - this just produces a warning
390 echo -n "reflash: verifying new flash image " >&2
396 echo "reflash: WARNING: rootfs flash image verification failed" >&2
397 echo " The system is probably unbootable." >&2
398 echo " System configuration files will be restored but this may fail" >&2
399 echo " Starting a shell for user recovery (exit to continue)" >&2
400 PS1='badflash$ ' sh -i <>/dev/tty >&0 2>&0
406 echo -n "reflash: verifying new kernel image " >&2
412 echo "reflash: WARNING: kernel flash image verification failed" >&2
413 echo " The system is probably unbootable." >&2
414 echo " System configuration files will be restored in the rootfs." >&2
418 # RESTORE THE OLD CONFIGURATION
419 # -----------------------------
420 # If not write the rootfs none of the following is required - exit now.
421 test -n "$ffsdev" || exit 0
423 echo "reflash: restoring saved configuration files" >&2
425 # the file /etc/.configured is the datestamp file used to ensure that
426 # changed configuration files can be recognised. It is created by
427 # /etc/rcS.d/S99finish on first boot (if it does not exist). We need
428 # a timestamp earlier than any files we create so touch it here, this
429 # also acts as a test on the mounted file system
430 mountflash "$ffsdev" "$ffsdir" && :>"$ffsdir/etc/.configured" || {
432 echo "reflash: mount of new flash root file system failed" >&2
433 if test -d "$ffsdir/etc"
435 echo " The file system does not seem to be writeable." >&2
436 echo " The mounted file system is in $ffsdir" >&2
438 echo " WARNING: the kernel and root file system have been reflashed," >&2
439 echo " HOWEVER the new root file system seems to be unuseable." >&2
440 echo " Saved configuration files are in $saved" >&2
441 echo " The list of saved configuration files is in $list" >&2
442 echo " You should determine the reason for the failed mount, mount the new" >&2
443 echo " file system and restore the configuration from $saved - it's just a" >&2
444 echo " matter of copying the saved files where required." >&2
449 # this is called with the name of a 'diff' file which is, indeed,
450 # different and with all the std streams connected to the tty. It
451 # returns a status code to say whether (0) or not (1) to copy the
455 echo "Please specify how to handle this file or link, the options are as follows,"
456 echo "two character abbreviations may be used:"
458 echo " keep: retain the old file, overwrite the new flash image file"
459 echo " upgrade: retain the new file, the old (saved) file is not used"
460 echo " diff: display the differences between the old and the new using diff -u"
461 echo " shell: temporarily start an interactive shell (sh -i), exit to continue"
462 echo " skip: ignore this file for the moment. The file is left in the directory"
463 echo " $saved and many be handled after this script has completed"
470 echo "reflash: $file: configuration file changed."
478 up*) rm "$saved/$file"
480 di*) echo "DIFF OLD($saved) NEW($ffsdir)"
481 diff -u "$saved/$file" "$ffsdir/$file";;
482 sh*) PS1="$file: " sh -i;;
484 *) verify_help "$file";;
488 # the same, but for a link
493 echo "reflash: $link: configuration link changed."
501 up*) rm "$saved/$link"
504 echo "OLD($saved): $link -> $(readlink "$saved/$link")"
505 echo "NEW($ffsdir): $link -> $(readlink "$ffsdir/$link")";;
506 sh*) PS1="$link: " sh -i;;
508 *) verify_help "$link";;
515 # handle .configured specially (to preserve the original datestamp)
516 if test "$file" = "etc/.configured"
518 # this should definately not fail because of the test above!
519 if cp -a "$saved/$file" "$ffsdir/$file"
523 echo "reflash: $file: timestamp copy failed (ignored)" >&2
525 elif test -h "$saved/file" -o -h "$ffsdir/$file"
527 # new or old symbolic link
528 if test -h "$saved/$file" -a -h "$ffsdir/$file" &&
529 test "$(readlink "$saved/$file")" = "$(readlink "$ffsdir/$file")"
534 # assume a change regardless
539 diff) # need user input
540 if verify_link "$file" <>/dev/tty >&0 2>&0
548 # only overwrite if necessary
549 if test -e "$ffsdir/$file" && cmp -s "$saved/$file" "$ffsdir/$file"
553 elif test ! -e "$ffsdir/$file"
563 diff) # the files are different, get user input
564 if verify "$file" <>/dev/tty >&0 2>&0
572 done <"$list" 3>/tmp/restore.$$ | (cd "$saved"; exec cpio -p -d -u "$ffsdir") || {
573 echo "reflash: $saved: restore of saved configuration files failed" >&2
574 echo " The new flash file system is mounted on $ffsdir" >&2
575 echo " The saved files are in $saved and the list in $list, the list of" >&2
576 echo " files selected for restore is in /tmp/restore.$$" >&2
577 echo " You should restore any required configuration from $saved," >&2
578 echo " then umount $ffsdir and reboot." >&2
582 # remove the copied files (i.e. the ones which were preserved)
584 exec rm $(cat /tmp/restore.$$)
588 # clean up, files left in $saved need to be handled by the user
589 files="$(find "$saved" ! -type d -print)"
592 echo "reflash: the following saved configuration files remain:" >&2
594 echo "The full list of preserved files is in $list. To alter the" >&2
595 echo "new root file system use the command:" >&2
597 echo " mount -t jffs2 $ffsdev /mnt" >&2
599 echo "The saved files are in the temporary directory, they will not" >&2
600 echo "be retained across a system boot. Copy them elsewhere if you" >&2
601 echo "are unsure whether they are needed" >&2
607 # now the final umount
611 echo "reflash: system upgrade complete. Reboot to continue." >&2
614 echo "reflash: $ffsdir: temporary mount point umount failed" >&2
615 echo " ALL changes have been made successfully, however the umount of" >&2
616 echo " the new root file system has failed. You should determine the" >&2
617 echo " cause of the failure, umount $ffsdir, then reboot the system (this" >&2
618 echo " will use the upgraded kernel and root file system)" >&2