#!/bin/bash
#(c) Copyright Barry Kauler, October 2017. License: GPL v3 (/usr/share/doc/legal)
#gui for 'dd' utility.
#optional cli mode: source-file target-drive
#171004 first release.
#171008 cli mode, do not use any X apps, run dd in same terminal.
#171009 MODE variable =gui =cli =dlg (latter uses dialog, NOT YET IMPLEMENTED)
#171205 change text "EasyOS" to "Linux"
#180408 support nvme drives.
#180718 support .zip zipped files.
#181220 bug fix.
#190827 basic bit-flipping test to verify write, plus verify normal write. 190828 fixes.
#191224 remove bit-flipping test, keep verify-write.
#200215 support write iso file to uab-stick. use isolyzer if exist.
#200521 GuillaumeD reported issue with non-english.
#200522 nvme doesn't have /sys/block/$ONEDRV/device/vendor

export TEXTDOMAIN=easydd
export OUTPUT_CHARSET=UTF-8

MODE='gui'
ERRTITLE="$(gettext 'ERROR')"
err_exit() {
 case $MODE in
  gui) ${MSGEXE} -wrap -bg '#ffa0a0' -title "EasyDD: ${ERRTITLE}" "$@" ;;
  dlg) dialog --cr-wrap --colors --title "${ERRTITLE}" --msgbox "\Z1${@}\Zn" 0 0 ;;
  *)   echo -e "\\033[1;31m${ERRTITLE}: ${@}\\033[0;39m" ;; #red
 esac
 exit 1
}

#import 'probedisk' code into here...
probedisk_func() {
 ALLDRVS="$(ls -1 /sys/block | grep -E '^sd|^mmcblk[0-9]$|^nvme' | tr '\n' ' ')" #180408
 for ONEDRV in $ALLDRVS
 do
  case $ONEDRV in
   sd*|nvme*) #180408 nvme quick hack, needs improving.
    MEDIA="ata"
    [ "$(readlink /sys/block/${ONEDRV} | grep '/usb[0-9]')" != "" ] && MEDIA="usb"
    VENDOR="$(cat /sys/block/$ONEDRV/device/vendor 2>/dev/null | tr -s ' ')" #200522 nvme doesnt have this.
    MODEL="$(cat /sys/block/$ONEDRV/device/model | tr -s ' ')"
    INFO="${VENDOR}${MODEL}"
   ;;
   mmc*) #/dev/mmcblk0
    MEDIA="card"
    INFO="MMC/SD: $(cat /sys/block/$ONEDRV/device/name)"
   ;;
  esac
  echo "/dev/$ONEDRV|$MEDIA|$INFO"
 done
}

FILESOURCE=''; DRVTARGET=''
if [ $1 ];then
 if [ -f "$1" ];then
  FILESOURCE="$1"
  MODE='cli'
  if [ ! $2 ];then
   #err_exit "Target drive not specified"
   DRVTARGET='ask'
  else
   DRVTARGET="${2/*\//}" #dump /dev/ if exists
   DRVVERIFY="$(ls -1 /sys/block | grep "^${DRVTARGET}$")"
   [ ! "$DRVVERIFY" ] && echo -e "\\033[1;31m$(gettext 'This drive does not exist:')
${DRVTARGET}
$(gettext 'Specify an existing drive, and not a partition')\\033[0;39m" #red
   exit
  fi
 else
  case "$1" in
   -d|--d*)
    MODE='dlg'
    E1a="$(gettext 'dialog mode not currently supported')"
    echo -e "\\033[1;31m${E1a}\\033[0;39m" #31=red
    exit
   ;;
   *)
    echo "EasyDD is a GUI frontend for the 'dd' utility, for writing an image to a drive.
easydd                No parameters, runs in full X GUI mode.
NOT CURRENTLY SUPPORTED easydd -d Runs in textmode GUI, using 'dialog' utility.
easydd <file>         CLI mode, source-file, will ask for target-drive.
easydd <file> <drive> CLI mode, source-file and target-drive parameters.
                      Source file must be format *.img[.gz|.bzip2|.xz|.zip] or *.iso
                      Target must be an entire drive, not a partition. ex: sda
