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
13 load_functions sysconf
15 # NSLU2 flash layout is non-standard.
30 ffspart="filesystem";;
37 ffspart="filesystem";;
40 # CHECKING FOR INPUT (ARGUMENTS ETC)
41 # ----------------------------------
43 # find the kernel and the new flash file system, an image file can
44 # be used to specify both images.
56 echo "reflash: -k: give the file containing the kernel image" >&2
63 echo "reflash: -j: give the file containing the root jffs2 image" >&2
69 test -n "$imageok" || {
70 echo "reflash: -i: only supported on the LinkSys NSLU2" >&2
71 echo " and the D-Link DSM-G600 systems; use -k and -j" >&2
72 echo " to specify the kernel and root file system instead." >&2
76 echo "reflash: -i: give the file containing the complete flash image" >&2
81 *) if test -n "$imageok"
83 echo "reflash: usage: $0 [-n] [-k kernel] [-j rootfs] [-i image]" >&2
85 echo "reflash: usage: $0 [-n] [-k kernel] [-j rootfs]" >&2
87 echo " -n: do not attempt to preserve the configuration" >&2
88 echo " -k file: the new compressed kernel image ('zImage')" >&2
89 echo " -j file: the new root file system (jffs2)" >&2
91 echo " -i file: a complete flash image (gives both kernel and jffs2)" >&2
92 echo " The current jffs2 will be umounted if mounted." >&2
97 # Sanity check on the arguments (note that the first case can only fire
98 # on NSLU2 or DSM-G600 because of the check for -i above.)
99 if test -n "$imgfile" -a -n "$ffsfile" -a -n "$kfile"
101 echo "reflash: specify at most two files" >&2
102 echo " -i has both a kernel and rootfs, the kernel from -k and" >&2
103 echo " the rootfs from -j override the one in the image (if given)" >&2
105 elif test -z "$imgfile" -a -z "$ffsfile" -a -z "$kfile"
107 echo "reflash: specify at least one file to flash" >&2
111 # Perform basic checks on the input (must exist, size must be ok).
112 if test -n "$imgfile"
114 if test -r "$imgfile" -a -n "$isnslu2"
116 # read the partition table and from this find the offset
117 # and size of $kpart and $ffspart partitions. The following
118 # devio command just dumps the partition table in a format
119 # similar to /proc/mtd (but it outputs decimal values!)
120 #NOTE: this uses a here document because this allows the while
121 # loop to set the variables, a pipe would put the while in
122 # a sub-shell and the variable settings would be lost. This
123 # works in ash, no guarantees about other shells!
124 while read size base name
126 if test "$name" = "$kpart"
130 elif test "$name" = "$ffspart"
136 $(devio "<<$imgfile" '
140 # 0xff byte in name[0] ends the partition table
142 # output size base name
156 test "$imgksize" -gt 0 -a "$imgkoffset" -ge 0 || {
157 echo "reflash: $imgfile: failed to find $kpart partition in image" >&2
160 # the kernel is after a 16 byte header which holds the
161 # values length,0,0,0 Get the true size.
162 ktmp="$(devio "<<$imgfile" "L=$imgksize" "O=$imgkoffset" '
170 test "$ktmp" -gt 0 || {
171 echo "reflash: $imgfile($imgkoffset,$imgksize): invalid kernel offset/size" >&2
174 # update the size and offset to these values (the offset is 16+ because
177 imgkoffset="$(devio "O=$imgkoffset" 'pr O16+')"
178 # just test the size for the rootfs
179 test "$imgffssize" -gt 0 -a "$imgffsoffset" -ge 0 || {
180 echo "reflash: $imgfile: failed to find $ffspart" >&2
183 elif test -r "$imgfile" -a -n "$isdsmg600"
186 # For the DSM-G600, this is really easy - the image is just
187 # a tar file. So, extract the contents of the tar file, and
188 # set the kernel and filesystem variables (if not already set)
189 # to point to the extracted content. Content will look like:
191 # drwxr-xr-x 500/500 0 2006-11-25 23:47:59 firmupgrade
192 # -rw-r--r-- 500/500 4718592 2006-12-02 16:32:51 firmupgrade/rootfs.gz
193 # -rw-r--r-- 500/500 40 2006-11-25 22:15:41 firmupgrade/version.msg
194 # -rw-r--r-- 500/500 0 2006-11-25 23:47:59 firmupgrade/usr.cramfs
195 # -rw-rw-r-- 500/500 1306872 2006-12-02 16:33:37 firmupgrade/ip-ramdisk
197 # Heuristic: if the size of usr.cramfs is zero, the firmware
198 # is not a D-Link firmware for the device. (The version.msg
199 # file is not useful for this purpose; it describes the hardware,
200 # not the firmware version in the image!)
202 # TODO: If usr.cramfs is non-zero, we should flash that, too, just
203 # to make sure that it matches the native firmware's kernel
204 # and rootfs that we're now flashing back onto the device.
206 echo "reflash: unpacking DSM-G600 image file" >&2
207 tar -x -f "$imgfile" -C /var/tmp || {
208 echo "reflash: unable to unpack image file to be flashed" >&2
214 kfile="/var/tmp/firmupgrade/ip-ramdisk"
217 if test -z "$ffsfile"
219 ffsfile="/var/tmp/firmupgrade/rootfs.gz"
222 if test -s "/var/tmp/firmupgrade/usr.cramfs"
224 echo "reflash: Native flash being restored" >&2
225 usrfile="/var/tmp/firmupgrade/usr.cramfs"
227 dsmg600_native_flash=1
231 echo "reflash: $imgfile: image file not found" >&2
237 if test ! -r "$kfile"
239 echo "reflash: $kfile: kernel file not found" >&2
242 # the file values override anything from the image.
243 imgksize="$(devio "<<$kfile" 'pr$')"
248 if test -n "$ffsfile"
250 if test ! -r "$ffsfile"
252 echo "reflash: $ffsfile: root file system image file not found" >&2
255 # values override those from the image
256 imgffssize="$(devio "<<$ffsfile" 'pr$')"
261 if test -n "$usrfile"
263 if test ! -r "$usrfile"
265 echo "reflash: $usrfile: usr file system image file not found" >&2
268 # values override those from the image
269 imgusrsize="$(devio "<<$usrfile" 'pr$')"
275 # INPUTS OK, CHECKING THE ENVIRONMENT
276 # -----------------------------------
277 # basic setup. This could be parameterised to use different partitions!
283 # we have a new kernel
284 kdev="$(mtblockdev $kpart)"
285 test -n "$kdev" -a -b "$kdev" || {
286 echo "reflash: $kpart($kdev): cannot find $kpart mtd partition." >&2
287 echo " check /proc/mtd, either the partition does not exist or there is no" >&2
288 echo " corresponding block device." >&2
291 ksize="$(devio "<<$kdev" 'pr$')"
293 # check the input file size
294 test -n "$imgksize" -a "$imgksize" -gt 0 -a "$imgksize" -le "$ksize" || {
295 echo "reflash: $kfile: bad $kpart size ($imgksize, max $ksize)" >&2
302 if test -n "$ffsfile"
304 ffsdev="$(mtblockdev $ffspart)"
305 test -n "$ffsdev" -a -b "$ffsdev" || {
306 echo "reflash: $ffspart($ffsdev): cannot find $ffspart mtd partition." >&2
307 echo " check /proc/mtd, either the partition does not exist or there is no" >&2
308 echo " corresponding block device." >&2
311 ffssize="$(devio "<<$ffsdev" 'pr$')"
313 # check the input file size
314 test -n "$imgffssize" -a "$imgffssize" -gt 0 -a "$imgffssize" -le "$ffssize" || {
315 echo "reflash: $ffsfile: bad $ffspart size ($imgffsize, max $ffssize)" >&2
322 if test -n "$usrfile"
324 usrdev="$(mtblockdev $usrpart)"
325 test -n "$usrdev" -a -b "$usrdev" || {
326 echo "reflash: $usrpart($usrdev): cannot find $usrpart mtd partition." >&2
327 echo " check /proc/mtd, either the partition does not exist or there is no" >&2
328 echo " corresponding block device." >&2
331 usrsize="$(devio "<<$usrdev" 'pr$')"
333 # check the input file size
334 test -n "$imgusrsize" -a "$imgusrsize" -gt 0 -a "$imgusrsize" -le "$usrsize" || {
335 echo "reflash: $usrfile: bad $usrpart size ($imgusrsize, max $usrsize)" >&2
341 # INPUTS OK, ENVIRONMENT OK, UMOUNT ANY EXISTING MOUNT OF THE FLASHDISK
342 # ---------------------------------------------------------------------
343 # This is only required if the device is going to be used
346 # -r causes this to fail if the flash device is mounted on /
347 umountflash -r "$ffsdev" || exit 1
349 # Everything is umounted, now remount on a temporary directory.
350 ffsdir="/tmp/flashdisk.$$"
352 echo "reflash: $ffsdir: failed to create temporary directory" >&2
356 mountflash "$ffsdev" "$ffsdir" -o ro || {
361 # this is a utility function to make the cleanup easier
363 umount "$ffsdir" && rmdir "$ffsdir" ||
364 echo "reflash: $ffsdir: temporary directory cleanup failed" >&2
368 test -r "$ffsdir/etc/default/conffiles" || {
369 echo "reflash: [/initrd]/etc/default/conffiles: file not found" >&2
378 # PRESERVE EXISTING CONFIGURATION
379 # -------------------------------
380 # Only required if the flash partition will be written
381 if test -n "$ffsdev" -a -n "$preserve_config"
383 echo "reflash: preserving existing configuration file" >&2
385 # This step produces /tmp/preserve.$$ and /tmp/cpio.$$, the former is
386 # a list of the preserved configuration files together with the processing
387 # option, the latter is a directory tree of the preserved files (a directory
388 # tree makes the restore step easier.)
390 list=/tmp/preserve.$$
392 echo "reflash: $saved: could not create save directory" >&2
396 # sysconf_save_conffiles <flash-directory> <dest> <list>
397 sysconf_save_conffiles "$ffsdir" "$saved" "$list" || {
398 echo "reflash: $saved: copy of saved configuration files failed" >&2
404 # If this umount fails do not try to continue...
405 umount "$ffsdir" || {
406 echo "reflash: $ffsdir: temporary mount point umount failed" >&2
407 echo " No changes have been made." >&2
414 # FLASH THE NEW IMAGES
415 # --------------------
416 echo "reflash: about to flash new image" >&2
418 # There are four possibilities here - kernel only, flashdisk only, then
419 # kernel&flashdisk in either one or two different files. The code used
420 # to attempt to do everything in one step, but this complicates it,
421 # so two steps are used (as required). A failure between the two
422 # steps is a problem, but then so is a failure in a partial write.
423 # Write the flashdisk first because this is larger (most likely to
426 # -p causes the progress indicator to be displayed
430 if test -n "$isnslu2"
432 # NSLU2: write length,0,0,0 header, then fill
433 cmd="wb L,4; fb 12,0; cpL"
435 # Other: just write the kernel bytes
438 devio $progress "$@" "<<$kfile" ">>$kdev" '
439 # kernel is at imgkoffset[imgksize]
440 ' "<= $imgkoffset" "L=$imgksize" "$cmd" '
446 devio $progress "$@" "<<$ffsfile" ">>$ffsdev" '
447 # rootfs is at imgffsoffset[imgffssize]
448 ' "<= $imgffsoffset" "cp $imgffssize" '
454 devio $progress "$@" "<<$usrfile" ">>$usrdev" '
455 # usrfs is at imgusroffset[imgusrsize]
456 ' "<= $imgusroffset" "cp $imgusrsize" '
461 # check_status $? type file(offset,size) device
462 # check the devio status code (given in $1)
465 0) echo " done" >&2;;
466 1) echo " failed" >&2
467 echo "reflash: $3: flash $2 failed, no changes have been made to $4" >&2
468 if test "$2" = rootfs
474 echo "reflash: $2: continuing with rootfs changes" >&2
475 echo " NOTE: the old kernel is still in $4!" >&2
477 3) echo " failed" >&2
478 echo "reflash: $3: WARNING: partial flash of $2 to $4 the system is unbootable" >&2
479 echo " Reflash from RedBoot or correct the problem here." >&2
480 if test "$2" = rootfs
484 echo "reflash: $2: continuing with rootfs changes" >&2
485 echo " NOTE: the kernel in $4 must be reflashed!" >&2
487 *) echo " failed" >&2
488 echo "reflash($1): $3: internal error flashing $2 to $4" >&2
495 echo -n "reflash: writing usrfs to $usrdev " >&2
497 check_status $? usrfs "$usrfile($imgusroffset,$imgusrsize)" "$usrdev"
502 echo -n "reflash: writing rootfs to $ffsdev " >&2
504 check_status $? rootfs "$ffsfile($imgffsoffset,$imgffssize)" "$ffsdev"
509 echo -n "reflash: writing kernel to $kdev " >&2
511 check_status $? kernel "$kfile($imgkoffset,$imgksize)" "$kdev"
514 # verify - this just produces a warning
517 echo -n "reflash: verifying new usr image " >&2
523 echo "reflash: WARNING: usrfs flash image verification failed" >&2
524 echo " The system is may be bootable." >&2
530 echo -n "reflash: verifying new flash image " >&2
536 echo "reflash: WARNING: rootfs flash image verification failed" >&2
537 echo " The system is probably unbootable." >&2
538 echo " System configuration files will be restored but this may fail" >&2
539 echo " Starting a shell for user recovery (exit to continue)" >&2
540 PS1='badflash$ ' sh -i <>/dev/tty >&0 2>&0
546 echo -n "reflash: verifying new kernel image " >&2
552 echo "reflash: WARNING: kernel flash image verification failed" >&2
553 echo " The system is probably unbootable." >&2
554 echo " System configuration files will be restored in the rootfs." >&2
558 # RESTORE THE OLD CONFIGURATION
559 # -----------------------------
560 # If not write the rootfs none of the following is required - exit now.
561 test -n "$ffsdev" -a -n "$preserve_config" || exit 0
563 echo "reflash: restoring saved configuration files" >&2
565 # the file /etc/.configured is the datestamp file used to ensure that
566 # changed configuration files can be recognised. It is created by
567 # /etc/rcS.d/S99finish on first boot (if it does not exist). We need
568 # a timestamp earlier than any files we create so touch it here, this
569 # also acts as a test on the mounted file system
570 mountflash "$ffsdev" "$ffsdir" && :>"$ffsdir/etc/.configured" || {
572 echo "reflash: mount of new flash root file system failed" >&2
573 if test -d "$ffsdir/etc"
575 echo " The file system does not seem to be writeable." >&2
576 echo " The mounted file system is in $ffsdir" >&2
578 echo " WARNING: the kernel and root file system have been reflashed," >&2
579 echo " HOWEVER the new root file system seems to be unuseable." >&2
580 echo " Saved configuration files are in $saved" >&2
581 echo " The list of saved configuration files is in $list" >&2
582 echo " You should determine the reason for the failed mount, mount the new" >&2
583 echo " file system and restore the configuration from $saved - it's just a" >&2
584 echo " matter of copying the saved files where required." >&2
588 # sysconf_restore_conffiles <flash-directory> <source-dir> <restore>
589 restore="/tmp/restore.$$"
590 sysconf_restore_conffiles "$ffsdir" "$saved" "$restore" <"$list" || {
591 echo "reflash: $saved: restore of saved configuration files failed" >&2
592 echo " The new flash file system is mounted on $ffsdir" >&2
593 echo " The saved files are in $saved and the list in $list, the list of" >&2
594 echo " files selected for restore is in $restore" >&2
595 echo " You should restore any required configuration from $saved," >&2
596 echo " then umount $ffsdir and reboot." >&2
600 # remove the copied files (i.e. the ones which were preserved)
602 exec rm $(cat "$restore")
606 # clean up, files left in $saved need to be handled by the user
607 files="$(find "$saved" ! -type d -print)"
610 echo "reflash: the following saved configuration files remain:" >&2
612 echo "The full list of preserved files is in $list. To alter the" >&2
613 echo "new root file system use the command:" >&2
615 echo " mount -t jffs2 $ffsdev /mnt" >&2
617 echo "The saved files are in the temporary directory, they will not" >&2
618 echo "be retained across a system boot. Copy them elsewhere if you" >&2
619 echo "are unsure whether they are needed" >&2
625 # now the final umount
629 echo "reflash: system upgrade complete. Reboot to continue." >&2
632 echo "reflash: $ffsdir: temporary mount point umount failed" >&2
633 echo " ALL changes have been made successfully, however the umount of" >&2
634 echo " the new root file system has failed. You should determine the" >&2
635 echo " cause of the failure, umount $ffsdir, then reboot the system (this" >&2
636 echo " will use the upgraded kernel and root file system)" >&2