#!/bin/bash

#######################################################################
#
#  Copyright (C) 2007 SCL Internet
#                www.scl.co.uk
#
#  Original Author:      John Sutton [EMAIL PROTECTED]
#
#  $Id: dumpjffs$
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
#######################################################################
#
#  dumpjffs : a shell script for extracting the jffs filesystems which
#              are contained in the 128Mb NAND flash backup image produced
#              by a Zaurus SL-C1000.
#
#######################################################################

: <<EOC

The primitive block in a SYSTC100.DBK flash file is 16 bytes long, we call
this a pblock.

The filesystems contained in the flash file are split up into a number of
datablocks each of which is 8192 pblocks = 128kb long.  Each datablock is
followed by a checkblock (which presumably contains some kind of checksums,
of unknown type), each checkblock is 256 pblocks.

A repeatblock is made up of a 1 pblock header followed by a datablock and
then a checkblock, i.e., a total of 1+8192+256 pblocks per repeatblock.

The flash file as a whole consists of a 1 pblock header followed by 1024
repeatblocks, i.e., (1+1024*(1+8192+256))*16 = 138428432 bytes total.

The flash file contains 3 filesystems in this order: rom, root, user.  The
rom fs contains the diagnostics menu etc and is NOT a jffs fs at all.  We only
need to know how long it is so that we can skip over it to find the root fs.
Ditto, if we know the size of the rom and root fs's, we can skip over both to
find the user fs.  So, we need to specify the size, in 128k blocks, of the
rom and root fs's and then the whole structure is specified.

YOU MAY NEED TO ADJUST THE TWO PARAMETERS BELOW.

Run the indicated commands on the zaurus to find your values.  It is unlikely
that ROMFS needs changing - I think this is fixed in the firmware at 7Mb,
i.e., 7 x 8 = 56 128kb blocks.  ROOTFS on the other hand will depend on how
you have divided up the remaining 121Mb between the root and user partitions.

EOC

ROMFS=56        # Use 'wc -c </dev/mtdblock1' and divide result by 128x1024.
#this next number is what I got according to my c3100 zaurus, you will probably have a different number - xamindar
ROOTFS=256      # Use 'df' to find the 1k-blocks for /dev/root and divide by 128.

# START

progname=`basename $0`

function usage {
        [ $# -gt 0 ] && echo "$@" >&2
        echo "usage: $progname outfile {{rom|root|user|all} flashfilename}" >&2
        exit 1
}

# Check the arguments.
[ $# = 2 -o $# = 3 ] || usage
[ -e "$1" ] && usage "file exists: $1"
#MP=$1
OF=$1

[ root = "$2" -o user = "$2" -o rom = "$2" -o all = "$2" ] || \
                                usage "Invalid filesystem identifier or 
operation: $2"
FS=$2

# We don't actually need the flash file if umount is specified, but if the
# user has given a 3rd arg we'll check it anyway.
[ $# = 3 ] && {
        [ -r "$3" ] || usage "Can't open flash file: $3"
        FF="$3"
}



# If umount specified, we are finished.
[ $FS = umount ] && exit 0

# Define the number of pblocks in each element of a repeatblock.
datablock=8192
checkblock=256

# Calculate the number of repeatblocks for the specified fs.
[ $FS = root ] && numrepeats=$ROOTFS || numrepeats=$((1024-ROMFS-ROOTFS))
[ $FS = rom ] && numrepeats=$ROMFS
[ $FS = all ] && numrepeats=1024

# Calculate the number of repeatblocks which come before this fs.
[ $FS = root ] && offset=$ROMFS || offset=$((ROMFS+ROOTFS))
[ $FS = rom ] && offset=0
[ $FS = all ] && offset=0



# Set up the pointer variable (in pblocks) for the loop.
in=$(( 1+offset*(1+datablock+checkblock) ))

# One iteration per repeatblock.
for (( i = 0; i < numrepeats; i++ ))
do
        # Skip over the repeatblock header.
        (( in += 1 ))

        # Write out the datablock.
        dd bs=16 skip=$in count=$datablock if="$FF"

        # Increment the pointer for the next repeatblock.
        (( in += datablock+checkblock ))

done 2>&1 >$OF | grep -v "^$datablock+0 records \(in\|out\)$" >&2