easydd -h             Displays this help message.
                      --dialog, --help  Long parameters supported."
    exit
   ;;
  esac
 fi
fi
[ "$MODE" == "gui" ] && [ ! $DISPLAY ] && exit

ERR=''; RXVTEXE=''; MSGEXE=''
if ! which dd >/dev/null ;then ERR="${ERR} dd"; fi
if ! which gunzip >/dev/null ;then ERR="${ERR} gunzip"; fi
if ! which sha512sum >/dev/null ;then ERR="${ERR} sha512sum"; fi
if ! which cmp >/dev/null ;then ERR="${ERR} cmp"; fi
if [ "$MODE" == "gui" ];then
 if which rxvt >/dev/null ;then RXVTEXE='rxvt' ; fi
 if [ ! "$RXVTEXE" ];then
  if which urxvt >/dev/null ;then RXVTEXE='urxvt' ; fi
 fi
 if which pupmessage >/dev/null ;then MSGEXE='pupmessage'; fi
 if [ ! "$MSGEXE" ];then #181220
  if which gxmessage >/dev/null ;then MSGEXE='gxmessage'; fi
 fi
 if [ ! "$MSGEXE" ];then
  if which xmessage; then xmessage "$(gettext "Need 'pupmessage' or 'gxmessage' utilities")" ; fi
  exit
 fi
 if ! which gtkdialog >/dev/null ;then ERR="${ERR} gtkdialog"; fi
 if ! which pupdialog >/dev/null ;then ERR="${ERR} pupdialog"; fi
 [ ! "$RXVTEXE" ] && ERR="${ERR} urxvt"
fi
if [ "$MODE" == "dlg" ];then
 if ! which dialog >/dev/null ;then ERR="${ERR} dialog"; fi
fi
if [ "$ERR" ];then
 err_exit "$(gettext 'These utilities are missing:')
${ERR}"
fi
#the full dd is required... 200521 prefix "LANG=C"...
DDTEST="$(LANG=C dd --help | grep 'periodic transfer statistics')"
[ ! "$DDTEST" ] && err_exit "$(gettext "dd utility does not support 'status=progress' cli option")"

INTERFACE="$(gettext 'Interface:')"
DESCRIPTION="$(gettext 'Description:')"
if [ "$DRVTARGET" == "ask" ];then #MODE=cli only
 echo -e "\\033[1;35m" #35=purple
 echo "$(gettext 'Please plugin the drive that you want to write to, if not already.')"
 echo "$(gettext 'DO IT RIGHT NOW, before hitting ENTER key.')"
 echo -e "\\033[0;39m"
 echo -n "$(gettext 'Then, press ENTER key to continue:') "
 read keepgoing
 echo
 echo "$(gettext 'You need to choose which drive to write to.')"
 echo "$(gettext 'Here is information about the drives:')"
 echo
 acnt=1
 echo -n '' > /tmp/easydd-drvs
 while read aline
 do
  echo -e "\\033[1;35m${acnt}\\033[0;39m ${aline}" #35=purple
  echo "$aline" >> /tmp/easydd-drvs
  acnt=`expr $acnt + 1`
 done <<_EOF
$(probedisk_func | cut -f 3- -d '/' | sed -e "s%|% (${INTERFACE} %" | sed -e "s%|% ${DESCRIPTION} %" | sed -e 's%$%)%')
_EOF
 echo
 echo -n "$(gettext 'Type a number from left column: ')"
 read anumber
 DRVTARGET="$(head -n ${anumber} /tmp/easydd-drvs | tail -n 1 | cut -f 1 -d ' ')"
 echo "$(gettext 'Chosen drive:') ${DRVTARGET}"
fi

