#!/bin/bash
# Для запуска в консоли нужно передать - cli,
# для запуска с oem-install.py  - gui

p=''
EFISIZE=100 #MiB
SWAPSIZE=500 #MiB
REWRITE="\e[25D\e[1A\e[K"
PATH="/sbin:/usr/sbin:$PATH"
CFG="/run/initramfs/live/oem-install.cfg"
KS="/run/initramfs/live/anaconda-ks.cfg"
FSTAB=""
PARTITIONS='auto' # (btrfs, std, auto)
ROOTSIZE=''

HLP(){
  echo "
  $0 - utility to installing Rosa distros from an image cloned to the disk to the same disk

  $0 cli - start instalation from root terminal
  $0 gui - do not use formatting stdout for console

  Config file: $CFG

  Available config parameters:

  PARTITONS=auto (btrfs, std)
      std -  common root partition (ext4)
      auto - add partiton (ext4) for home, if disk size greater then 100Gib
      btrfs - common partiton (btrfs), subvolumes for / (root) and for /home
  ROOTSIZE=''
      size for root partition MiB, auto setup if empty
  SWAPSIZE=1000
      size for swap MiB, set -0 (zero), to disable swap partition creation
  EFISIZE=100
      size for EFI partiton MiB
  "
  exit
}

echo_run() {
    echo "==> run: $@"
    $@
}

sync_timer() {
  local MARKERS
  (: > /tmp/checksync ; sync ; rm -f /tmp/checksync) &
  MARKERS="/proc/$! /tmp/checksync"
  sek=0
  echo "wait..."
  while true; do
    BREAK="yes"
    echo -e "${REWRITE}==> sync time: ${sek}"
    for a in $MARKERS ; do
      [ -e $a ] && BREAK=no
    done
    [ "$BREAK" == "yes" ] && break
    sleep 1
    sek=$(($sek + 1))
  done
  echo -e "${REWRITE}"
}

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

echo_exit() {
  clear
  echo -e "ERROR: $2 # line: $1" 1>&2
  echo -e '\n:(' 1>&2
  exit $1
}

clear(){
  echo "==> Clear" 1>&2
  sync
  umount /mnt/sysroot/boot/efi || umount -l /mnt/sysroot/boot/efi
  umount /mnt/sysroot || umount -l /mnt/sysroot
  umount /mnt/sysimage  || umount -l /mnt/sysimage
  for a in 3 4 5  ; do
    losetup -D /dev/loop$a
  done
  rm -f /run/oem-install
}

partitions(){
  local dev=$1
  echo "==> partitions" 1>&2
  for a in $(seq 2 $(parted -m $dev print |tail -n1 |cut -f1 -d ':')) ; do
    echo_run parted -s "$dev" rm "$a"
  done
  partprobe $dev
  echo_run parted -s "$dev" set 1 boot off
  ISOSIZE=$(parted -m $dev unit MiB print | grep '^1:.*' |cut -f3 -d ':' | sed 's/MiB$//')
  if [ $ROOTSIZE ] ; then
    HOMESIZE=$(( "$DEVSIZE" - "$ISOSIZE" - "$EFISIZE" - "ROOTSIZE" - "$SWAPSIZE" - 10 ))
  else
    ROOTSIZE=$(( "$DEVSIZE" - "$ISOSIZE" - "$EFISIZE" - "$SWAPSIZE" - 10 ))
  fi
  for a in DEVSIZE PARTITIONS SWAPSIZE ROOTSIZE EFISIZE HOMESIZE ISOSIZE TABLE; do
    eval echo "${a}: \$$a"
  done
  if ! [ "$GUI" ] ; then
    echo "ENTER to continue, ctrl+c to abort"
    read qqq
  fi
  EFILABEL=primary
  ROOTLABEL=primary
  SWAPLABEL=primary

  if [ $TABLE == 'gpt' ] ; then
    EFILABEL=EFI
    ROOTLABEL=ROSA_SYSTEM
    SWAPLABEL=ROSA_SWAP
    HOMELABEL=ROSA_HOME
  fi
  echo_run parted  -a optimal -s "$dev"  mkpart $EFILABEL  \
    $(( $ISOSIZE +1 ))MiB  $(( $ISOSIZE + 1 + $EFISIZE))MiB set 2 esp on
  echo_run parted  -a optimal -s "$dev"  mkpart $ROOTLABEL \
    $(( $ISOSIZE + 1 + $EFISIZE + 1))MiB $(( $ISOSIZE + 1 + $EFISIZE + 1 + $ROOTSIZE))MiB

  if [ "$HOMESIZE" ] ; then
    if [ "$SWAPSIZE" -ne 0 ] ; then
      echo_run parted  -a optimal -s "$dev"  mkpart $HOMELABEL \
        $(( $ISOSIZE + 1 + $EFISIZE + 1 + $ROOTSIZE + 1))MiB \
        $(( $ISOSIZE + 1 + $EFISIZE + 1 + $ROOTSIZE + 1 + $HOMESIZE))MiB
      echo_run parted  -a optimal -s "$dev"  mkpart $SWAPLABEL \
        $(( $ISOSIZE + 1 + $EFISIZE + 1 + $ROOTSIZE + 1 + $HOMESIZE + 1 ))MiB 100%
    else
      echo_run parted  -a optimal -s "$dev"  mkpart $HOMELABEL \
        $(( $ISOSIZE + 1 + $EFISIZE + 1 + $ROOTSIZE + 1))MiB 100%
    fi
  else
    [ "$SWAPSIZE" -ne 0 ] && echo_run parted  -a optimal -s "$dev"  mkpart $SWAPLABEL \
      $(( $ISOSIZE + 1 + $EFISIZE + 1 + $ROOTSIZE + 1))MiB 100%
  fi
  partprobe $dev
}

