#!/bin/bash
# write part to floppy

# WARNING: reading this code may make you paranoid!

#sleep time for myklog to catch up printing if running on a
#virtual console.  If we don't wait for it the screen gets messy.
if [ $virtcons = y ]; then
 vc1=0
else
 vc1=1
fi

#checks for 
#     floppy I/O error
#in the kernel message log.
function cfk ()
{
if grep "floppy I/O error" kernmeslog >/dev/null; then
 printf "\007"; sleep 1;printf "\007"; sleep 1
 echo "**ERROR** : The kernel reports floppy errors:"
 gawk '{ if(v ~ "floppy I/O error") print "  ",v,$0; v=$0 }' \
       kernmeslog |tail -4 
 printf "" >kernmeslog
 return 0
fi

if grep "<myklog>Some kernel messages are lost." kernmeslog >/dev/null; then
 printf "\007"; sleep 1;printf "\007"; sleep 1
 echo "**WARNING** : Something is producing kernel messages so fast that"
 echo "              some of them could not be captured."
 echo "              There may have been a floppy error that was not noticed."
 printf "" >kernmeslog
 if ! question "Ignore this warning"; then 
  return 0
 fi
 echo "Warning ignored."
fi

return 1
}

#normal fdformat fails on verify with extended densities.
function myfdformat ()
{
#if nothing special, use std fdformat.
 if [ $mdens != xd -a $mdens != xh ]; then
  if ! fdformat $1; then return 1; else return 0; fi
 fi

 if ! fdformat -n $1; then return 1; else
   echo -n "Verify.."
#a setfdprm is missing from the standard fdformat.
   eval $setfdprm
   fdflush $mdev
#checking if the contents are actually the fill byte should not be necessary
#as the CRC check will catch virtually all errors anyway.
   if ! dd if=$mdev of=/dev/null bs=1024 count=$disksizek 2>/dev/null; then
    echo 
    echo "Verify failed."
    return 1
   else
    echo
   fi
 fi

 return 0
}

if [ $formatalways = y ]; then
 echo "--Insert a blank, unformatted disk for $it" 
else
 echo "--Insert an empty, formatted disk for $it"
fi
enter -f
printf "  in drive $mnr and press enter. (Type o for options.)\007 "

while true; do
 read
 if [ "$REPLY" = "" ]; then err=no; break; fi
 if [ "$REPLY" = "o" ]; then err=yes; break; fi
 printf "-->  "
done

beep=no

while true; do
#attempt to write part loop
#at this point, an empty disk is in the drive.

#this if handles user interaction if an error occures.
if [ $err != no ]; then

 echo
 echo " Enter one of the following commands:"
 echo "                           (You may want to insert a new disk first.)"
 if [ $formatalways = n ]; then
  echo " r  : retry writing $it to drive $mnr"
  echo " f  : do a low-level format on the disk in drive $mnr"
  echo " fn : do a low-level format without verify on the disk in drive $mnr"
 else
  echo " r  : retry format and writing $it to drive $mnr"
 fi
 if [ $prepnr = $[$nr-1] -a $nr != 1 ]; then
  echo " p  : write the previous part (number $[$nr-1]) again"
 fi
 echo " c  : change format/verify options"
 echo " q! : quit trying to write this part, continue with the next part"
 if [ $err = part ]; then 
 echo " o! : overwrite existing contents, use this disk for $it"
 fi
# echo " e  : escape to shell, exit with exit. (DEBUG CODE)"
 if [ $beep = yes ]; then printf "\007"; sleep 1;printf "\007"; fi
 beep=yes

 enter -f
 REPLY=""
 while [ "$REPLY" = "" ]; do printf "-->"; read; done;
 
   if [ "$REPLY" = r ]; then
    echo;
 elif [ "$REPLY" = f -a $formatalways = n ]; then 
    if ! myfdformat $mdev; then
      echo
#the sleep is for myklog to catch up printing if running on a
#virtual console.
      sleep $vc1
      echo "**ERROR**: fdformat failed."
    else beep=no; echo "Format successful."
         echo "(You may now want to type \`r'.)"
    fi
    continue
 elif [ "$REPLY" = fn -a $formatalways = n ]; then 
    if ! fdformat -n $mdev; then
      echo
      sleep $vc1
      echo "**ERROR**: fdformat failed."
      echo " Note: this may be a bug in fdformat, on my machine with my kernel"
      echo " fdformat -n always signals failure, even if everything seems OK."
    else beep=no; echo "Format successful."
    fi
    echo "(You may now want to type \`r'.)"
    continue
  elif  [ "$REPLY" = p -a $prepnr = $[$nr-1] -a $nr != 1 ]; then
    prevpart=y
    echo
    echo "Going back to previous part."
    echo
    break
 elif [ "$REPLY" = c ]; then
#get format&verify options.
    printf "Always format inserted disks?"
    getpar formatalways n yn
    if [ $formatalways = y ]; then
     printf "Verify format?"
     getpar verifyformat y yn
     echo "Check if disk is already formatted (with the right density)"
     printf "before formatting?"
     getpar checkformatted n yn
    fi
    printf "Verify after write to disk?"
    getpar verifywrite n yn
    beep=no
    continue;
 elif [ "$REPLY" = "q!" ]; then
    echo "Without this part the archive can only be partially restored."
    if question "Really give up writing $it"; then 
       echo "Attempt to write $it to disk aborted."
       echo