D1b="$(gettext 'Continue')"
D1c="$(gettext 'Cancel')"
D1d="$(gettext 'This first version of EasyDD will write an image file to a drive.')"
D1e="$(gettext 'Please plugin the target drive right now, if not already.')"
D1f="$(gettext "Then, click the 'Continue' button...")"
D1g="$(gettext '(Note, there will be further sanity checks before writing to the drive)')"
while [ ! "$DRVTARGET" ];do ###start gui-1###
 
 pupdialog --background '#ffff80' --backtitle "EasyDD" --yes-label "${D1b}" --no-label "${D1c}" --colors --yesno "${D1d}
\Zb${D1e}\ZB
${D1f}

${D1g}" 0 0
 [ $? -ne 0 ] && exit
 sleep 0.5
 
 DISKS="$(probedisk_func | cut -f 3- -d '/' | sed -e "s%|% (${INTERFACE} %" | sed -e "s%|% ${DESCRIPTION} %" | sed -e 's%$%)%')"
 CNT=1; RADIOXML=""
 while read adisk
 do
  adev="$(echo -n "$adisk" | cut -f 1 -d ' ')" #ex: sda
  RADIOXML="${RADIOXML}
 <radiobutton><variable>DISK_${adev}</variable><label>${adisk}</label></radiobutton>"
  CNT=`expr $CNT + 1`
 done <<_EOF
$(echo "$DISKS")
_EOF

 [ ! "$RADIOXML" ] && err_exit "$(gettext 'Cannot find any drives')"

 export EASYDD_DLG1="
<window title=\"EasyDD $(gettext 'frontend for dd')\" icon-name=\"gtk-harddisk\">
 <vbox>
  <text use-markup=\"true\">
   <label>\"<b>$(gettext 'Simple GUI for dd')</b>\"</label>
  </text>
  <text><label>$(gettext 'This first version has only one purpose, to write an image file to an entire drive.')</label></text>
  <text use-markup=\"true\"><label>\"$(gettext 'An example would be a downloaded release of EasyOS, with a name like:')
<b>easy-0.6-amd64.img.gz</b>\"</label></text>

  <frame $(gettext 'Source')>
   <text><label>$(gettext 'Choose the image file:')</label></text>
   <hbox>
    <entry accept=\"savefilename\">
     <variable>FILESOURCE</variable>
    </entry>
    <button>
     <input file stock=\"gtk-open\"></input>
     <variable>FILE_BROWSE_SAVEFILENAME</variable>
     <action function=\"fileselect\">FILESOURCE</action>
    </button>
   </hbox>
  </frame>
  
  <frame $(gettext 'Destination')>
   <text><label>$(gettext 'Choose the target drive:')</label></text>
   ${RADIOXML}
  </frame>
  <hbox>
   <button><label>$(gettext 'Go back to previous window')</label><action>exit:goback</action></button>
   <button cancel></button>
   <button ok></button>
  </hbox>
 </vbox>
</window>"

 RETVARS="`gtkdialog --program=EASYDD_DLG1 --center`"
 [ $? -ne 0 ] && exit
 eval "$RETVARS"

 #echo "$RETVARS" #TEST
 if [ "$EXIT" == "goback" ];then
  DRVTARGET=''
  continue
 fi
 [ "$EXIT" != "OK" ] && exit

 DRVTARGET="$(echo "$RETVARS" | grep '^DISK_' | grep '"true"' | cut -f 2 -d '_' | cut -f 1 -d '=')"
 break
done ###end gui-1###

if [ "$MODE" == "dlg" ];then
 Dmain="${D1d}
\Zb${D1e}\ZB
${D1f}

${D1g}"
 dialog --cr-wrap --colors --no-label "${D1c}" --yes-label "${D1b}" --title "EasyDD" --yesno "${Dmain}" 0 0
 
fi

#check source
if [ "$(echo -n "$FILESOURCE" | grep -E '\.img\.gz$|\.img\.xz$|\.img\.bzip2$|\.img$|\.img\.zip$|\.iso$')" == "" ];then
 err_exit "For sanity-check, the source filename must end in '.img', '.img.gz', 'img.xz', '.img.bzip2', '.img.zip' or '.iso'"
fi

#check dest
MNTD="$(grep "^/dev/$DRVTARGET" /proc/mounts | cut -f 1 -d ' ')"
for amntd in $MNTD
do
 sync
 umount $amntd
done
MNTD="$(grep "^/dev/$DRVTARGET" /proc/mounts | cut -f 1 -d ' ')"
if [ "$MNTD" ];then
 err_exit "$(gettext 'A partition in target drive cannot be unmounted:')
${MNTD}"
fi

M2b="$(gettext 'Ready to write!')"
M2c="$(gettext 'Source file:')"
M2d="$(gettext 'Target drive:')"
M2e="$(gettext 'Check very carefully that target drive is correct, as it will be entirely rewritten, and all pre-existing partitions wiped. Only click the OK button if you know what you are doing!')"
M2ex="$(gettext 'Check very carefully that target drive is correct, as it will be entirely rewritten, and all pre-existing partitions wiped. Only press ENTER if you know what you are doing!')"
M2f="$(gettext 'This will be an opportunity to observe the write-speed of your drive. Some cheap USB-sticks are extremely slow, and will give a very poor experience when running Linux. If the write speed is less than 7MB/sec, it is recommended that you use a faster drive.')"
#M2g="$(gettext 'NOTE: due to internal caching, the drive-speed may be faster initially, toward the end of the write you will see its true write-speed.')"
export EASYDD_DLG2="
<window title=\"EasyDD $(gettext 'frontend for dd')\" icon-name=\"gtk-harddisk\">
 <vbox>
  <text use-markup=\"true\"><label>\"<b>${M2b}</b>\"</label></text>
  
  <text use-markup=\"true\"><label>\"${M2c}
<b>${FILESOURCE}</b>
${M2d}
<b>${DRVTARGET}</b>\"</label></text>
  
  <text use-markup=\"true\"><label>\"<span fgcolor='red'>${M2e}</span>\"</label></text>

  <hbox>
   <button cancel></button>
   <button ok></button>
  </hbox>
 </vbox>
</window>"

if [ "$MODE" == "gui" ];then
 #echo "$EASYDD_DLG2" #TEST
 RETVARS="`gtkdialog --program=EASYDD_DLG2 --center`"
 [ $? -ne 0 ] && exit
 eval "$RETVARS"
 [ "$EXIT" != "OK" ] && exit
fi
if [ "$MODE" == "cli" ];then
 echo -e "\\033[1;35m" #35=purple
 echo "${M2b}"
 echo "${M2c}  ${FILESOURCE}"
 echo "${M2d} ${DRVTARGET}"
 echo -e "\\033[0;39m"
 echo -e "\\033[1;31m${M2ex}\\033[0;39m" #31=red
 echo
 echo -n "$(gettext 'Press ENTER to continue, CTRL-C to quit:') "
 read willigoon
 [ "$willigoon" != "" ] && exit
fi

EXEC=''; MSGID=''
EXT="${FILESOURCE/*./}"
W1b="$(gettext 'Please wait, testing integrity of file...')"
case $MODE in
 gui)
  ${MSGEXE} -bg '#fabc30' "${W1b}" &
  MSGID="$!"
 ;;
 *) echo -e "\n${W1b}" ;;
