diff options
Diffstat (limited to 'packages/openslug-init/openslug-init-0.10/reflash')
-rw-r--r-- | packages/openslug-init/openslug-init-0.10/reflash | 560 |
1 files changed, 339 insertions, 221 deletions
diff --git a/packages/openslug-init/openslug-init-0.10/reflash b/packages/openslug-init/openslug-init-0.10/reflash index dc6ef0bbd8..504e78f694 100644 --- a/packages/openslug-init/openslug-init-0.10/reflash +++ b/packages/openslug-init/openslug-init-0.10/reflash @@ -11,52 +11,13 @@ # /etc/default/functions contains useful utility functions . /etc/default/functions # -# CHECKING THE ENVIRONMENT -# ------------------------ -# basic setup. This could be parameterised to use different partitions! -ffspart=Flashdisk -kpart=Kernel -# -ffsdev="$(mtblockdev $ffspart)" -test -n "$ffsdev" -a -b "$ffsdev" || { - echo "reflash: $ffspart($ffsdev): cannot find $ffspart mtd partition." >&2 - echo " check /proc/mtd, either the partition does not exist or there is no" >&2 - echo " corresponding block device." >&2 - exit 1 -} -ffssize="$(devio "<<$ffsdev" 'pr$')" -# -kdev="$(mtblockdev $kpart)" -test -n "$kdev" -a -b "$kdev" || { - echo "reflash: $kpart($kdev): cannot find $kpart mtd partition." >&2 - echo " check /proc/mtd, either the partition does not exist or there is no" >&2 - echo " corresponding block device." >&2 - exit 1 -} -ksize="$(devio "<<$kdev" 'pr$')" -# -# find the device number of the flash partition then make sure it isn't -# mounted anywhere. -ffsno="$(devio "<<$ffsdev" prd)" -test -n "$ffsno" -a "$ffsno" -ge 0 || { - echo "reflash: $ffsdev: device number $ffsno is not valid, cannot continue." >&2 - exit 1 -} -# -# Make sure that Flashdisk isn't mounted on / -if test "$(devio "<</etc/init.d/sysconfsetup" prd)" -eq "$ffsno" -then - echo "reflash: $ffsdev is mounted on /, use turnup ram to reflash" >&2 - exit 1 -fi -# # CHECKING FOR INPUT (ARGUMENTS ETC) # ---------------------------------- # -# find the kernel and the new flash file system, they default to /boot/zImage -# and /boot/rootfs.jffs2, an image file can be used to specify both images. -ffsfile=/boot/rootfs.jffs2 -kfile=/boot/zImage +# find the kernel and the new flash file system, an image file can +# be used to specify both images. +ffsfile= +kfile= imgfile= while test $# -gt 0 do @@ -67,15 +28,13 @@ do exit 1 } kfile="$1" - imgfile= shift;; - -j) shift + -[jr]) shift test $# -gt 0 || { echo "reflash: -j: give the file containing the root jffs2 image" >&2 exit 1 } ffsfile="$1" - imgfile= shift;; -i) shift test $# -gt 0 || { @@ -84,20 +43,31 @@ do } imgfile="$1" shift;; - *) echo "reflash: usage: $0 [-k kernel -j rootfs] | -i image" >&2 - echo " -k [$kfile]: the new compressed kernel image ('zImage')" >&2 - echo " -j [$ffsfile]: the new root file system (jffs2)" >&2 - echo " -i image: a complete flash image (gives both kernel and jffs2)" >&2 + *) echo "reflash: usage: $0 [-k kernel] [-j rootfs] [-i image]" >&2 + echo " -k file: the new compressed kernel image ('zImage')" >&2 + echo " -j file: the new root file system (jffs2)" >&2 + echo " -i file: a complete flash image (gives both kernel and jffs2)" >&2 echo " The current jffs2 will be umounted if mounted." >&2 exit 1;; esac done # +# Sanity check on the arguments +if test -n "$imgfile" -a -n "$ffsfile" -a -n "$kfile" +then + echo "reflash: -k,-j,-i: specify at most two files" >&2 + echo " -i has both a kernel and rootfs, the kernel from -k and" >&2 + echo " the rootfs from -j override the one in the image (if given)" >&2 + exit 1 +elif test -z "$imgfile" -a -z "$ffsfile" -a -z "$kfile" +then + echo "reflash: -k,-j,-i: specify at least one file to flash" >&2 + exit 1 +fi +# # Perform basic checks on the input (must exist, size must be ok). if test -n "$imgfile" then - kfile= - ffsfile= if test -r "$imgfile" then # read the partition table and from this find the offset @@ -120,6 +90,7 @@ then done <<EOI $(devio "<<$imgfile" ' <= $ 0x20000 - + L= 0x1000 $( 1 # 0xff byte in name[0] ends the partition table $? @ 255 = @@ -133,219 +104,366 @@ $(devio "<<$imgfile" ' cp 16 pn <= f240+ - $) 1') + L= L256- + $) L255>') EOI # check the result - test -n "$imgksize" -a "$imgksize" -gt 0 -a "$imgksize" -le "$ksize" || { - echo "reflash: $imgfile: bad kernel size ($imgksize, max $ksize)" >&2 + test "$imgksize" -gt 0 -a "$imgkoffset" -ge 0 || { + echo "reflash: $imgfile: failed to find Kernel partition in image" >&2 + exit 1 + } + # the kernel is after a 16 byte header which holds the + # values length,0,0,0 Get the true size. + ktmp="$(devio "<<$imgfile" "L=$imgksize" "O=$imgkoffset" ' + $( OL+$>! + <= O + A= b + $( AL>! + pr A + $) 0 + $) 0')" + test "$ktmp" -gt 0 || { + echo "reflash: $imgfile($imgkoffset,$imgksize): invalid kernel offset/size" >&2 exit 1 } - test -n "$imgffssize" -a "$imgffssize" -gt 0 -a "$imgffssize" -le "$ffssize" || { - echo "reflash: $imgfile: bad flashdisk size ($imgffssize, max $ffssize)" >&2 + # update the size and offset to these values (the offset is 16+ because + # of the header). + imgksize="$ktmp" + imgkoffset="$(devio "O=$imgkoffset" 'pr O16+')" + # just test the size for the rootfs + test "$imgffssize" -gt 0 -a "$imgffsoffset" -ge 0 || { + echo "reflash: $imgfile: failed to find Flashdisk" >&2 exit 1 } else echo "reflash: $imgfile: image file not found" >&2 exit 1 fi -else - if test -r "$kfile" +fi +if test -n "$kfile" +then + if test ! -r "$kfile" then - # check the size - s="$(devio "<<$kfile" 'pr$')" - test -n "$s" -a "$s" -gt 0 -a "$s" -le "$ksize" || { - echo "reflash: $kfile: bad size ($s, max $ksize)" >&2 - exit 1 - } - else echo "reflash: $kfile: kernel file not found" >&2 exit 1 fi - if test -r "$ffsfile" + # the file values override anything from the image. + imgksize="$(devio "<<$kfile" 'pr$')" + imgkoffset=0 +else + kfile="$imgfile" +fi +if test -n "$ffsfile" +then + if test ! -r "$ffsfile" then - s="$(devio "<<$ffsfile" 'pr$')" - test -n "$s" -a "$s" -gt 0 -a "$s" -le "$ffssize" || { - echo "reflash: $ffsfile: bad size ($s, max $ffssize)" >&2 - exit 1 - } - else echo "reflash: $ffsfile: root file system image file not found" >&2 exit 1 fi + # values override those from the image + imgffssize="$(devio "<<$ffsfile" 'pr$')" + imgffsoffset=0 +else + ffsfile="$imgfile" +fi +# +# INPUTS OK, CHECKING THE ENVIRONMENT +# ----------------------------------- +# basic setup. This could be parameterised to use different partitions! +kpart=Kernel +ffspart=Flashdisk +# +kdev= +ksize=0 +if test -n "$kfile" +then + # we have a new kernel + kdev="$(mtblockdev $kpart)" + test -n "$kdev" -a -b "$kdev" || { + echo "reflash: $kpart($kdev): cannot find $kpart mtd partition." >&2 + echo " check /proc/mtd, either the partition does not exist or there is no" >&2 + echo " corresponding block device." >&2 + exit 1 + } + ksize="$(devio "<<$kdev" 'pr$')" + # + # check the input file size + test -n "$imgksize" -a "$imgksize" -gt 0 -a "$imgksize" -le "$ksize" || { + echo "reflash: $kfile: bad Kernel size ($s, max $ksize)" >&2 + exit 1 + } fi # -# INPUTS OK, UMOUNT ANY EXISTING MOUNT OF THE FLASHDISK -# ---------------------------------------------------- -echo "reflash: umounting any existing mount of $ffsdev" >&2 +ffsdev= +ffssize=0 +if test -n "$ffsfile" +then + ffsdev="$(mtblockdev $ffspart)" + test -n "$ffsdev" -a -b "$ffsdev" || { + echo "reflash: $ffspart($ffsdev): cannot find $ffspart mtd partition." >&2 + echo " check /proc/mtd, either the partition does not exist or there is no" >&2 + echo " corresponding block device." >&2 + exit 1 + } + ffssize="$(devio "<<$ffsdev" 'pr$')" + # + # check the input file size + test -n "$imgffssize" -a "$imgffssize" -gt 0 -a "$imgffssize" -le "$ffssize" || { + echo "reflash: $ffsfile: bad Flashdisk size ($s, max $ffssize)" >&2 + exit 1 + } +fi # -# check each mount point, do this last first because otherwise nested -# mounts of ffsdev cannot be umounted. -ffs_umount() { - local device mp type options stuff +# find the device number of the flash partition then make sure it isn't +# mounted anywhere. +if test -n "$ffsdev" +then + ffsno="$(devio "<<$ffsdev" prd)" + test -n "$ffsno" -a "$ffsno" -ge 0 || { + echo "reflash: $ffsdev: device number $ffsno is not valid, cannot continue." >&2 + exit 1 + } + # + # Make sure that Flashdisk isn't mounted on / + if test "$(devio "<</etc/init.d/sysconfsetup" prd)" -eq "$ffsno" + then + echo "reflash: $ffsdev is mounted on /, use turnup ram to reflash" >&2 + exit 1 + fi +fi +# +# INPUTS OK, ENVIRONMENT OK, UMOUNT ANY EXISTING MOUNT OF THE FLASHDISK +# --------------------------------------------------------------------- +# This is only required if the device is going to be used +if test -n "$ffsdev" +then + echo "reflash: umounting any existing mount of $ffsdev" >&2 + # + # check each mount point, do this last first because otherwise nested + # mounts of ffsdev cannot be umounted. + ffs_umount() { + local device mp type options stuff - read device mp type options stuff - test -z "$device" && return 0 + read device mp type options stuff + test -z "$device" && return 0 - # handle following entries first - ffs_umount || return 1 + # handle following entries first + ffs_umount || return 1 - # handle this entry - case "$type" in - jffs2) test "$(devio "<<$mp/etc/init.d/sysconfsetup" prd)" -ne "$ffsno" || - umount "$mp" || { - echo "reflash: $mp: unable to umount $ffsdev" >&2 - return 1 - };; - esac + # handle this entry + case "$type" in + jffs2) test "$(devio "<<$mp/etc/init.d/sysconfsetup" prd)" -ne "$ffsno" || + umount "$mp" || { + echo "reflash: $mp: unable to umount $ffsdev" >&2 + return 1 + };; + esac - return 0 -} -# -ffs_umount </proc/mounts || { - echo "reflash: umount $ffsdev from all mount points then re-run reflash" >&2 - exit 1 -} + return 0 + } + # + ffs_umount </proc/mounts || { + echo "reflash: umount $ffsdev from all mount points then re-run reflash" >&2 + exit 1 + } + # + # Everything is umounted, now remount on a temporary directory. + ffsdir="/tmp/flashdisk.$$" + mkdir "$ffsdir" || { + echo "reflash: $ffsdir: failed to create temporary directory" >&2 + exit 1 + } + # + mountflash "$ffsdir" -o ro || { + rmdir "$ffsdir" + exit 1 + } + # + # this is a utility function to make the cleanup easier + errorexit() { + umount "$ffsdir" && rmdir "$ffsdir" || + echo "reflash: $ffsdir: temporary directory cleanup failed" >&2 + exit 1 + } + # + test -r "$ffsdir/etc/default/conffiles" || { + echo "reflash: [/initrd]/etc/default/conffiles: file not found" >&2 + errorexit + } +else + errorexit() { + exit 1 + } +fi # -# Everything is umounted, now remount on a temporary directory. -ffsdir="/tmp/flashdisk.$$" -mkdir "$ffsdir" || { - echo "reflash: $ffsdir: failed to create temporary directory" >&2 - exit 1 -} +# PRESERVE EXISTING CONFIGURATION +# ------------------------------- +# Only required if the flash partition will be written +if test -n "$ffsdev" +then + echo "reflash: preserving existing configuration file" >&2 + # + # This step produces /tmp/preserve.$$ and /tmp/cpio.$$, the former is + # a list of the preserved configuration files together with the processing + # option, the latter is a directory tree of the preserved files (a directory + # tree makes the restore step easier.) + saved=/tmp/cpio.$$ + list=/tmp/preserve.$$ + mkdir "$saved" || { + echo "reflash: $saved: could not create save directory" >&2 + errorexit + } + # + ( cd "$ffsdir" + find etc/*.conf $(sed 's!^/!!' usr/lib/ipkg/info/*.conffiles) ! -type d -newer etc/.configured -print | + sed 's/^/diff /' + exec sed 's/#.*$//;/^[ ]*$/d' etc/default/conffiles + ) | sed 's!^/*!!' | awk '{ op=$1; $1=""; file[$0]=op } + END{ for (f in file) if (file[f] != "ignore") print file[f] f }' | + while read op file + do + if test -e "$ffsdir/$file" + then + echo "$op $file" >&3 + echo "$file" + fi + done 3>"$list" | (cd "$ffsdir"; exec cpio -p -d -m -u "$saved") || { + echo "reflash: $saved: copy of saved configuration files failed" >&2 + rm -rf "$saved" + rm "$list" + errorexit + } + # + # If this umount fails do not try to continue... + umount "$ffsdir" || { + echo "reflash: $ffsdir: temporary mount point umount failed" >&2 + echo " No changes have been made." >&2 + rm -rf "$saved" + rm "$list" + exit 1 + } +fi # -mountflash "$ffsdir" -o ro || { - rmdir "$ffsdir" - exit 1 +# FLASH THE NEW IMAGES +# -------------------- +echo "reflash: about to flash new image" >&2 +# +# There are four possibilities here - kernel only, flashdisk only, then +# kernel&flashdisk in either one or two different files. The code used +# to attempt to do everything in one step, but this complicates it, +# so two steps are used (as required). A failure between the two +# steps is a problem, but then so is a failure in a partial write. +# Write the flashdisk first because this is larger (most likely to +# fail). +# Temporarily check for devio progress indicator capability this way... +if devio -p '' 2>/dev/null +then + progress=-p +else + progress= +fi +do_kernel() { + devio $progress "$@" "<<$kfile" ">>$kdev" ' + # kernel is at imgkoffset[imgksize] + ' "<= $imgkoffset" "L=$imgksize" ' + # kernel write length,0,0,0 header, then fill + wb L,4 + fb 12,0 + cp L + # fill with 255 + fb #t-,255' } # -# this is a utility function to make the cleanup easier -errorexit() { - umount "$ffsdir" && rmdir "$ffsdir" || - echo "reflash: $ffsdir: temporary directory cleanup failed" >&2 - exit 1 +do_ffs() { + devio $progress "$@" "<<$ffsfile" ">>$ffsdev" ' + # rootfs is at imgffsoffset[imgffssize] + ' "<= $imgffsoffset" "cp $imgffssize" ' + # fill with 255 + fb #t-,255' } # -test -r "$ffsdir/etc/default/conffiles" || { - echo "reflash: [/initrd]/etc/default/conffiles: file not found" >&2 - errorexit +# check_status $? type file(offset,size) device +# check the devio status code (given in $1) +check_status() { + case "$1" in + 0) echo " done" >&2;; + 1) echo " failed" >&2 + echo "reflash: $3: flash $2 failed, no changes have been made to $4" >&2 + if test "$2" = rootfs + then + rm -rf "$saved" + rm "$list" + exit 1 + else + echo "reflash: $2: continuing with rootfs changes" >&2 + echo " NOTE: the old kernel is still in $4!" >&2 + fi;; + 3) echo " failed" >&2 + echo "reflash: $3: WARNING: partial flash of $2 to $4 the system is unbootable" >&2 + echo " Reflash from RedBoot or correct the problem here." >&2 + if test "$2" = rootfs + then + exit 3 + else + echo "reflash: $2: continuing with rootfs changes" >&2 + echo " NOTE: the kernel in $4 must be reflashed!" >&2 + fi;; + *) echo " failed" >&2 + echo "reflash($1): $3: internal error flashing $2 to $4" >&2 + exit $1;; + esac } # -# PRESERVE EXISTING CONFIGURATION -# ------------------------------- -echo "reflash: preserving existing configuration file" >&2 +if test -n "$ffsdev" +then + echo -n "reflash: writing rootfs to $ffsdev " >&2 + do_ffs + check_status $? rootfs "$ffsfile($imgffsoffset,$imgffssize)" "$ffsdev" +fi # -# This step produces /tmp/preserve.$$ and /tmp/cpio.$$, the former is -# a list of the preserved configuration files together with the processing -# option, the latter is a directory tree of the preserved files (a directory -# tree makes the restore step easier.) -saved=/tmp/cpio.$$ -list=/tmp/preserve.$$ -mkdir "$saved" || { - echo "reflash: $saved: could not create save directory" >&2 - errorexit -} +if test -n "$kdev" +then + echo -n "reflash: writing kernel to $kdev " >&2 + do_kernel + check_status $? kernel "$kfile($imgkoffset,$imgksize)" "$kdev" +fi # -( cd "$ffsdir" - find etc/*.conf $(sed 's!^/!!' usr/lib/ipkg/info/*.conffiles) ! -type d -newer etc/.configured -print | - sed 's/^/diff /' - exec sed 's/#.*$//;/^[ ]*$/d' etc/default/conffiles -) | sed 's!^/*!!' | awk '{ op=$1; $1=""; file[$0]=op } - END{ for (f in file) if (file[f] != "ignore") print file[f] f }' | -while read op file -do - if test -e "$ffsdir/$file" +# verify - this just produces a warning +if test -n "$ffsdev" +then + echo -n "reflash: verifying new flash image " >&2 + if do_ffs -v then - echo "$op $file" >&3 - echo "$file" + echo " done" >&2 + else + echo " failed" >&2 + echo "reflash: WARNING: rootfs flash image verification failed" >&2 + echo " The system is probably unbootable." >&2 + echo " System configuration files will be restored but this may fail" >&2 + echo " Starting a shell for user recovery (exit to continue)" >&2 + PS1='badflash$ ' sh -i <>/dev/tty >&0 2>&0 fi -done 3>"$list" | (cd "$ffsdir"; exec cpio -p -d -m -u "$saved") || { - echo "reflash: $saved: copy of saved configuration files failed" >&2 - rm -rf "$saved" - rm "$list" - errorexit -} -# -# If this umount fails do not try to continue... -umount "$ffsdir" || { - echo "reflash: $ffsdir: temporary mount point umount failed" >&2 - echo " No changes have been made." >&2 - rm -rf "$saved" - rm "$list" - exit 1 -} -# -# FLASH THE NEW IMAGES -# -------------------- -echo "reflash: about to flash new images" >&2 +fi # -# If the images are in separate files do this in two steps, kernel then -# rootfs (this seems like it might be safer if the first fails). For an -# image file use one step but still write the kernel first. -do_devio() { - if test -r "$imgfile" - then - # image file case - copy the whole of the image partition, - # which already includes headers (etc). - devio "$@" "<<$imgfile" ">>$ffsdev" ">>$kdev" ' - # kernel is at imgkoffset[imgksize] - ' "<= $imgkoffset" "cp $imgksize" ' - fb #t-,255 - ' "<>$kdev" ">>$ffsdev" ' - # rootfs is at imgffsoffset[imgffssize] - ' "<= $imgffsoffset" "cp $imgffssize" ' - fb #t-,255' - elif test -r "$kfile" -a -r "$ffsfile" +if test -n "$kdev" +then + echo -n "reflash: verifying new kernel image " >&2 + if do_kernel -v then - # use separate files, do this in one command to be sure - # that everything can be opened at the start - devio "$@" "<<$ffsfile" ">>$ffsdev" "<<$kfile" ">>$kdev" ' - # kernel write length+16,0,0,0 header, then fill - wb $16+,4 - fb 12,0 - cp $ - fb #t-,255 - ' "<>$kfile" "<>$kdev" "<<$ffsfile" ">>$ffsdev" ' - # rootfs, write the whole image, fill if necessary - cp $ - fb #t-,255' + echo " done" >&2 else - # oops, my checking was wrong... - echo "reflash: internal error: image files not found!" >&2 - echo " No changes have been made." >&2 - exit 2 + echo " failed" >&2 + echo "reflash: WARNING: kernel flash image verification failed" >&2 + echo " The system is probably unbootable." >&2 + echo " System configuration files will be restored in the rootfs." >&2 fi -} -# -echo "reflash: writing kernel to $kdev and rootfs to $ffsdev..." >&2 -do_devio -st=$? -case "$st" in -0) ;; -1) echo "reflash: flash of new images failed, no changes have been made" >&2 - rm -rf "$saved" - rm "$list" - exit 1;; -3) echo "reflash: WARNING: partial flash, the system is unbootable" >&2 - echo " Reflash from RedBoot or correct the problem here." >&2 - exit 3;; -*) echo "reflash($st): internal error" >&2 - exit $st;; -esac -echo " ... done" >&2 -# -# verify - this just produces a warning -echo "reflash: verifying new flash image..." >&2 -do_devio -v || { - echo "reflash: WARNING: flash image verification failed" >&2 - echo " The system is probably unbootable." >&2 - echo " System configuration files will be restored but this may fail" >&2 - echo " Starting a shell for user recovery (exit to continue)" >&2 - PS1='badflash$ ' sh -i <>/dev/tty >&0 2>&0 -} -echo " ... done" >&2 +fi # # RESTORE THE OLD CONFIGURATION # ----------------------------- +# If not write the rootfs none of the following is required - exit now. +test -n "$ffsdev" || exit 0 +# echo "reflash: restoring saved configuration files" >&2 # # the file /etc/.configured is the datestamp file used to ensure that |