post

CP/M on the Pi! Ultibo baremetal app

EMUZ80 RPI is a CP/M emulator, by Ronald Daleske, for the Z80 processor the Raspberry PI (2). Here is the emulator without an operating system “bare metal” operated on the Raspberry PI. This particular application will start in about 5 Seconds.

This project shows, what is possible with the Lazaus/Free Pascal-Cross-Compiler from Ultibo.

The installation of Bare Metal programs on the Raspberry PI (2) is quite easy.
All you need is a blank SD card (or Micro-SD card for newer versions).
The SD card must formatted with the File System FAT or FAT32.
After then all files from the folder “boot” written directly to the SD card (inclusive the subfolders “CPM_LW_A” and “CPM_LW_B”).

cpm SCREEN_full

Here you find the project page, including all sources.

Clone a sdcard with Raspberry

Add a USB based card reader, insert the SD card you want to work on:

Use the script:

https://github.com/KoljaWindeler/pi-clone

Afterwards you can access the cloned SD card to make more alterations.

#!/bin/bash
 
PGM=`basename $0`
RSYNC_OPTIONS="--force -rltWDEgopt"
#-r recursive
#-l copy symlinks as symlinks
#-t preserve modification time
#-W copy whole files
#-D
#-E preserve file executability
#-g preserve group
#-o preserve owner
#-p preerve permission
#-t preserver times
 
 
# List of extra dirs to create under /mnt.
OPTIONAL_MNT_DIRS=""
 
# Where to mount the disk filesystems to be rsynced.
DEST_ROOT_PATH=/mnt/clone
SRC_ROOT_PATH=/mnt/source
 
CLONE_LOG=/var/log/$PGM.log
 
HOSTNAME=`hostname`
 
# e.g. mmcblk0->p<-1, we dont need that in sdb-><-1 ...
PARTITION_SPACER="p"
 
# check if we are root
if &#91; `id -u` != 0 &#93;
then
    echo -e "$PGM needs to be run as root.\n"
    exit 1
fi
 
# check if we have rsync installed
if ! rsync --version > /dev/null
then
        echo -e "\nOoops! $PGM needs the rsync program but cannot run it."
        echo "Make sure rsync is installed:"
        echo "    $ sudo apt-get update"
        echo -e "    $ sudo apt-get install rsync\n"
        exit 0
fi
 
if test -e /sbin/fsck.vfat
then
        HAVE_FSCK_VFAT="yes"
else
 
        echo "[Note] fsck.vfat was not found."
        echo "It is recommended to install dosfstools:"
        echo "    $ sudo apt-get update"
        echo "    $ sudo apt-get install dosfstools"
fi
 
usage()
        {
        echo ""
        echo "usage: $PGM sdN sdM {-f|--force-initialize} {-v|--verbose} {-y|--yes-to-all}"
        echo "    Example:  $PGM sda"
	echo "              to clone the current running system from /dev/mmcblk0"
        echo "    Example:  $PGM sda sdb "
	echo "              to restore the system from /dev/sda to /dev/sdb"
        echo "    -v - list all files as they are copied."
        echo "    -f - force initialize the destination partitions"
        echo "    -y - skip all questions"
        echo ""
        echo "    $PGM can run in two ways"
        echo "    1) $PGM sdN (without sdM) will cloning your current running system"
	echo "       to a SD card installed on sdN"
        echo "    2) $PGM sdN sdM will clone the system on disk sdN to the disk sdM"
        echo ""
        echo "    $PGM can clone the system to a new SD card or can"
        echo "    incrementally rsync to existing backup Raspberry/Banana Pi SD cards."
        echo ""
        echo "    If the destination SD card has an existing $SRC_BOOT_PARTITION_TYPE partition 1 and a"
        echo "    $SRC_ROOT_PARTITION_TYPE partition 2, $PGM assumes (unless using the -f option)"
        echo "    that the SD card is an existing backup with the partitions"
        echo "    properly sized and set up for a Raspberry/Banana Pi.  All that is needed"
        echo "    is to mount the partitions and rsync them to the source system."
        echo ""
        echo "    If these partitions are not found (or -f), then $PGM will ask"
        echo "    if it is OK to initialize the destination SD card partitions."
        echo "    This is done by a partial 'dd' from the source device /dev/mmcblk0"
        echo "    or /dev/sdN to the destination SD card followed by a"
        echo "    fdisk resize and mkfs.ext4 of partition 2."
        echo "    This creates a completed $SRC_BOOT_PARTITION_TYPE partition 1 containing all boot"
        echo "    files and an empty but properly sized partition 2 rootfs."
        echo "    The SD card  partitions are then mounted and rsynced to the"
        echo "    running system."
        echo ""
        echo "    The SD card destination partitions will be mounted on $DEST_ROOT_PATH."
        echo "    A log will be written to $CLONE_LOG."
        echo "    Avoid running other disk writing programs when running $PGM."
        echo ""
        exit 0
        }
 