esac
case "$EXT" in
 gz)
  if ! which gunzip >/dev/null ;then err_exit "$(gettext 'Utility gunzip does not exist')"; fi
  EXEC="gunzip --stdout"
  gunzip --test $FILESOURCE > /dev/null 2>&1
  [ $? -ne 0 ] && err_exit "$(gettext 'Source file appears to be corrupted:')
${FILESOURCE}"
 ;;
 bzip2|bz2) #190827 added bz2
  if ! which bunzip2 >/dev/null ;then err_exit "$(gettext 'Uility bunzip2 does not exist')"; fi
  EXEC="bunzip2 --stdout"
  bunzip2 --test $FILESOURCE > /dev/null 2>&1
  [ $? -ne 0 ] && err_exit "$(gettext 'Source file appears to be corrupted:')
${FILESOURCE}"
 ;;
 xz)
  if ! which unxz >/dev/null ;then err_exit "$(gettext 'Utility unxz does not exist')"; fi
  EXEC="unxz --stdout"
  unxz --test $FILESOURCE > /dev/null 2>&1
  [ $? -ne 0 ] && err_exit "$(gettext 'Source file appears to be corrupted:')
${FILESOURCE}"
 ;;
 img)
  EXEC=''
 ;;
 zip)
  if ! which unzip >/dev/null ;then err_exit "$(gettext 'Utility unzip does not exist')"; fi
  EXEC="unzip -p"
  unzip -t $FILESOURCE > /dev/null 2>&1
  [ $? -ne 0 ] && err_exit "$(gettext 'Source file appears to be corrupted:')