mount_iso(){
  [ -e /mnt/sysimage/bin/bash ] && return
  mkdir -p /mnt/sysimage
  mount /dev/mapper/live-base /mnt/sysimage
}

mount_sysroot (){
  mkdir -p /mnt/sysroot
  loop_efi=$(losetup -f)
  losetup $loop_efi ${dev}${p}2                           || echo_exit ${LINENO} "losetup partition"
  loop_root=$(losetup -f)
  losetup $loop_root ${dev}${p}3                          || echo_exit ${LINENO} "losetup partition"
  yes | mkfs.vfat $loop_efi                               || echo_exit ${LINENO} "make FS"
  yes | mkfs.ext4  -E nodiscard -L ROSA_SYSTEM $loop_root || echo_exit ${LINENO} "make FS"
  mount $loop_root /mnt/sysroot                           || echo_exit ${LINENO} "mount sysroot"
  rm -rf /mnt/sysroot/*
  mkdir -p /mnt/sysroot/boot/efi
  rm -rf /mnt/sysroot/boot/efi/*
  mount $loop_efi /mnt/sysroot/boot/efi                   || echo_exit ${LINENO} "mount sysroot"
  FSTAB="# set by oem-install
LABEL=ROSA_SYSTEM /    ext4 rw 0 0
"
  if [ "$SWAPSIZE" -ne 0 ] ; then
    loop_swap=$(losetup -f)
    losetup $loop_swap ${dev}${p}4
    mkswap -L ROSA_SWAP $loop_swap
    swapon -L ROSA_SWAP
    FSTAB="$FSTAB
LABEL=ROSA_SWAP   none swap sw 0 0
"
  fi
}

mount_sysroot_home (){
  mkdir -p /mnt/sysroot
  loop_efi=$(losetup -f)
  losetup $loop_efi ${dev}${p}2                           || echo_exit ${LINENO} "losetup partition"
  loop_root=$(losetup -f)
  losetup $loop_root ${dev}${p}3                          || echo_exit ${LINENO} "losetup partition"
  loop_home=$(losetup -f)
  losetup $loop_home ${dev}${p}4                          || echo_exit ${LINENO} "losetup partition"
  yes | mkfs.vfat $loop_efi                               || echo_exit ${LINENO} "make FS"
  yes | mkfs.ext4  -E nodiscard -L ROSA_SYSTEM $loop_root || echo_exit ${LINENO} "make FS"
  yes | mkfs.ext4  -E nodiscard -L ROSA_HOME $loop_home   || echo_exit ${LINENO} "make FS"
  mount $loop_root /mnt/sysroot                           || echo_exit ${LINENO} "mount sysroot"
  rm -rf /mnt/sysroot/*
  mkdir -p /mnt/sysroot/boot/efi
  rm -rf /mnt/sysroot/boot/efi/*
  mount $loop_efi /mnt/sysroot/boot/efi                   || echo_exit ${LINENO} "mount sysroot"
  mkdir -p /mnt/sysroot/home
  mount $loop_home /mnt/sysroot/home                      || echo_exit ${LINENO} "mount sysroot"
  FSTAB="# set by oem-install
LABEL=ROSA_SYSTEM /        ext4  rw 0 0
LABEL=ROSA_HOME   /home    ext4  rw 0 0
"
  if [ "$SWAPSIZE" -ne 0 ] ; then
    loop_swap=$(losetup -f)
    losetup $loop_swap ${dev}${p}5
    mkswap -L ROSA_SWAP $loop_swap
    swapon -L ROSA_SWAP
    FSTAB="$FSTAB
LABEL=ROSA_SWAP   none     swap sw 0 0
"
  fi
}

mount_sysroot_btrfs (){
  mkdir -p /mnt/sysroot
  loop_efi=$(losetup -f)
  losetup $loop_efi ${dev}${p}2                              || echo_exit ${LINENO} "losetup partition"
  loop_root=$(losetup -f)
  losetup $loop_root ${dev}${p}3                             || echo_exit ${LINENO} "losetup partition"
  loop_swap=$(losetup -f)
  losetup $loop_swap ${dev}${p}4                             || echo_exit ${LINENO} "losetup partition"
  yes | mkfs.vfat $loop_efi                                  || echo_exit ${LINENO} "make FS"
  yes | mkfs.btrfs  --nodiscard -f -L ROSA_SYSTEM $loop_root || echo_exit ${LINENO} "make FS"
  mkdir /tmp/btrfs_root
  mount $loop_root /tmp/btrfs_root                           || echo_exit ${LINENO} "subvol create"
  btrfs subvolume create  /tmp/btrfs_root/root               || echo_exit ${LINENO} "subvol create"
  btrfs subvolume create  /tmp/btrfs_root/home               || echo_exit ${LINENO} "subvol create"
  umount /tmp/btrfs_root ; rmdir /tmp/btrfs_root
  mkswap -L ROSA_SWAP $loop_swap
  mount  -o subvol=/root $loop_root /mnt/sysroot             || echo_exit ${LINENO} "mount sysroot"
  rm -rf /mnt/sysroot/*
  mkdir -p /mnt/sysroot/home
  mount  -o subvol=/home $loop_root /mnt/sysroot/home        || echo_exit ${LINENO} "mount sysroot"
  rm -rf /mnt/sysroot/home/*
  mkdir -p /mnt/sysroot/boot/efi
  mount $loop_efi /mnt/sysroot/boot/efi                      || echo_exit ${LINENO} "mount sysroot"
  rm -rf /mnt/sysroot/boot/efi/*
  swapon -L ROSA_SWAP

  FSTAB="# set by oem-install
LABEL=ROSA_SYSTEM /     btrfs subvol=root 0 0
LABEL=ROSA_SYSTEM /home btrfs subvol=home 0 0
LABEL=ROSA_SWAP   none  swap  sw          0 0
"
}

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

post_install(){
  echo "==> post_install" 1>&2
  cat <<EOF >> ${1}/init_OS.sh
#!/bin/sh
source /etc/locale.conf
[ \$LANG ] || LANG="ru_RU.UTF-8"
export LANG
export LANGUAGE=\$LANG
export LC_ALL=\$LANG

dd if=/dev/random bs=64 count=1 2>/dev/null |md5sum | cut -f1 -d ' ' >/etc/machine-id
mkdir -p /var/log/anaconda

cat /usr/share/anaconda/post-scripts/90-rosa1-postinstall.ks |sed '/^%.*$/d' |bash

systemctl enable initial-setup.service

# перечисленные тут модули нужны
grub2-install --target=x86_64-efi --modules "echo part_gpt ext2"
update-grub2

: > /boot/grub2/oem-install.sgn

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

exit 0
EOF

# пункт в конфиг граба для запуска переустановки
  cat <<EOF >>  ${1}/etc/grub.d/40_oem-install
#!/bin/sh
set -e
export TEXTDOMAIN=grub
export TEXTDOMAINDIR="\${datarootdir}/locale"
cdlabel=\$(blkid -s LABEL -o value -t TYPE=iso9660)
echo "
if search --no-floppy --file /ROSA-LIVE.sgn ; then
menuentry 'Return to a factory settings' {
    search --no-floppy --file /ROSA-LIVE.sgn --set=iso
    lang=\$(echo \$LANG |cut -f1 -d '.')
    lang_utf=\$LANG
    linux (\\\$iso)/vmlinuz0 root=live:LABEL=\$cdlabel ro rd.live.image quiet  oem.install rhgb rhgb splash=silent logo.nologo  inst.lang=\\\$lang_utf locale.LANG=\\\$lang_utf locale.LANGUAGE=\\\$lang_utf
        echo "\\\$loading /vmlinuz0..."
    initrd (\\\$iso)/initrd0.img
        echo "\\\$loading /initrd0.img..."
}
fi
"
EOF
  chmod +x ${1}/etc/grub.d/40_oem-install

  echo "LANG=$LANG" > ${1}/etc/locale.conf
  [ "$PARTITIONS" == 'btrfs' ] && sed -i 's/^GRUB_SAVEDEF.*/GRUB_SAVEDEFAULT=false/' "${1}/etc/default/grub"

  BINDS=$(for a in $(seq $(ls ${dev}${p}[1-9] |wc -l)) ; do
  echo -n "--bind=${dev}${p}${a} --bind=/dev/loop$(( $a + 1 )) "
  done)
  chmod +x ${1}/init_OS.sh
  echo_run systemd-nspawn -D ${1} $BINDS --bind="/dev/disk/" --bind="/sys/firmware/efi/efivars" /init_OS.sh || \
                                                               echo_exit ${LINENO} "post install chroot actions"

# ks файл, который генерируется при установке анакондой
  if [ -f "$KS" ] ; then
    cp "$KS" ${1}/root/
  else
  layouts=$( cat /etc/X11/xorg.conf.d/00-keyboard.conf |
    grep XkbLayout |awk '{print $3}' |sed -e 's/,/","/' -e "s/\"/\'/g")
  [ -z "$layouts" ] && layouts="'us'"
  cat <<EOF >>  ${1}/root/anaconda-ks.cfg
graphical
keyboard --vckeymap=ru --xlayouts=$layouts --switch='grp:alt_shift_toggle'
lang $LANG
selinux --disabled
firstboot --enable
autopart --noboot
clearpart --none --initlabel
timezone Europe/Moscow --utc
rootpw --lock
network --hostname=$(hostname)
EOF
  fi

# для initial-setup
  cat <<EOF > ${1}/etc/initial-setup/conf.d/10-eula.conf
[License]
eula = /usr/share/licenses/rosa-distro/license_${LANG:0:2}.txt
EOF
# временный костыль нужно исправить в пакете initial-setup-gui
  rm -f ${1}/usr/lib/python3.8/site-packages/initial_setup/gui/spokes/__pycache__/eula*
  rm -f ${1}/usr/lib/python3.8/site-packages/initial_setup/gui/spokes/eula*

# временный костыль для споука с паролем рута, лучше нормально запатчить
  cat <<EOF >>  ${1}/$(rpm --eval %python3_sitearch)/pyanaconda/ui/gui/spokes/root_password.py
    @classmethod
    def should_run(cls, environment, data):
        return True
EOF

  echo "$FSTAB" > ${1}/etc/fstab

}

