OSEC

Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
 
Re: Duplicating File System - Compact Flash

From: Abel Talaveron (abelteya.com)
Date: Wed Jan 19 2005 - 16:31:10 CST


> Hello,
>
> I was wondering if anyone had a quick tutorial/HOW-TO on this subject.
> Here's what I want to accomplish:
>
> I have a 1GB Compact Flash drive running OpenBSD v3.6. I would like to be
> able to duplicate the entire file system onto another 1GB compact flash
> card for backup and duplication reasons. The backup flash card needs to
> be
> identical to the existing one and be bootable. All free space also needs
> to be retained.
>
> Is there an easy way to do this? I have a USB Compact Flash Writer in a
> Windows workstation and ideally would like to be able to do a "rawrite" or
> something of an exported image file.
>
> TIA...Steve
>
>

It seems that the attached file has been removed. Here you have it:

#!/bin/sh

IMAGE_FILE=./image_cf
DISKLABEL_TMP=cf.$$.t
VNODE_DEV=svnd0
VNODE_MOUNT=./__mount_cf__
DEFAULT_ROOT=./root_cf
DEFAULT2_ROOT=./root
FILE_EXTENSION=cf

# boot settings
FIRST_BOOT=usr/mdec/biosboot
SECOND_BOOT=boot
MBR_TEMPLATE=usr/mdec/mbr

###############################################################################

cat << __EOF

Soekris CF Install Script for OpenBSD
Copyright 2003 Gray Watson
http://256.com/gray/docs/soekris_openbsd_diskless/
-------------------------------------

__EOF

#################################################

echo -n "Enter the filename to write the image into: [$IMAGE_FILE] "
read image_file
if [ "$image_file" = "" ]; then
    image_file=$IMAGE_FILE
fi

#################################################

cat << __EOF
----------
Type in size of CF card in MB. Either: 32, 64, 128, 256.

If your size isn't in the above list then insert the CF card into your
Soekris box and boot it and write down what it says. When it boots it
should say:

    Pri Mas [ Name of CF Card ] LBA: CCC-TT-SS MMM MByte.

The CCC is the number of cylinders, TT is the tracks per cylinder, and SS
is the sectors per track. The MMM is the number of megabytes on the card
with some space removed for rounding.

__EOF
echo -n "Enter size in MB or just press enter to type in drive specs: "
read cf_size

case $cf_size in
    32)
 # 32mb CF
 sectors_track=32 # "sectors/track:"
 tracks_cylinder=8 # "tracks/cylinder:"
 cylinders=245 # "cylinders:"
 ;;
    64)
 # 64mb CF
 sectors_track=32 # "sectors/track:"
 tracks_cylinder=8 # "tracks/cylinder:"
 cylinders=490 # "cylinders:"
 ;;
    128)
 # 128Meg CF
 sectors_track=32 # "sectors/track:"
 tracks_cylinder=64 # "tracks/cylinder:"
 cylinders=122 # "cylinders:"
 ;;
    256)
 # 256Meg CF
 sectors_track=32 # "sectors/track:"
 tracks_cylinder=16 # "tracks/cylinder:"
 cylinders=980 # "cylinders:"
 ;;

    *)
 echo -n "Enter cylinders: "
 read cylinders
 echo -n "Tracks per cylinder: "
 read tracks_cylinder
 echo -n "Sectors per track: "
 read sectors_track
 ;;
esac

#################################################

# calculate our total size of the image in 512b blocks
total_blocks=`expr $cylinders \* $tracks_cylinder \* $sectors_track`
total_bytes=`expr $total_blocks \* 512`
# calculate sectors per cylinder
sectors_cylinder=`expr $tracks_cylinder \* $sectors_track`

# calculate the wd0a partition size
a_blocks=`expr $cylinders \* $sectors_cylinder`
#
# From flashdist.sh by Chris Cappuccio and modified by Ron Rosson.
# Here we remove additional cylinders while
# (totalsize <= (cylinders*(sectors/cylinder))) so that
# we have room for the b partition and still lie on a cylinder boundary:
#
while [ "$total_blocks" -le "$a_blocks" ]; do
    a_blocks=`expr $a_blocks - $sectors_cylinder`
done

# remove the first track where the disklabel goes
a_blocks=`expr $a_blocks - $sectors_track`
a_bytes=`expr $a_blocks \* 512`

# start our minimal swap partition
b_offset=`expr $a_blocks + $sectors_track`
b_blocks=1
b_bytes=`expr $b_blocks \* 512`

cat << __EOF
----------

Here are the final settings for the image in terms of partition map
and filesystem settings. Please review and press control-c to quit if
there are any problems. If you don't understand any of this then just
press enter.

Partition Map:
             cylinders: $cylinders
   tracks per cylinder: $tracks_cylinder
     sectors per track: $sectors_track
  sectors per cylinder: $sectors_cylinder
    total image blocks: $total_blocks
     total image bytes: $total_bytes

Disklabel:
  partition 'a' offset: $sectors_track
  partition 'a' blocks: $a_blocks
   partition 'a' bytes: $a_bytes
  partition 'b' offset: $b_offset
  partition 'b' blocks: $b_blocks
   partition 'b' bytes: $b_bytes