${FILESOURCE}"
 ;;
 iso) #200215
  EXEC=''
  if which isolyzer >/dev/null;then
   SZflg="$(isolyzer ${FILESOURCE} | grep -c '<smallerThanExpected>False</smallerThanExpected>')"
   [ "$SZflg" == "0" ] && err_exit "$(gettext 'ISO file size is less than it should be')"
  fi
 ;;
 *)
  err_exit "$(gettext 'Filename is wrong')"
 ;;
esac
if [ "$MSGID" ];then
 if which pupkill >/dev/null;then pupkill ${MSGID}; fi
 kill $MSGID 2>/dev/null
fi

#how to flip all bits in a file:
# https://unix.stackexchange.com/questions/151003/how-could-i-flip-content-of-a-binary-file-with-bash-commands
# LC_ALL=C tr '\0-\377' '\377\376\375\374\373\372\371\370\367\366\365\364\363\362\361\360\357\356\355\354\353\352\351\350\347\346\345\344\343\342\341\340\337\336\335\334\333\332\331\330\327\326\325\324\323\322\321\320\317\316\315\314\313\312\311\310\307\306\305\304\303\302\301\300\277\276\275\274\273\272\271\270\267\266\265\264\263\262\261\260\257\256\255\254\253\252\251\250\247\246\245\244\243\242\241\240\237\236\235\234\233\232\231\230\227\226\225\224\223\222\221\220\217\216\215\214\213\212\211\210\207\206\205\204\203\202\201\200\177\176\175\174\173\172\171\170\167\166\165\164\163\162\161\160\157\156\155\154\153\152\151\150\147\146\145\144\143\142\141\140\137\136\135\134\133\132\131\130\127\126\125\124\123\122\121\120\117\116\115\114\113\112\111\110\107\106\105\104\103\102\101\100\77\76\75\74\73\72\71\70\67\66\65\64\63\62\61\60\57\56\55\54\53\52\51\50\47\46\45\44\43\42\41\40\37\36\35\34\33\32\31\30\27\26\25\24\23\22\21\20\17\16\15\14\13\12\11\10\7\6\5\4\3\2\1\0' < file.in > file.out
# ...very slow! have a fast utility 'bitflip', now in pup-tools pet.
# bitflip ref: https://unix.stackexchange.com/questions/104585/bit-wise-complement-with-dd

[ -e /tmp/easydd-read-failure ] && rm -f /tmp/easydd-read-failure
xEXEC="${EXEC}"
[ "$EXEC" == "" ] && xEXEC='cat'

M3a="$(gettext 'Writing inverse of file to drive:')"
M3c="$(gettext 'Executing:')"
M3d="$(gettext 'Verifying write of inverse of file:')"
M3b="$(gettext 'Writing file to drive:')"
M3e="$(gettext 'Verifying write of file:')"
M3f="$(gettext 'Verifying write of inverse of file has failed. The drive is faulty.')"
M3h="$(gettext '...verified successful write')"
M3i="$(gettext 'Verifying write of file has failed. The drive is faulty.')"