# main
if [ "$1" -a "$1" == 'gui' ] ; then
    REWRITE=""
    GUI='yes'
elif [ ! "$1" -o "$1" != 'cli' ] ; then
    HLP
fi

[ $(id -un) != root ] && echo_exit ${LINENO} "need root"

dev=$(blkid -t TYPE=iso9660 |sed 's/[[:digit:]]\+:.*//')

[ $(echo "$dev" |wc -l) -gt 1 ] && \
  echo_exit ${LINENO} "More than one iso9660 partitions found:\n$dev"

[ -f /run/oem-install ] && \
  echo_exit ${LINENO} "Lock file found, created by previous $0 process."

: > /run/oem-install

# "P" is a separator between device name and partition number for nvme
if [ "${dev:(-1)}" == 'p' ] ; then
    dev=${dev::${#dev}-1}
    p='p'
fi

TABLE=gpt
gdisk -l "$dev" |grep 'GPT:.*not.*present' 2>/dev/null && TABLE='mbr'
# Если gpt, записать в таблицу реальный размер диска вместо размера исо
if [ "$TABLE" == 'gpt' ] ; then
  echo -e "x\ne\nw\ny\n" |gdisk "$dev"
  partprobe "$dev"
fi

DEVSIZE=$(parted -m $dev unit MiB print | grep '^/dev/.*' |cut -f2 -d ':' | sed 's/MiB$//')

# Если диск больше 100Gb считаем, что это не тестовыя установка, а боевая
if [ "$DEVSIZE" -gt 100000 ] ; then
  # SWAP = RAM * 2
  RAM_Mb=$(( $(cat /proc/meminfo |sed -n '/MemTotal/s/\(MemTotal:[[:space:]]\+\)\([[:digit:]]\+\)\(.*\)/\2/p') /1000 ))
  SWAPSIZE=$(( "$RAM_Mb" * 2 ))
  # Размер системного раздела - треть от размера диска без свопа, но не больше 100Gb
  ROOTSIZE=$(( ("$DEVSIZE" - "$SWAPSIZE") / 3 ))
  [ "$ROOTSIZE" -gt 100000] && ROOTSIZE=100000 #MiB
fi

blkid |grep -q MOS && PARTITIONS='btrfs'
[ -f "$CFG" ] && source "$CFG"

# отключаем создание отдельного раздела /home когда не нужен
[ "$PARTITIONS" == 'btrfs' -o "$PARTITIONS" == 'std' ] && ROOTSIZE=''

trap 'clear' EXIT

partitions "$dev"
if [ "$PARTITIONS" == 'btrfs' ] ; then
  mount_sysroot_btrfs
elif [ "$HOMESIZE" ] ; then
  mount_sysroot_home
else
  mount_sysroot
fi

mount_iso
install_OS /mnt/sysimage /mnt/sysroot
post_install /mnt/sysroot "$dev"
sync_timer

if [ "$GUI" ] ; then
  exit 0
else
  echo "Instalation finished, see /mnt/sysroot
ENTER to unmount all new partitions and exit."
  read qqq
fi