__EOF

echo -n "Press enter to continue or press control-c to quit and correct. "
read doit

#################################################

cat << __EOF
----------
Enter the vnode device to use. If you do not know what this is then
just press enter to take the default of "$VNODE_DEV".

__EOF
echo -n "Vnode device [$VNODE_DEV]: "
read vnode_device
if [ "$vnode_device" = "" ]; then
    vnode_device=$VNODE_DEV
fi

#################################################

cat << __EOF
----------
Enter the directory path to the files that you want to load into the
CF image. The default is the directory $DEFAULT_ROOT in the current
directory.
It is assumed that this directory has the kernel files, boot
configuration files, and all other information necessary for the
system to work. The directory should hold the following boot files in
these specific relevant places. If you are using the root directory
then the following files should exist:

    # second-stage boot program to be installed in /
    $DEFAULT_ROOT/$SECOND_BOOT
    # first-stage boot program installed in the boot block
    $DEFAULT_ROOT/$FIRST_BOOT
    # alternate master-boot-record template file for fdisk
    $DEFAULT_ROOT/$MBR_TEMPLATE

__EOF

default_root=$DEFAULT_ROOT
if [ ! -d $default_root ]; then
    default_root=$DEFAULT2_ROOT
fi

echo -n "Root filesystem directory [$default_root]: "
read root_dir

if [ "$root_dir" = "" ]; then
    root_dir=$default_root
fi

if [ ! -d $root_dir ]; then
    echo "I cannot see the directory $root_dir"
    exit 1
fi

############################################################################

# create the image file
echo "----------"
doit=yes
if [ -f $image_file ]; then
    echo -n "Image file $image_file exists. Re-zero or re-create it? [yes]
"
    read doit
    if [ "$doit" = "" ]; then
 doit=yes
    fi
fi
if [ "$doit" = "yes" ]; then
    echo "Creating image file $image_file"
    rm -f $image_file
    dd if=/dev/zero of=$image_file bs=512 count=$total_blocks
    if [ $? -ne 0 ]; then
 echo "dd to $image_file failed"
 exit 1
    fi
fi

#################################################

# now map it into the vnode device
echo "----------"
echo "Mapping $image_file to vnode device $vnode_device."
vnconfig $vnode_device $image_file
if [ $? -ne 0 ]; then
    echo "Mapping $image_file to vnode device $vnode_device failed."
    exit 1
fi

#################################################

# configure the partitions
echo "----------"
echo "Updating the partition map for $vnode_device"
fdisk -c $cylinders -h $tracks_cylinder -s $sectors_track \
    -f $root_dir/$MBR_TEMPLATE -e $vnode_device << __EOF
reinit
update
write
quit
__EOF
if [ $? -ne 0 ]; then
    echo "Updating partition map for vnode device $vnode_device failed."
    vnconfig -u $vnode_device
    exit 1
fi

#################################################

# create the disk label
echo ""
echo "----------"
echo "Creating disk label for $vnode_device."
cat >> $DISKLABEL_TMP << __EOF
type: SCSI
disk: vnd device
label: fictitious
flags:
bytes/sector: 512
sectors/track: $sectors_track
tracks/cylinder: $tracks_cylinder
sectors/cylinder: $sectors_cylinder
cylinders: $cylinders
total sectors: $total_blocks
rpm: 3600
interleave: 1
trackskew: 0
cylinderskew: 0
headswitch: 0 # microseconds
track-to-track seek: 0 # microseconds
drivedata: 0

16 partitions:
# size offset fstype [fsize bsize cpg]
  a: $a_blocks $sectors_track 4.2BSD 1024 8192 16
  b: $b_blocks $b_offset swap
  c: $total_blocks 0 unused 0 0
__EOF
if [ $? -ne 0 ]; then
    echo "Creating new disklabel for vnode device $vnode_device failed."
    vnconfig -u $vnode_device
    exit 1
fi

# if you want to display the label before writing, uncomment this
#cat $DISKLABEL_TMP

#################################################

# now write the disklable
echo "----------"
echo "Writing the disklabel to $vnode_device."
disklabel -R $vnode_device $DISKLABEL_TMP
if [ $? -ne 0 ]; then
    echo "Writing new disklabel to vnode device $vnode_device failed."
    vnconfig -u $vnode_device
    exit 1
fi
rm -f $DISKLABEL_TMP

#################################################

# creating new filesystem
echo "----------"
echo "Creating filesystem on /dev/r${vnode_device}a"
newfs -S 512 -u $sectors_track -z $tracks_cylinder /dev/r${vnode_device}a
if [ $? -ne 0 ]; then
    echo "Creating new filesystem on vnode device $vnode_device failed."
    vnconfig -u $vnode_device
    exit 1
fi

#################################################

# making the new filesystem directory
echo "----------"
echo "Making mount directory $VNODE_MOUNT."
mkdir $VNODE_MOUNT
if [ $? -ne 0 ]; then
    echo "Mkdir of $VNODE_MOUNT failed."
    vnconfig -u $vnode_device
    exit 1
