#!/bin/bash

#######################################################################
#
#  Copyright (C) 2007 SCL Internet
#                www.scl.co.uk
#
#  Author:      John Sutton john@scl.co.uk
#
#  $Id: mountjffs
#
#  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.
#
#######################################################################
#
#  mountjffs : a shell script for mounting 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.
ROOTFS=464	# 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 mountpoint {umount | {root|user} flashfilename}" >&2
	exit 1
}

# Check the arguments.
[ $# = 2 -o $# = 3 ] || usage
[ -d "$1" ] || usage "Mount point specified is not a directory: $1"
MP=$1

[ root = "$2" -o user = "$2" -o umount = "$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"
}

# Unmount and unload the 5 modules.
umount $MP 2>/dev/null
modprobe -r mtdblock mtdchar mtdram jffs2 mtdcore || exit 2

# 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))

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

# Load up the 5 modules.
modprobe mtdcore
modprobe jffs2
modprobe mtdram total_size=$((numrepeats*128))
modprobe mtdchar
modprobe mtdblock

# Find the device files
while true
do
	CDEV=/dev/mtd0; [ -c $CDEV ] && break
	CDEV=/dev/mtd/0; [ -c $CDEV ] && break
	echo "Can't find mtd character device" >&2; exit 2
done
while true
do
	BDEV=/dev/mtdblock0; [ -b $BDEV ] && break
	BDEV=/dev/mtdblock/0; [ -b $BDEV ] && break
	echo "Can't find mtd block device" >&2; exit 2
done

# 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 >$CDEV | grep -v "^$datablock+0 records \(in\|out\)$" >&2

# Mount it readonly - not much point in allowing it to be modified since
# we don't know how to calculate the checkblocks which would be needed to
# construct a new flash file.
mount -t jffs2 -r $BDEV $MP || echo "Maybe you need to adjust ROMFS or ROOTFS?"
