#!/bin/bash
IMG_TYPE=${IMG_TYPE:-qcow2}
TABLE=${TABLE:-gpt}
SIZE=${SIZE:-20000} # в метрах
BIOS=${BIOS:-legacy}
p=''

HLP(){
  echo "
  $(basename "$0") - Tool for quick installation of Rosa Linux from ISO to a disk image  
  Supported image formats: img (raw image), qcow2, vdi, vmdk  (default: qcow2)

  USAGE:
     $(basename "$0") [OPTIONS] <file.iso>
  or
     VAR=VALUE $(basename "$0") <file.iso>

  OPTIONS:
    -e            - Use UEFI (default: Legacy BIOS)
    -m            - Use MBR partition table (default: GPT)
    -s <SIZE>     - Set disk image size in MB (default: 20000)
    -t <TYPE>     - Image type (img, qcow2, vmdk, vdi; default: qcow2)
    -o <NAME>     - Name for output image with a PATH (default: <ISO_NAME>.<TYPE>)
    -h, --help    - Show this help message

  ENVIRONMENT VARIABLES (used if no equal option is provided):
    BIOS=efi             - Use UEFI (same as -e)
    TABLE=mbr            - Use MBR (same as -m)
    SIZE=20000           - Image size in MB (same as -s)
    IMG_TYPE=vdi         - Image format (same as -t)
    IMG=/tmp/file.qcow2  - Output image file (same as -o)
    
  DEFAULT CREDENTIALS:
    Username: rosa
    Password: rosa

  EXAMPLES:
    $(basename "$0") -s 25000 -t qcow2 RosaLinux.iso   # Creates './RosaLinux.qcow2'
    $(basename "$0") -o /tmp/custom.img RosaLinux.iso  # Creates '/tmp/custom.img'
    IMG_TYPE=vmdk $(basename "$0") RosaLinux.iso       # Creates './RosaLinux.vmdk'
  "
  exit
}