VERBOSE=off
RESTORE_MODE=0
NO_REQUEST=false
 
while [ "$1" ]
do
        case "$1" in
                -v|--verbose)
                        VERBOSE=on
                        RSYNC_OPTIONS=${RSYNC_OPTIONS}v
                        ;;
                -f|--force-initialize)
                        FORCE_INITIALIZE=true
                        ;;
                -h|--help)
                        usage
                        ;;
                -y|--yes-to-all)
                        NO_REQUEST=true
                        ;;
                *)
                        if [ "$DST_DISK" != "" ]
                        then
                                if [ "$SRC_DISK" != "" ]
                                then
                                        echo "Bad args"
                                        usage
                                fi
                                SRC_DISK=$DST_DISK
                                RESTORE_MODE=1
                                PARTITION_SPACER=""
                        fi
                        DST_DISK=$1
                        ;;
        esac
        shift
done
 
if [ "$SRC_DISK" = "" ]
then
        SRC_DISK=mmcblk0
fi
 
SRC_BOOT_PARTITION_TYPE=`parted /dev/$SRC_DISK -ms p | grep "^1" | cut -f 5 -d:`
SRC_ROOT_PARTITION_TYPE=`parted /dev/$SRC_DISK -ms p | grep "^2" | cut -f 5 -d:`
 
if [ "$DST_DISK" = "" ]
then
        usage
        exit 0
fi
 
 
if ! cat /proc/partitions | grep -q $DST_DISK
then
        echo "Destination disk '$DST_DISK' does not exist."
        echo "Plug the destination SD card into a USB port."
        echo "If it does not show up  as '$DST_DISK', then do a"
        echo -e "'cat /proc/partitions' to see where it might be.\n"
        exit 0
fi
 
if [ "$RESTORE_MODE" = "1" ]
then
        if ! cat /proc/partitions | grep -q $SRC_DISK
        then
                echo "Source disk '$SRC_DISK' does not exist."
                echo "Plug the destination SD card into a USB port."
                echo "If it does not show up  as '$SRC_DISK', then do a"
                echo -e "'cat /proc/partitions' to see where it might be.\n"
                exit 0
        fi
fi
 
unmount_or_abort()
        {
        echo -n "Do you want to unmount $1? (yes/no): "
        if [ "$NO_REQUEST" = "true" ]
        then
         resp="y"
         echo "yes"
        else
         read resp
        fi
        if [ "$resp" = "y" ] || [ "$resp" = "yes" ]
        then
                if ! umount $1
                then
                        echo "Sorry, $PGM could not unmount $1."
                        echo -e "Aborting!\n"
                        exit 0
                fi
        else
                echo -e "Aborting!\n"
                exit 0
        fi
        }
 
DST_ROOT_PARTITION=/dev/${DST_DISK}2
DST_BOOT_PARTITION=/dev/${DST_DISK}1
 
SRC_ROOT_PARTITION=/dev/${SRC_DISK}${PARTITION_SPACER}2
SRC_BOOT_PARTITION=/dev/${SRC_DISK}${PARTITION_SPACER}1
 
# Check that none of the destination partitions are busy (mounted).
# src partitions can be mounted as we are just reading from them
#
DST_ROOT_CURMOUNT=`fgrep "$DST_ROOT_PARTITION " /etc/mtab | cut -f 2 -d ' ' `
DST_BOOT_CURMOUNT=`fgrep "$DST_BOOT_PARTITION " /etc/mtab | cut -f 2 -d ' ' `
 