#find size of expanded file...
EXPSIZEB="$(${xEXEC} "${FILESOURCE}" | wc -c)"
EXPSIZEK="$(($EXPSIZEB / 1024))"
EXPSIZEM="$(($EXPSIZEK / 1024))"
#create a script to perform the write... 191224 remove inverse-write...
echo "#!/bin/bash
##write inverse of file and verify...
#echo \"${M3a}\"
#if which bitflip >/dev/null; then #bitflip is in pup-tools pet package.
# LC_ALL=C ${xEXEC} \"${FILESOURCE}\" | bitflip | sha512sum > /tmp/easydd-inverse-sha512sum-write
# sync
# LC_ALL=C ${xEXEC} \"${FILESOURCE}\" | bitflip 2>/dev/null | dd of=/dev/${DRVTARGET} bs=1M conv=fsync status=progress oflag=sync
#else
# LC_ALL=C ${xEXEC} \"${FILESOURCE}\" | tr '\\0-\\377' '\\377\\376\\375\\374\\373\\372\\371\\370\\367\\366\\365\\364\\363\\362\\361\\360\\357\\356\\355\\354\\353\\352\\351\\350\\347\\346\\345\\344\\343\\342\\341\\340\\337\\336\\335\\334\\333\\332\\331\\330\\327\\326\\325\\324\\323\\322\\321\\320\\317\\316\\315\\314\\313\\312\\311\\310\\307\\306\\305\\304\\303\\302\\301\\300\\277\\276\\275\\274\\273\\272\\271\\270\\267\\266\\265\\264\\263\\262\\261\\260\\257\\256\\255\\254\\253\\252\\251\\250\\247\\246\\245\\244\\243\\242\\241\\240\\237\\236\\235\\234\\233\\232\\231\\230\\227\\226\\225\\224\\223\\222\\221\\220\\217\\216\\215\\214\\213\\212\\211\\210\\207\\206\\205\\204\\203\\202\\201\\200\\177\\176\\175\\174\\173\\172\\171\\170\\167\\166\\165\\164\\163\\162\\161\\160\\157\\156\\155\\154\\153\\152\\151\\150\\147\\146\\145\\144\\143\\142\\141\\140\\137\\136\\135\\134\\133\\132\\131\\130\\127\\126\\125\\124\\123\\122\\121\\120\\117\\116\\115\\114\\113\\112\\111\\110\\107\\106\\105\\104\\103\\102\\101\\100\\77\\76\\75\\74\\73\\72\\71\\70\\67\\66\\65\\64\\63\\62\\61\\60\\57\\56\\55\\54\\53\\52\\51\\50\\47\\46\\45\\44\\43\\42\\41\\40\\37\\36\\35\\34\\33\\32\\31\\30\\27\\26\\25\\24\\23\\22\\21\\20\\17\\16\\15\\14\\13\\12\\11\\10\\7\\6\\5\\4\\3\\2\\1\\0' | sha512sum > /tmp/easydd-inverse-sha512sum-write
# sync
# LC_ALL=C ${xEXEC} \"${FILESOURCE}\" | tr '\\0-\\377' '\\377\\376\\375\\374\\373\\372\\371\\370\\367\\366\\365\\364\\363\\362\\361\\360\\357\\356\\355\\354\\353\\352\\351\\350\\347\\346\\345\\344\\343\\342\\341\\340\\337\\336\\335\\334\\333\\332\\331\\330\\327\\326\\325\\324\\323\\322\\321\\320\\317\\316\\315\\314\\313\\312\\311\\310\\307\\306\\305\\304\\303\\302\\301\\300\\277\\276\\275\\274\\273\\272\\271\\270\\267\\266\\265\\264\\263\\262\\261\\260\\257\\256\\255\\254\\253\\252\\251\\250\\247\\246\\245\\244\\243\\242\\241\\240\\237\\236\\235\\234\\233\\232\\231\\230\\227\\226\\225\\224\\223\\222\\221\\220\\217\\216\\215\\214\\213\\212\\211\\210\\207\\206\\205\\204\\203\\202\\201\\200\\177\\176\\175\\174\\173\\172\\171\\170\\167\\166\\165\\164\\163\\162\\161\\160\\157\\156\\155\\154\\153\\152\\151\\150\\147\\146\\145\\144\\143\\142\\141\\140\\137\\136\\135\\134\\133\\132\\131\\130\\127\\126\\125\\124\\123\\122\\121\\120\\117\\116\\115\\114\\113\\112\\111\\110\\107\\106\\105\\104\\103\\102\\101\\100\\77\\76\\75\\74\\73\\72\\71\\70\\67\\66\\65\\64\\63\\62\\61\\60\\57\\56\\55\\54\\53\\52\\51\\50\\47\\46\\45\\44\\43\\42\\41\\40\\37\\36\\35\\34\\33\\32\\31\\30\\27\\26\\25\\24\\23\\22\\21\\20\\17\\16\\15\\14\\13\\12\\11\\10\\7\\6\\5\\4\\3\\2\\1\\0' | dd of=/dev/${DRVTARGET} bs=1M conv=fsync status=progress oflag=sync
#fi
#sync
#echo ''
#echo \"${M3d}\"
#LC_ALL=C dd if=/dev/${DRVTARGET} bs=1K count=${EXPSIZEK} | sha512sum > /tmp/easydd-inverse-sha512sum-read
#sync
#if cmp -s /tmp/easydd-inverse-sha512sum-write /tmp/easydd-inverse-sha512sum-read; then
# echo \"${M3h}\"
#else
# echo \"${M3f}\"
# touch /tmp/easydd-read-failure
# sleep 2
# exit 1
#fi
#now write the normal image file...
echo ''
echo \"${M3b}\"
 echo -e \"\\\\033[1;31m${M2f}\\\\033[0;39m\" #red
 echo \"${M3c}\"