copy_timer() {
    local SHORTNAME TARGET_DIR MARKER
    REWRITE="\e[25D\e[1A\e[K"
    TARGET_DIR="$3"
    SHORTNAME=$(basename $2)
    (cp "$1" "$2"/* "$3"/) &
    MARKER="/proc/$!"
    sek=0
    echo "wait..."
    while true; do
        echo -e "${REWRITE}==> cp time: ${sek}; ${SHORTNAME}: $(du -hd 0 $TARGET_DIR | cut -f1)"
        [ -e $MARKER ] || break
        sleep 1
        sek=$(($sek + 1))
    done
    echo -ne "${REWRITE}"
}

echo_exit() {
    clear
    echo "ERROR: line: $@" 1>&2
    echo ':(' 1>&2
    exit $1
}

clear(){
  echo "==> Clear" 1>&2
  n=5
  while [ "$n" -ne 0 ] ; do
    ls iso2img.* 2>/dev/null 1>&2 || break
    umount iso2img.* 2>/dev/null
    rmdir iso2img.* 2>/dev/null
    n=$(( $n - 1 ))
  done
  umount -l iso2img.* 2>/dev/null
  rmdir iso2img.* 2>/dev/null
  qemu-nbd --disconnect /dev/nbd0
}


mk_img(){
  echo "==> mk_img" 1>&2
  if [ "$IMG_TYPE" != 'img' ] ; then
    qemu-img create -f "$IMG_TYPE" "$1" "${SIZE}M"
  else
    dd if=/dev/zero of="$1" bs=1 count=0 seek="${SIZE}M"
  fi
}

partitions(){
  echo "==> partitions" 1>&2
  if [ $TABLE == 'gpt' ] ; then
    echo '* gpt'
    parted -s $1 mklabel gpt || echo_exit ${LINENO} "Cannot create gpt"
    if [ $BIOS == 'legacy' ] ; then
      echo '* legacy'
      parted  -a optimal -s "$1"  mkpart bios_boot  0  2MiB set 1 bios_grub on
      parted  -a optimal -s "$1"  mkpart ROSA  3MiB  100% 
    else
      echo '* efi'
      parted  -a optimal -s "$1"  mkpart EFI  1MiB  100MiB set 1 esp on
      parted  -a optimal -s "$1"  mkpart ROSA 101MiB  100%
    fi
  else
    echo '* mbr'
    parted -s $1 mklabel msdos || echo_exit ${LINENO} "Cannot create msdos"
    if [ $BIOS == 'legacy' ] ; then
      echo '* legacy'
      parted  -a optimal -s "$1"  mkpart primary  1MiB  100% set 1 boot on
    else
      echo efi
      parted  -a optimal -s "$1"  mkpart primary  1MiB  100MiB set 1 esp on
      parted  -a optimal -s "$1"  mkpart primary  101MiB  100%
    fi
  fi
  partprobe $1
}

connect_img() {
  echo "==> connect_img" 1>&2
  if [ $IMG_TYPE != img ] ; then
    if qemu-nbd --connect=/dev/nbd0 $(realpath $1) 1>&2 ; then
      echo /dev/nbd0
    else 
      echo_exit ${LINENO} "Cannot connect /dev/nbd"
    fi
  else
    blk=$(losetup -f)
    if losetup $blk $(realpath $1) ; then
      echo "$blk"
    else
      echo_exit ${LINENO} "losetup error"
    fi
fi
}

mount_img() {
  local blk MPOIN
  echo "==> mount_img" 1>&2
  MPOINT=$(mktemp -d iso2img.root.XXXX) 1>&2
  partprobe $1 1>&2
  if [ $BIOS == 'legacy' ] ; then
      N=1
      [ $TABLE == 'gpt' ] && N=2
      mkfs.ext4 -L ROSA ${1}${p}${N} 1>&2
      mount ${1}${p}${N} $MPOINT || echo_exit ${LINENO} "Cannot mount ${1}${p}${N}"
  else
    mkfs.ext4 -L ROSA ${1}${p}2 1>&2
    mkfs.vfat -F 32 -n ROSA_EFI ${1}${p}1 1>&2
    mount ${1}${p}2 $MPOINT || echo_exit ${LINENO} "Cannot mount ${1}${p}2"
    mkdir -p ${MPOINT}/boot/efi
    mount ${1}${p}1 ${MPOINT}/boot/efi || echo_exit ${LINENO} "Cannot mount ${1}${p}1"
  fi
  echo $MPOINT
}

mount_iso(){
  echo "==> mount_iso" 1>&2
  local MPOINT_ISO
  MPOINT_ISO=$(mktemp -d iso2img.iso.XXXX)
  local MPOINT_SQFS
  MPOINT_SQFS=$(mktemp -d iso2img.sqfs.XXXX)
  local MPOINT_ext=$(mktemp -d iso2img.ext.XXXX)
  MPOINT_ext=$(mktemp -d iso2img.ext.XXXX)
  (mount -o loop $ISO $MPOINT_ISO 1>&2 && \
  mount ${MPOINT_ISO}/LiveOS/squashfs.img $MPOINT_SQFS 1>&2 && \
  mount ${MPOINT_SQFS}/LiveOS/rootfs.img $MPOINT_ext 1>&2) || \
  echo_exit ${LINENO} "Cannot mount ISO layers"
  echo "$MPOINT_ext"
}

install_OS(){
  echo "==> install_OS" 1>&2
  copy_timer -fax  "${1}" "${2}"
  [ -f "${2}/etc/os-release" ] || echo_exit ${LINENO} "Install OS error"
}

post_install(){
  TARGET=i386-pc
  [ "$BIOS" == 'efi' ] && TARGET='x86_64-efi'
  echo "==> post_install" 1>&2
  cat <<EOF >> ${1}/init_OS.sh
#!/bin/sh
#dnf refresh
dnf remove -y 'anaconda*'
# dnf autoremove
dd if=/dev/random bs=64 count=1 2>/dev/null |md5sum | cut -f1 -d ' ' >/etc/machine-id
grub2-install $2 --target=$TARGET
update-grub2
# В чруте swapon видит своп, отсюда в конфиге resume=UUID=
sed -i  's/ resume=UUID=/ /g' /boot/grub2/grub.cfg
if [ -f /boot/efi/EFI/rosa/grubx64.efi ] ; then
  cp /boot/efi/EFI/rosa/* /boot/efi/EFI/BOOT/
  cp /boot/efi/EFI/BOOT/shimx64.efi /boot/efi/EFI/BOOT/BOOTx64.efi || \
  cp /boot/efi/EFI/BOOT/grubx64.efi /boot/efi/EFI/BOOT/BOOTx64.efi
fi
adduser rosa
echo rosa | passwd rosa --stdin
usermod -a -G wheel rosa
#/bin/sh
EOF
  chmod +x ${1}/init_OS.sh
  if [ -b "${blkdev}${p}2" ] ; then
    systemd-nspawn -D ${1} --bind="${blkdev}" --bind="${blkdev}${p}1" --bind="${blkdev}${p}2" --bind="/dev/disk/" /init_OS.sh
  else
    systemd-nspawn -D ${1} --bind="${blkdev}" --bind="${blkdev}${p}1" --bind="/dev/disk/" /init_OS.sh
  fi
}

while [ -n "$1" ] ; do
  case "$1" in
    "-m" ) TABLE=msdos;;
    "-e" ) BIOS=efi;;
    "-h" | "--help" ) HLP ;;
    "-t" | "--image-type" ) shift
           IMG_TYPE="$1";;
    "-s" | "--size" ) shift
           SIZE="$1";;
    "-o" | "--out-img" ) shift
           IMG=$1 ;;

    *) ISO=$(realpath $1) ;;
  esac
  shift
done

if [ $(id -un) != root ] ; then
  echo "need root"
  exit ${LINENO}
elif ! [ -f "$ISO" ] ; then
  echo $ISO
  HLP
fi

ISOtoIMG="${ISO%.*}".$IMG_TYPE
IMG=${IMG:-$ISOtoIMG}
mkdir -p $(dirname $IMG)
command -v qemu-img || echo_exit ${LINENO} "qemu-img comman not found"
modprobe nbd max_part=8 || echo_exit ${LINENO} "Cannot insert nbd kernel module"
clear
trap 'clear' EXIT
ISO_ROOT=$(mount_iso)
mk_img "$IMG"
blkdev=$(connect_img "$IMG")
partitions "$blkdev"
# "p" - разделитель между именем устройства и номером раздела. Либо 'p' либо ничего.
# сделал на случай расширения функционала с установкой на /dev/sd??
p=$(ls ${blkdev}*1 |sed -e 's:'$blkdev'::' -e 's/.$//')
OS_ROOT=$(mount_img "$blkdev")
install_OS "$ISO_ROOT" "$OS_ROOT"
post_install "$OS_ROOT" "$blkdev"