#prepare part if not already done.
       if [ $prepnr != $nr ]; then
          source floppywrmakep
       fi
       break
    fi
    beep=no
    continue; 
 elif [ "$REPLY" = "o!" -a $err = part ]; then 
    if ! mformat $mdisk; then 
      echo
      echo "**ERROR**: mformat failed."
      continue; 
    fi
# elif [ "$REPLY" = "e" ]; then 
#      bash
#      continue; 
 else echo "Invalid command, try again."; beep=no; continue;
 fi

fi
#end of handle user interaction on error.
 
beep=yes
err=yes


#######
#write a part



##########
# format if needed

#empty kernel message log
printf "" >kernmeslog

#echo "next format check";enter

#set the floppy parameters for xdens formats.
eval $setfdprm
#flush to let them take effect
fdflush $mdev


if [ $formatalways = y ]; then
# format disk

 if [ $checkformatted = y ]; then
  echo
  echo "Checking if disk is already formatted, please disregard the"
  echo "floppy errors below......"
  if dd bs=1 count=9 if=$mdev of=dhead 2>/dev/null; then
   echo
   echo "**ERROR**: this disk is already formatted with the correct density!"
   if ! question "Format anyway"; then
     continue
   fi
  fi
  sleep 1
  echo
 fi

 echo "Formatting drive $mnr......"

 echo "frommel" >dhead
 if [ $verifyformat = y ]; then
   if ! myfdformat $mdev; then
     echo
     sleep $vc1
     echo "**ERROR**: fdformat failed."
     continue
   fi
 else  
   if ! fdformat -n $mdev; then
     echo
     echo " fdformat failed."
     echo " Note: this may be a bug in fdformat, on my machine with my kernel"
     echo " fdformat -n always signals failure, even if everything seems OK."
   fi
 fi

else
#do not format disk

 if ! dd bs=1 count=9 if=$mdev of=dhead 2>/dev/null; then 
#1st sector is not formatted in the right way
  echo
  sleep $vc1
  echo "**ERROR**: no disk inserted, disk is not formatted, or disk is not"
  echo "           formatted with the right density."
  continue
 fi

fi

printf "" >kernmeslog

##################
#already part of this backup set?

if [ "`tail -c6 dhead`" = Mtools ]; then
#disk is formatted by mtools
rm diskdesc 2>/dev/null
mcopy $mdisk\descr2k diskdesc &>/dev/null
 if [ -e diskdesc ]; then 
  if cmp -s descr2k diskdesc; then 
#descr2k on disk is equal to current desc.
   echo
   echo "**ERROR**: This disk contains a part of the current backup."
   echo "Contents of the disk:  (only up to 7 files are listed)"
   mdir $mdisk |head -10
   err=part
   continue
  fi
 fi
fi

if cfk ; then continue; fi

#now make the part if not already prepared.
 if [ $prepnr != $nr ]; then
   source floppywrmakep
 fi

##########
#now we write the disk image.

echo "Writing $it to drive $mnr (i interrupts)......"

if ! mycp /tmp/tbup/bulk/floppy $mdev;
then
   sleep $vc1
   echo "**ERROR**: Writing of $it failed."
   mdel $mdisk\descr2k
   sleep $vc1
   continue
fi


#check if we already have some write error reports.
if cfk ; then 
#delete the descr file to prevent confusing messages on retry
 mdel $mdisk\descr2k
 sleep $vc1
 continue
fi

#Empty floppy cache. Needed for verify, and also for the next dd to have
#the desired effect if there is lots of ram.
eval $setfdprm
fdflush $mdev

#There are still some pending writes in the floppy r/w request queue after
#cp has exited.
#These could generate write errors that are not noticed if we go right on, so
#we first do a read on the first sector, and hope that the elevator
#algorithm schedules it after the pending writes.
#When dd exits, we can thus reasonably assume that all writes were performed,
#giving errors or not.

if ! dd bs=1 count=9 if=$mdev of=/dev/null 2>/dev/null; then 
#1st sector is now unreadable? mega-weirdness!
  echo
  sleep $vc1
  echo "**ERROR**: First sector of the floppy is unreadable, write failed."
  mdel $mdisk\descr2k
  sleep $vc1
  continue
fi

#Wait 2 more seconds for the kernel logger to get possible errors, but
#not if we are going to verify, because that should catch the errors anyway.
if [ $verifywrite = n ]; then
 sleep 2
fi

#this is the real test for floppy write errors reported by the kernel.
if cfk ; then 
#delete the descr file to prevent confusing messages on retry
 mdel $mdisk\descr2k
 sleep $vc1
 continue
fi


###########
#verify if needed.
  
if [ $verifywrite = y ]; then

echo "Verify....."

 if ! cmp $mdev /tmp/tbup/bulk/floppy; then
   echo
   sleep $vc1
   echo "**ERROR**: verify of $it failed."
   mdel $mdisk\descr2k
   sleep $vc1
   continue
 fi

#not really necessary, read errors are reported to reading process.
 if cfk ; then 
  mdel $mdisk\descr2k
  sleep $vc1
  continue
 fi


fi

echo "Finished writing $it."
echo

break

done