fi

#################################################

# mounting the new filesystem
echo "----------"
echo "Mounting vnode device /dev/r${vnode_device}a on directory
$VNODE_MOUNT."
mount /dev/${vnode_device}a $VNODE_MOUNT
if [ $? -ne 0 ]; then
    echo "Mounting vnode device on $VNODE_MOUNT failed."
    rmdir $VNODE_MOUNT
    vnconfig -u $vnode_device
    exit 1
fi

#################################################

# we need to copy the boot into place first probably so it can be
# contiguous and at a specific place on the disk early for the
# bootstrap code.
echo "----------"
echo "Copying boot file from $root_dir/$SECOND_BOOT into $VNODE_MOUNT."
cp $root_dir/$SECOND_BOOT $VNODE_MOUNT
if [ $? -ne 0 ]; then
    echo "Copying boot file from $root_dir/$SECOND_BOOT into $VNODE_MOUNT
failed."
    umount $VNODE_MOUNT
    rmdir $VNODE_MOUNT
    vnconfig -u $vnode_device
    exit 1
fi

#################################################

# install the boot blocks
echo "----------"
echo "Installing boot blocks on $vnode_device."
/usr/mdec/installboot -h $tracks_cylinder -s $sectors_track \
    $VNODE_MOUNT/$SECOND_BOOT $root_dir/$FIRST_BOOT $vnode_device
if [ $? -ne 0 ]; then
    echo "Installing boot blocks on $vnode_device failed."
    umount $VNODE_MOUNT
    rmdir $VNODE_MOUNT
    vnconfig -u $vnode_device
    exit 1
fi

#################################################

# copy the files over to the new system
# first the kernels
FILES=`( cd $root_dir ; ls -d bsd* )`
echo "----------"
echo "Copying the files from $root_dir into $VNODE_MOUNT"
echo "Kernel files first:"
echo "$FILES"
echo "This may take a bit..."
( cd $root_dir ; tar -cf - $FILES ) | ( cd $VNODE_MOUNT ; tar -xpf - )
if [ $? -ne 0 ]; then
    echo "Copying kernel files from $root_dir to $VNODE_MOUNT failed."
    umount $VNODE_MOUNT
    rmdir $VNODE_MOUNT
    vnconfig -u $vnode_device
    exit 1
fi

#################################################

# next everything else but not boot or bsd
FILES=`( cd $root_dir ; ls -d .??* * | egrep -v '^boot|^bsd' )`
echo "----------"
echo "Now everything else (not boot nor bsd*):"
echo "$FILES"
echo "This may take a while..."
( cd $root_dir ; tar -cf - $FILES ) | ( cd $VNODE_MOUNT ; tar -xpf - )
if [ $? -ne 0 ]; then
    echo "Copying other files from $root_dir to $VNODE_MOUNT failed."
    umount $VNODE_MOUNT
    rmdir $VNODE_MOUNT
    vnconfig -u $vnode_device
    exit 1
fi

#################################################

cat << __EOF
----------
If you have the compact flash and the root disk files in the same
directory, then you can put files in $root_dir with a .$FILE_EXTENSION
extension
and this script will rename them to the filename without the
.$FILE_EXTENSION.
For example, a different etc/fstab file is needed for each image.

__EOF

FILES=`( cd $VNODE_MOUNT ; find . -name '*.'$FILE_EXTENSION )`
if [ "$FILES" = "" ]; then
    echo "No *.$FILE_EXTENSION files found in $root_dir."
else
    for file in $FILES
    do
        new_file=`echo $file | sed -e "s/[.]$FILE_EXTENSION$//"`
        echo -n "Rename $file to $new_file? [yes] "
        read doit
        if [ "$doit" = "" ]; then
            doit=yes
        fi
        if [ "$doit" = "yes" ]; then
            mv $VNODE_MOUNT/$file $VNODE_MOUNT/$new_file
            if [ $? -eq 0 ]; then
                echo " Done."
            else
                echo "Moving $file to $new_file failed."
                umount $VNODE_MOUNT
                rmdir $VNODE_MOUNT
                vnconfig -u $vnode_device
                exit 1
            fi
        fi
    done
fi

###############################################################################

# syncing filesystems
sync

###############################################################################

# unmounting the image
sync
echo "----------"
echo "Unmounting $VNODE_MOUNT."
umount $VNODE_MOUNT
if [ $? -ne 0 ]; then
    echo "Unmounting $VNODE_MOUNT failed."
    exit 1
fi
echo "Removing $VNODE_MOUNT directory."
rmdir $VNODE_MOUNT
if [ $? -ne 0 ]; then
    echo "Remolving directory $VNODE_MOUNT failed."
    # continue
fi

# removing the vnode
echo "Removing vnode device $vnode_device."
vnconfig -u $vnode_device
if [ $? -ne 0 ]; then
    echo "Removing vnode device $vnode_device failed."
    exit 1
fi

# sync to disk
sync

#################################################

echo "----------"
echo "Done. Created image: $image_file"