echo \"${xEXEC} \"${FILESOURCE}\" | dd of=/dev/${DRVTARGET} bs=1M conv=fsync status=progress oflag=sync\"
echo ''
LC_ALL=C ${xEXEC} \"${FILESOURCE}\" | sha512sum > /tmp/easydd-sha512sum-write
sync
LC_ALL=C ${xEXEC} \"${FILESOURCE}\" | dd of=/dev/${DRVTARGET} bs=1M conv=fsync status=progress oflag=sync
sync
echo ''
echo \"${M3e}\"
LC_ALL=C dd if=/dev/${DRVTARGET} bs=1K count=${EXPSIZEK} | sha512sum > /tmp/easydd-sha512sum-read
sync
if cmp -s /tmp/easydd-sha512sum-write /tmp/easydd-sha512sum-read; then
 echo \"${M3h}\"
else
 echo \"${M3i}\"
 touch /tmp/easydd-read-failure
 sleep 2
 exit 1
fi
exit 0" > /tmp/easydd-exec
chmod 755 /tmp/easydd-exec
if [ "$MODE" == "gui" ];then
 ${RXVTEXE} -title 'EasyDD' -background '#ffff80' -geometry '80x10' -e /tmp/easydd-exec
else
 echo
 /tmp/easydd-exec
fi
sync

sleep 2 #need sleep before next line...
echo 'change' > /sys/block/${DRVTARGET}/uevent

if [ -e /tmp/easydd-read-failure ];then
 M4b="$(gettext 'Write failed')"
 M4c="$(gettext 'The drive is faulty. Please unplug it.')"
 if [ "$MODE" == "gui" ];then
  ${MSGEXE} -wrap -bg '#ffa0a0' -title "EasyDD: ${M4b}" "${M4c}"
 else
  echo
  echo -e "\\033[1;31m${M4b}\\033[0;39m" #red
  echo -e "\\033[1;31m${M4c}\\033[0;39m" #red
 fi
else
 M4b="$(gettext 'Write finished')"
 M4c="$(gettext 'Verified successful. You may unplug the drive')"
 if [ "$MODE" == "gui" ];then
  ${MSGEXE} -wrap -bg '#a0ffa0' -title "EasyDD: ${M4b}" "${M4c}"
 else
  echo
  echo -e "\\033[1;32m${M4b}\\033[0;39m" #green
  echo -e "\\033[1;32m${M4c}\\033[0;39m" #green
 fi
fi
###END###