if [ "$DST_ROOT_CURMOUNT" != "" ] || [ "$DST_BOOT_CURMOUNT" != "" ]
then
        echo "A destination partition is busy (mounted).  Mount status:"
        echo "    $DST_ROOT_PARTITION:  $DST_ROOT_CURMOUNT"
        echo "    $DST_BOOT_PARTITION:  $DST_BOOT_CURMOUNT"
        if [ "$DST_BOOT_CURMOUNT" != "" ]
        then
                unmount_or_abort $DST_BOOT_CURMOUNT
        fi
        if [ "$DST_ROOT_CURMOUNT" != "" ]
        then
                unmount_or_abort $DST_ROOT_CURMOUNT
        fi
fi
 
# check that no other drive is mounted on our mountpoint for destination
TEST_MOUNTED=`fgrep " $DEST_ROOT_PATH " /etc/mtab | cut -f 1 -d ' ' `
if [ "$TEST_MOUNTED" != "" ]
then
        echo "This script uses $DEST_ROOT_PATH for mounting filesystems, but"
        echo "$DEST_ROOT_PATH is already mounted with $TEST_MOUNTED."
        unmount_or_abort $DEST_ROOT_PATH
fi
 
# check that no other drive is mounted on our mountpoint for source
if [ "$RESTORE_MODE" = "1" ]
then
        TEST_MOUNTED=`fgrep " $SRC_ROOT_PATH/boot " /etc/mtab | cut -f 1 -d ' ' `
        if [ "$TEST_MOUNTED" != "" ]
        then
                echo "This script uses $SRC_ROOT_PATH/boot for mounting filesystems, but"
                echo "$SRC_ROOT_PATH/boot is already mounted with $TEST_MOUNTED."
                unmount_or_abort $SRC_ROOT_PATH"/boot"
        fi
 
        TEST_MOUNTED=`fgrep " $SRC_ROOT_PATH " /etc/mtab | cut -f 1 -d ' ' `
        if [ "$TEST_MOUNTED" != "" ]
        then
                echo "This script uses $SRC_ROOT_PATH for mounting filesystems, but"
                echo "$SRC_ROOT_PATH is already mounted with $TEST_MOUNTED."
                unmount_or_abort $SRC_ROOT_PATH
        fi
fi
 
# check that /mnt is not mounted on another drive
if [ ! -d $DEST_ROOT_PATH ]
then
        MNT_MOUNT=`fgrep " /mnt " /etc/mtab | cut -f 1 -d ' ' `
        if [ "$MNT_MOUNT" != "" ]
        then
                echo "$MNT_MOUNT is currently mounted on /mnt."
                unmount_or_abort /mnt
        fi
 
        mkdir $DEST_ROOT_PATH
fi
 
# ensure source mount dir is available
if [ "$RESTORE_MODE" = "1" ]
then
        if [ ! -d $SRC_ROOT_PATH ]
        then
                mkdir $SRC_ROOT_PATH
        fi
fi
 
 
 
 
# Borrowed from do_expand_rootfs in raspi-config
expand_rootfs()
        {
        # Get the starting offset of the root partition
        PART_START=$(parted /dev/$SRC_DISK -ms unit s p | grep "^2" | cut -f 2 -d:)
        [ "$PART_START" ] || return 1
        # Return value will likely be error for fdisk as it fails to reload the
        # partition table because the root fs is mounted
        fdisk /dev/$DST_DISK > /dev/null <<EOF
p
d
2
n
p
2
$PART_START
 
p
w
q
EOF
        }
 
 
# =========== Disk Setup and Checks ===========
#
# Check that destination partitions are the right type.
#
DST_BOOT_PARTITION_TYPE=`parted /dev/$DST_DISK -ms p \
                | grep "^1" | cut -f 5 -d:`
DST_ROOT_PARTITION_TYPE=`parted /dev/$DST_DISK -ms p \
                | grep "^2" | cut -f 5 -d:`
SRC_BOOT_PARTITION_SIZE=`parted /dev/$SRC_DISK -ms p \
                | grep "^1" | cut -f 3 -d:`
DST_BOOT_PARTITION_SIZE=`parted /dev/$DST_DISK -ms p \
                | grep "^1" | cut -f 3 -d:`

 
if &#91; "$DST_BOOT_PARTITION_TYPE" != "$SRC_BOOT_PARTITION_TYPE" &#93; || \
   &#91; "$DST_ROOT_PARTITION_TYPE" != "$SRC_ROOT_PARTITION_TYPE" &#93; || \
   &#91; "$SRC_BOOT_PARTITION_SIZE" != "$DST_BOOT_PARTITION_SIZE" &#93; || \
   &#91; "$FORCE_INITIALIZE" = "true" &#93;
