#! /bin/bash

#-----------------------------------------------------------------------------
#
# author sudodus alias nio-wiklund at launchpad
#
# date        editor   comment
# 2013-06-25  sudodus  linux installer from tarball of installed system
# 2013-06-27  sudodus  raring.tar.gz
# 2013-08-09  sudodus  removed lame logic for wipe as alternative to install
# 2013-09-22  sudodus  mktst selector introduced in mkusb
# 2013-09-24  sudodus  help text managed also for text screen
# 2013-09-26  sudodus  mktst selector tweaked for mkusb
# 2013-09-26  sudodus  mkusb cleaned, version 4.0
# 2013-11-17  sudodus  not only check also offer installation of pv
# 2013-11-22  sudodus  mkusb version 5.0
# 2014-01-06  sudodus  mkusb version 6.0 calls to sudo removed
# 2014-01-29  sudodus  identification of 'livedrive' fixed for live session
# 2014-01-29  sudodus  mkusb version 7.0
# 2014-01-30  sudodus  more livedrive fixes: CD, cloned iso, grub-n-iso,
#                      unetbootin, usb-creator-gtk
# 2014-01-30  sudodus  mkusb version 7.1
# 2014-03-06  sudodus  fix to recognize debian iso file and work from CD
# 2014-03-06  sudodus  mkusb version 7.2
# 2014-03-09  sudodus  second parameter 'all' to start seeing all drives
#                      usbonly=false
# 2014-03-09  sudodus  mkusb version 7.3
# 2014-03-13  sudodus  switch for help window
# 2014-03-14  sudodus  writing "Done" after installation (for xterm -hold) 
# 2014-03-14  sudodus  mkusb version 7.4
# 2014-10-02  sudodus  mkusb-bas version, simple and basic version
# 2014-10-02  sudodus  stripped from iso-testing feature
# 2014-10-02  sudodus  improved livedrive recognition
# 2014-10-03  sudodus  tweaked to recognize and run from Wary Puppy
# 2014-10-03  sudodus  mkusb version 7.4.1
# 2014-11-19  sudodus  "Please wait for sync (flushing file system buffers
#                      to the device) until 'Done' is written ..."
# 2014-11-19  sudodus  mkusb version 7.4.2
# 2017-06-28  sudodus  tweaked to recognize and run from TahrPup
# 2017-06-28  sudodus  FINAL WARNING ---> Final checkpoint
# 2017-06-28  sudodus  mkusb version 7.4.3

version=7.4.3

inversvid="\0033[7m"
resetvid="\0033[0m"

#-----------------------------------------------------------------------------

function mktst {

# select target drive, make command and run command

echo "***  Unmount the device if mounted  ****************************"
echo " "

ltest0=$(grep -m 1 " / " /etc/mtab|cut -d ' ' -f 1)
if [ "$ltest0" == "/cow" ] || [ "$ltest0" == "aufs" ] || [ "$ltest0" == "rootfs" ]
then
 ltest1=$(grep -m 1 ' /isodevice' /etc/mtab|cut -c 5-8)
 if [ "$ltest1" != "" ]
 then
  livedrive=$ltest1
 else
  ltest1=$(grep -m 1 ' /cdrom' /etc/mtab|cut -c 5-8)
  if [ "$ltest1" != "" ]
  then
   livedrive=$ltest1
  else
   ltest1=$(grep -m 1 ' /livecd' /etc/mtab|cut -c 5-8)
   if [ "$ltest1" != "" ]
   then
    livedrive=$ltest1
   else
    ltest1=$(grep -m 1 ' iso9660' /etc/mtab|grep -v ' /media'|grep -v ' /mnt'|cut -c 5-8)
    if [ "$ltest1" != "" ]
    then
     livedrive=$ltest1
    else
     ltest1=$(grep -m 1 ' iso9660' /etc/mtab|grep ' /mnt-system'|cut -c 5-8)  # knoppix
     if [ "$ltest1" != "" ]
     then
      livedrive=$ltest1
     else
      livedrive=$(df|grep -m 1 " /$" |cut -c 5-8)  # mageia
      if [ "$ltest1" != "" ] && test -b "/dev$ltest1"
      then
       livedrive=$ltest1
      else
       df|grep pup_r > /dev/null  # wary puppy
       if [ $? -eq 0 ]
       then
        ltest1=
        echo "Check if Puppy live drive:"
        iso=$(mktemp -d)
        icnt=0
        for i in $(blkid|grep /dev/[^f]d.:|sed 's/:.*//'|sort)
        do
         umount "$i" > /dev/null 2>&1
         mount -t auto "$i" "$iso" > /dev/null 2>&1
         ls "$iso" |grep puppy
         if [ $? -eq 0 ]
         then
          icnt=$((icnt + 1))
          if [ $icnt -eq 1 ]
          then
           echo "This Puppy drive might be the active live drive"
          else
           echo "*** There are more than one Puppy drives! ***"
          fi
          drstr=$(fdisk -lu "$i" | grep "^Disk /")
          echo -e "$inversvid $drstr $resetvid"
          read -p "Check and decide: Is this the live drive (Y/n) " excl
          if [ "$excl" != "n" ]
          then
           ltest1=${i/\/dev}
           livedrive=$ltest1
          fi
         fi
         umount "$iso"
        done
        if [ "$ltest1" == "" ]
        then
         rmdir "$iso"
         echo "--------------------------------------------------------"
         echo "This version is basic and lacks some automatic checking."
         echo "Live drive not identified. Select target drive carefully"
         echo "to avoid mistakes.   Press Enter to continue!           "
         echo "--------------------------------------------------------"
         read 
         livedrive="_not_found"
        fi
       else
        df|grep -m 1 /tmp/tcloop > /dev/null  # tiny core
        if [ $? -eq 0 ]
        then
         ltest1=
         echo "Check if TinyCore live drive:"
#         iso=$(mktemp -d)
         for i in $(blkid|grep TinyCore|grep iso9660|sed 's/:.*//'|sort)
         do
#          umount "$i" > /dev/null 2>&1
#          mount -t auto "$i" "$iso" > /dev/null 2>&1
#          ls "$iso" |grep puppy
#          if [ $? -eq 0 ]
#          then
           ltest1=${i:4:4}
           livedrive=$ltest1
           echo "$i is a TinyCore device and might belong to the live drive"
#          fi
#          umount "$iso"
          done
         if [ "$ltest1" == "" ]
         then
          rmdir "$iso"
          echo "--------------------------------------------------------"
          echo "This version is basic and lacks some automatic checking."
          echo "Live drive not identified. Select target drive carefully"
          echo "to avoid mistakes.   Press Enter to continue!           "
          echo "--------------------------------------------------------"
          read 
          livedrive="_not_found"
         fi
        else
         which lvm > /dev/null
         if [ $? -eq 0 ]
         then
          ltest1=$(lvm pvdisplay|grep 'PV Name'|sed 's/.* //'|cut -c 5-8)  # fedora
          ltest2=$(df|grep -m 1 " /$" |sed 's/ .*//')
         fi
         if [ "$ltest1" != "" ] && [ "$ltest2" == "/dev/mapper/fedora-root" ]
         then
          livedrive=$ltest1
          if ! test -b "/dev$livedrive"
          then
           echo "--------------------------------------------------------"
           echo "This version is basic and lacks some automatic checking."
           echo "Live drive not identified. Select target drive carefully"
           echo "to avoid mistakes.   Press Enter to continue!           "
           echo "--------------------------------------------------------"
           read
           livedrive="_not_found"
          fi
         fi
        fi
       fi
      fi
     fi
    fi
   fi
  fi
 fi
elif [ "${ltest0/\/dev\/[^f]d}" != "" ]
then
 livedrive=$(grep -m 1 " / " /etc/mtab|cut -c 5-8)
else
 livedrive=$(df|grep -m 1 " /$" |cut -c 5-8)
 if ! test -b "/dev$livedrive"
 then
  livedrive="not_found"
 fi
fi
#echo ltest0=$ltest0
#echo ltest1=$ltest1
#echo ltest2=$ltest2
#echo livedrive=$livedrive

if [ "$livedrive" != "not_found" ]
then
 echo "Live drive: /dev$livedrive"
else
 echo "Live drive not found"
fi

for i in /dev/[^f]d?; do parted -ls 2>/dev/null|grep -B1 "$i"|tr '\n' '\t';echo "";done
if [ "$livedrive" != "not_found" ]
then
 echo "Live drive: /dev$livedrive"
else
 echo "Live drive not found"
fi
for i in $(find /sys/devices -name "*sd?"|grep usb|sed s#.*/##)
do
 fdisk -lu /dev/$i 2>/dev/null|grep "Disk /dev"
done|sed 's/Disk/USB drive: /'|sort
echo " "

choice=1

# check if all drives should be available at start (not only USB)
# usbonly default true, can be changed with parameter2 'all'

if [ "$2" == "all" ]
then
 usbonly=false
else
 usbonly=true
fi

ans=
while [ "$ans" != "g" ]
do
 item=0
 cmdsav=

 if $usbonly; then ufl=usb; else ufl=d;fi
#  for j in $(for i in $(find /sys/devices -name "*sd?"|grep usb|grep -v $livedrive|sed s#.*/##)
  for j in $(for i in $(find /sys/devices -name "[^f]d?"|grep $ufl|grep -v $livedrive|sed s#.*/##)
            do
              fdisk -lu /dev/$i 2>/dev/null|grep "Disk /dev"|sed -e s/:.*// -e s/.*\ //
            done|sort)
 do
  busy=0
  for k in $(grep $j /etc/mtab|sed s#\ /.*##)
  do umount $k 2>/dev/null; if [ "$?" == "1" ];then busy=1;fi ;done
  if [ "$busy" == "1" ]
  then
   echo "#       could not unmount $j because file system on device is busy"
  else
   item=$(($item + 1))
#   echo $item , $choice
   if [ $item -eq $choice ]
   then
    /bin/echo -en "\0033[7m---> "
   else
    /bin/echo -en "     "
   fi

   tj="$(parted -ls 2>/dev/null|grep -B1 "$j"|tr '\n' ' '|sed s/Model:\ //;echo "")"
#echo "${tj}"
#echo "${tj:1:7}"
   if [ "${tj:1:7}" == "Warning" ] || [ "${tj:1:5}" == "Error" ] || \
      [ "${tj:0:7}" == "Warning" ] || [ "${tj:0:5}" == "Error" ]   
   then
     tj=$(fdisk -lu "$j" 2>/dev/null|grep "$j":|sed s/\,\ .*//)
   fi
   if [ "$source" != "/dev/zero" ]
   then
    targ0="$j"
#    cmd0="$item: install $source to $tj"
    cmd0="$item: install to $tj"
   else
    targ0="$j"
    cmd0="$item: wipe device $tj"
   fi
   if [ "$item" == "$choice" ]
   then
#    /bin/echo -en "$resetvid"
    target="$targ0"
    cmdsav=$cmd0
    cmd0="$cmd0""$resetvid"
   fi
   /bin/echo -e $cmd0
  fi
 done
 
# select device, go or quit

 if [ $item -lt 1 ]
 then
  if $usbonly
  then
   echo "No USB target device available. Toggle USB-only?"
  else
   echo "No target device available"
   exit
  fi
 elif [ $item -gt 1 ]
 then
  echo "Select another device with (+/-) or the number of the list item."
 fi
 echo "Go ahead with (g) or quit with (q). Toggle USB-only with (u)."
 read ans
 if [ "$ans" == "+" ]
 then
  choice=$(($choice + 1))
  if [ $choice -gt $item ]
  then
    choice=$item
  fi
 elif [ "$ans" == "-" ]
 then
  choice=$(($choice - 1))
  if [ $choice -lt 1 ]
  then
    choice=1
  fi
 elif [ "$ans" == "u" ]
 then
  choice=1
  if $usbonly
  then
   usbonly=false
  else
   usbonly=true
  fi
 elif [ "$ans" == "q" ]
 then
  exit
 elif [ "$ans" '>' "0" ] && [ "$ans" '<' "$item" ] || [ "$ans" == "$item" ]
# elif [ "$ans" != "g" ] && [ $ans -gt 0 ] && [ $ans -le $item ]
 then
   choice=$ans
 fi
done

# check if any target

if [ $item -lt 1 ]
then
 echo "No target device selected"
 exit
fi

# here we go

/bin/echo -e "${cmdsav/install to/source: $source
   target:}"
/bin/echo -e "$inversvid Final checkpoint" $resetvid
echo "Do you really want to wipe and install to this device? (y/n)"
read ans
if [ "$ans" == "y" ]
then
 if [ "$target" == "" ]
 then
  echo "$cmdsav"
 else
  swapoff "$target"* 2>/dev/null
  sync

# the command line is implemented 

  echo " "

# build target

  if [ "$1" == "wipe-whole-device" ] || [ "$1" == "/dev/zero" ]
  then
   echo "Wiping the whole device $target ..."
  elif [ "$1" == "wipe-1" ] || [ "$1" == "wipe1" ]
  then
   echo "Wiping the first megabyte (MibiByte) of $target ... :"
  else
   echo "Installing $1 to $target ..."
   echo " "
  fi

# build beginning of command (read the source) and calculate size

  if [ "$source" == "$1" ]
  then
   if [ "${1/.iso}" != "$1" ] || [ "${1/.img}" != "$1" ]
   then
    size=$(wc -c "$1"|cut -d ' ' -f 1)
    readsrc="< $source"
   elif [ "${1/.img.[gx]z}" != "$1" ]
   then
    if [ "${1/.img.gz}.img.gz" == "$1" ]
    then
     size=$(gzip -l "$1"|grep "${1/.gz}"|tr -s ' ' ' '|sed s/^\ //|cut -d ' ' -f 2)
     readsrc="zcat $source |"
    else
     si10=$(xz -l "$1"|grep "${1/.xz}"|tr -s ' ' ' '|sed s/^\ //| \
            cut -d ' ' -f 5|sed 's/\.//')
     sitr=$(((${si10}+5)/10))
     powr=$(xz -l "$1"|grep "${1/.xz}"|tr -s ' ' ' '|sed s/^\ //| \
            cut -d ' ' -f 6|sed -e s/..$//)
     size=$sitr$powr
     readsrc="xzcat $source |"
    fi
   fi
   sizz=$(echo "$size" | tr '[:upper:]' '[:lower:]')
   size="-s $sizz"
  else
   readsrc="< $source"
   size=
  fi

# build pvpipe (if available)

  if $pvplug
  then
   pvpipe="pv $size |"
  else
   pvpipe=
  fi

#  echo "\$1=$1"
#  echo "source=$source"
#  echo "target=$target"
#  echo "bs=$bs"
#  echo "cnt=$cnt"
#  echo "pvplug=$pvplug"
#  echo "size=$size"
#  echo "pvpipe=$pvpipe"
#  echo "readsrc=$readsrc"

  cmdfile=$(mktemp)

  cmdline="$readsrc $pvpipe dd bs=$bs $cnt of=$target"

  echo "$cmdline"|tee $cmdfile
  echo "Please wait for sync (flushing file system buffers to the device)"
  echo "until 'Done' is written ..."
  bash $cmdfile
  echo "Syncing the device ..."
  rm $cmdfile
  sync
  echo "Done"
 fi
fi
}

# ---------------------------------------------------------------------
#
# mkusb main program
#
# ---------------------------------------------------------------------

bs=4096
count=256
cnt=
target=
source="$1"
LC_ALL=C
LANG=C

# print version on demand

if [ "$1" == "-v" ]
then
 echo "mkusb version $version"
 exit
fi 

# usage text

if [ "$(whoami)" != "root" ] || \
  ( [ $# -ne 1 ] && ( [ "$2" != "all" ] || [ $# -ne 2 ] ) )
then
 echo "Usage:"
 if [ $# -ne 1 ] && ( [ "$2" != "all" ] || [ $# -ne 2 ] )
 then
  echo "---- Make a USB install device from 'file.iso' ---------------"
  echo "sudo $0 file.iso"
  echo "---- Make a USB install device from 'file.img' ---------------"
  echo "sudo $0 file.img"
  echo "---- Make a USB install device from 'file.img.gz' ------------"
  echo "sudo $0 file.img.gz"
  echo "---- Make a USB install device from 'file.img.xz' ------------"
  echo "sudo $0 file.img.xz"
  echo "---- Install from 'file.img.xz', show all mass storage devices"
  echo "sudo $0 file.img.xz all"
  echo "---- Wipe the USB device (may take long time) ----------------"
  echo "sudo $0 wipe-whole-device"
  echo "---- Wipe the first megabyte (MibiByte), show only USB devices"
  echo "sudo $0 wipe-1"
  echo "---- Wipe the first megabyte, show all mass storage devices --"
  echo "sudo $0 wipe-1 all"
  echo "---- Version -------------------------------------------------"
  echo "$0 -v"
 else
  echo "sudo $0 $1 $2"
 fi
 exit
fi

# check usage mode and input file extension

if [ "${1/.iso}.iso" != "$1" ] && \
   [ "${1/.img}.img" != "$1" ] && \
   [ "${1/.img.gz}.img.gz" != "$1" ] && \
   [ "${1/.img.xz}.img.xz" != "$1" ]
then
 if [ "$1" == "wipe-whole-device" ] || [ "$1" == "/dev/zero" ]
 then
  echo "Wipe the whole device ... :"
  source="/dev/zero"
 elif [ "$1" == "wipe-1" ] || [ "$1" == "wipe1" ]
 then
  echo "Wipe the first megabyte (MibiByte) ... :"
  source="/dev/zero"
  cnt="count=$count"
 else
  echo ":-( $1 is neither an iso, img nor an img.{gz,xz} file :-("
  exit
 fi
elif [ ! -f "$source" ]
then
 echo ":-( $source is not found :-("
 exit
fi

# check pipe view and offer installation

which pv > /dev/null
if [ "$?" == "0" ]
then
 pvplug=true
else
 echo "The program 'pv' can show the progress during the installation."
 echo "Please install it to get this feature!"
 which pv > /dev/null
 if [ "$?" == "0" ]
 then
  pvplug=true
 else
  pvplug=false
 fi
fi
#echo $pvplug

# alternatives: wipe or clone an iso, img, img.gz, img.xz file

echo "------------------------------------------------------------------------"
echo "'mkusb-bas' is basic and lacks automatic checking for ISO testing."
echo "Sometimes the live drive is not found. Select target drive carefully"
echo "to avoid mistakes. Use mkusb-bas only if mkusb or mkusb-nox do not work!"
echo "------------------------------------------------------------------------"
question="Do you want to clone $1 to a mass storage device
(typically USB drive)? (y/N) "
if [ "$source" == "/dev/zero" ]
then
 echo "Do you want to wipe a mass storage device (typically USB drive)? (y/n)"
elif [ "${1/.iso}.iso" == "$1" ] || [ "${1/.img}.img" == "$1" ]
then
 echo "$question"
elif [ "${1/.img.gz}.img.gz" == "$1" ] || [ "${1/.img.xz}.img.xz" == "$1" ]
then
 echo "$question"
else
 echo "Bad choice -- exit"
 exit
fi
read ans
if [ "$ans" == "y" ]
then

 warnstr="***  WARNING: the device will be completely overwritten      ***"
 quitstr="***  quit with (q)                                           ***"
 /bin/echo -e "$inversvid""$warnstr""$resetvid"
 /bin/echo -e "$inversvid""$quitstr""$resetvid"

# select target drive, make command and run command

 mktst "$1" "$2"
fi