then
        echo ""
        if &#91; "$FORCE_INITIALIZE" = "true" &#93;
        then
                echo "*** Forcing a partition initialization of destination '$DST_DISK' ***"
        fi
 
        echo "The existing partitions on destination disk '$DST_DISK' are:"
#       fdisk -l /dev/$DST_DISK | grep $DST_DISK
        parted /dev/$DST_DISK unit MB p \
                | sed "/^Model/d ; /^Sector/d"
        if &#91; "$DST_BOOT_PARTITION_TYPE" != "$SRC_BOOT_PARTITION_TYPE" &#93;
        then
                echo "  ... Cannot find a destination boot file system of type: $SRC_BOOT_PARTITION_TYPE"
                echo ""
        fi
        if &#91; "$DST_ROOT_PARTITION_TYPE" != "$SRC_ROOT_PARTITION_TYPE" &#93;
        then
                echo "  ... Cannot find a destination root file system of type: $SRC_ROOT_PARTITION_TYPE"
                echo ""
        fi
        if &#91; "$SRC_BOOT_PARTITION_SIZE" != "$DST_BOOT_PARTITION_SIZE" &#93;
        then
                echo " ... The boot partitions have different sizes." 
                echo "     Required $SRC_BOOT_PARTITION_SIZE vs $DST_BOOT_PARTITION_SIZE available on $DST_DISK"
                echo ""
        fi
        echo "This script can initialize the destination disk with a partition"
        echo "structure copied from the source filesytem and then resize"
        echo "partition 2 (the root filesystem) to use all space on the SD card."
        echo -n "Do you want to initialize the destination /dev/$DST_DISK? (yes/no): "
        if &#91; "$NO_REQUEST" = "true" &#93;
        then
         resp="y"
         echo "yes"
        else
         read resp
        fi
        if &#91; "$resp" = "y" &#93; || &#91; "$resp" = "yes" &#93;
        then
                # Image onto the destination disk a beginning fragment of the
                # running SD card file structure that spans at least more than
                # the start of partition 2.
                #
                # Calculate the start of partition 2 in MB for the dd.
                PART2_START=$(parted /dev/$SRC_DISK -ms unit MB p | grep "^2" \
                                | cut -f 2 -d: | sed s/MB// | tr "," "." | cut -f 1 -d.)
                # and add some slop
                DD_COUNT=`expr $PART2_START + 8`
 
                echo ""
                echo "Imaging the partition structure, copying $DD_COUNT megabytes..."
                sync
                dd if=/dev/$SRC_DISK of=/dev/$DST_DISK bs=1M count=$DD_COUNT
 
                # Partition was copied live so fsck to clean up for possible future
                # "Volume was not properly unmounted" warnings.
                if &#91; "$HAVE_FSCK_VFAT" = "yes" &#93;
                then
                        echo "Running fsck on $DST_BOOT_PARTITION..."
                        fsck -p $DST_BOOT_PARTITION &> /dev/null
                fi
 
                # But, though Partion 1 is now imaged, partition 2 is incomplete and
                # maybe the wrong size for the destination SD card.  So fdisk it to
                # make it fill the rest of the disk and mkfs it to clean it out.
                #
                echo "Sizing partition 2 (root partition) to use all SD card space..."
                expand_rootfs
                mkfs.ext4 $DST_ROOT_PARTITION > /dev/null
 
                echo ""
                echo "/dev/$DST_DISK is initialized and resized.  Its partitions are:"
#               fdisk -l /dev/$DST_DISK | grep $DST_DISK
                parted /dev/$DST_DISK unit MB p \
                        | sed "/^Model/d ; /^Sector/d"
 
                SRC_ROOT_VOL_NAME=`e2label /dev/${SRC_DISK}${PARTITION_SPACER}2`
 
                echo ""
                echo "Your booted /dev/${SRC_DISK}${PARTITION_SPACER}2 rootfs existing label: $SRC_ROOT_VOL_NAME"
                echo -n "You may enter a label for the destination rootfs $DST_ROOT_PARTITION: "
                if [ "$NO_REQUEST" = "true" ]
                then
                 resp=""
                 echo "skipped"
                else
                 read resp
                fi
                if [ "$resp" != "" ]
                then
                        e2label $DST_ROOT_PARTITION $resp
                fi
        else
                echo -e "Aborting\n"
                exit 0
        fi
fi
 
 
# =========== Setup Summary ===========
#
DST_ROOT_VOL_NAME=`e2label $DST_ROOT_PARTITION`
SRC_ROOT_VOL_NAME=`e2label $SRC_ROOT_PARTITION`
 
 
if [ "$DST_ROOT_VOL_NAME" = "" ]
then
        DST_ROOT_VOL_NAME="no label"
fi
 
if [ "$SRC_ROOT_VOL_NAME" = "" ]
then
        SRC_ROOT_VOL_NAME="no label"
fi
 
 
echo ""
if [ "$RESTORE_MODE" = "1" ]
then
        echo "Restore mode             :  yes"
        echo "Source disk              :  $SRC_DISK"
        echo "Source bootfs            :  $SRC_BOOT_PARTITION on ${SRC_ROOT_PATH}/boot"
        echo "Source rootfs            :  $SRC_ROOT_PARTITION ($SRC_ROOT_VOL_NAME) on ${SRC_ROOT_PATH}"
else
        echo "Restore mode             :  no"
fi
echo "Clone destination disk   :  $DST_DISK"
echo "Clone destination bootfs :  $DST_BOOT_PARTITION on ${DEST_ROOT_PATH}/boot"
echo "Clone destination rootfs :  $DST_ROOT_PARTITION ($DST_ROOT_VOL_NAME) on ${DEST_ROOT_PATH}"
echo "Verbose mode             :  $VERBOSE"
 
echo "==============================="
 
 
# If this is an SD card initialization, can watch progress of the clone
# in another terminal with:  watch df -h
#
echo -n "Final check, is it Ok to proceed with the clone (yes/no)?: "
if [ "$NO_REQUEST" = "true" ]
then
 resp="y"
 echo "yes"
else
 read resp
fi
if [ "$resp" != "y" ] && [ "$resp" != "yes" ]
then
        echo -e "Aborting the disk clone.\n"
        exit 0
fi
 
#
# =========== End of Setup  ===========
 
# mount the root filesystem if we are using the restore mode
if [ "$RESTORE_MODE" = "1" ]
then
        echo "=> Mounting /dev/${SRC_DISK}${PARTITION_SPACER}2 ($SRC_ROOT_VOL_NAME) on ${SRC_ROOT_PATH}"
 
        if ! mount /dev/${SRC_DISK}${PARTITION_SPACER}2 ${SRC_ROOT_PATH}
        then
                echo -e "Mount failure on ${SRC_ROOT_PATH}, aborting!\n"
                exit 0
        fi
fi
 
# ensure that the boot partition is mounted before running rsync
SRC_BOOT_PATH="/boot"
if [ "$RESTORE_MODE" = "1" ]
then
        SRC_BOOT_PATH="${SRC_ROOT_PATH}/boot"
        if [ ! -d ${BOOT_PATH} ]
        then
                mkdir ${BOOT_PATH}
        fi
fi
 
BOOT_MOUNT=`fgrep " ${SRC_BOOT_PATH} " /etc/mtab | cut -f 1 -d ' ' `
if [ "$BOOT_MOUNT" = "" ]
        then
        echo "=> Mounting /dev/${SRC_DISK}${PARTITION_SPACER}1 on ${SRC_BOOT_PATH}"
        if [ ! -d ${SRC_BOOT_PATH} ]
        then
                mkdir -p ${SRC_BOOT_PATH}
        fi
 
        if ! mount /dev/${SRC_DISK}${PARTITION_SPACER}1 ${SRC_BOOT_PATH}
        then
                echo -e "Mount failure on ${SRC_BOOT_PATH}, aborting!\n"
                exit 0
        fi
fi
 
# Mount destination filesystems.
echo "=> Mounting $DST_ROOT_PARTITION ($DST_ROOT_VOL_NAME) on $DEST_ROOT_PATH"
if ! mount $DST_ROOT_PARTITION $DEST_ROOT_PATH
then
        echo -e "Mount failure of $DST_ROOT_PARTITION, aborting!\n"
        exit 0
fi
 
if [ ! -d $DEST_ROOT_PATH/boot ]
then
        mkdir -p $DEST_ROOT_PATH/boot
fi
 
echo "=> Mounting $DST_BOOT_PARTITION on $DEST_ROOT_PATH/boot"
if ! mount $DST_BOOT_PARTITION $DEST_ROOT_PATH/boot
then
        umount $DEST_ROOT_PATH
        echo -e "Mount failure of $DST_BOOT_PARTITION, aborting!\n"
        exit 0
fi
 
echo "==============================="
 
 
 
 
START_TIME=`date '+%H:%M:%S'`
 
# Exclude fuse mountpoint .gvfs, various other mount points, and tmpfs
# file systems from the rsync.
#
sync
 
RSYNC_SRC_PATH="/"
if [ "$RESTORE_MODE" = "1" ]
then
        RSYNC_SRC_PATH="${SRC_ROOT_PATH}/"
fi
 
echo "Starting the filesystem rsync ${RSYNC_SRC_PATH} to $DEST_ROOT_PATH"
echo -n "(This may take several minutes)..."
 
rsync $RSYNC_OPTIONS --delete \
                --exclude '.gvfs' \
                --exclude ${RSYNC_SRC_PATH}'dev' \
                --exclude ${RSYNC_SRC_PATH}'media' \
                --exclude ${RSYNC_SRC_PATH}'mnt' \
                --exclude ${RSYNC_SRC_PATH}'proc' \
                --exclude ${RSYNC_SRC_PATH}'run' \
                --exclude ${RSYNC_SRC_PATH}'sys' \
                --exclude ${RSYNC_SRC_PATH}'tmp' \
                --exclude ${RSYNC_SRC_PATH}'lost\+found' \
        $RSYNC_SRC_PATH \
        $DEST_ROOT_PATH
 
 
# Fixup some stuff
#
 
for i in dev media mnt proc run sys
do
        if [ ! -d $DEST_ROOT_PATH/$i ]
        then
                mkdir $DEST_ROOT_PATH/$i
        fi
done
 
if [ ! -d $DEST_ROOT_PATH/tmp ]
then
        mkdir $DEST_ROOT_PATH/tmp
        chmod a+w $DEST_ROOT_PATH/tmp
fi
 
# Some extra optional dirs I create under /mnt
for i in $OPTIONAL_MNT_DIRS
do
        if [ ! -d $DEST_ROOT_PATH/mnt/$i ]
        then
                mkdir $DEST_ROOT_PATH/mnt/$i
        fi
done
 
 
#rm -f $DEST_ROOT_PATH/etc/udev/rules.d/70-persistent-net.rules
 
 
DATE=`date '+%F %H:%M'`
 
echo "$DATE  $HOSTNAME $PGM : clone to $DST_DISK ($DST_ROOT_VOL_NAME)" \
                >> $CLONE_LOG
echo "$DATE  $HOSTNAME $PGM : clone to $DST_DISK ($DST_ROOT_VOL_NAME)" \
                >> $DEST_ROOT_PATH/$CLONE_LOG
 
 
STOP_TIME=`date '+%H:%M:%S'`
 
echo ""
echo "*** Done with clone to /dev/$DST_DISK ***"
echo "    Started: $START_TIME    Finished: $STOP_TIME"
echo ""
 
# Pause before unmounting in case I want to inspect the clone results
# or need to custom modify any files on the destination SD clone.
# Eg. modify $DEST_ROOT_PATH/etc/hostname, $DEST_ROOT_PATH/etc/network/interfaces, etc
# if I'm cloning into a card to be installed on another Pi.
#
echo -n "Hit Enter when ready to unmount the used partitions..."
if [ "$NO_REQUEST" = "true" ]
then
 echo "skipped"
else
 read resp
fi
 
echo "unmounting $DEST_ROOT_PATH/boot"
umount $DEST_ROOT_PATH/boot
 
echo "unmounting $DEST_ROOT_PATH"
umount $DEST_ROOT_PATH
 
if [ "$RESTORE_MODE" = "1" ]
then
        echo "unmounting $SRC_ROOT_PATH/boot"
        umount $SRC_ROOT_PATH/boot
 
        echo "unmounting $SRC_ROOT_PATH"
        umount $SRC_ROOT_PATH
fi
 
echo "==============================="
 
exit 0

Contact

Your Name (required)

Your Email (required)

Subject

Your Message

captcha

Enter the Above Text