#!/bin/bash

SCRIPT_VERSION="20190811"

###### ZACATEK voleb pro nastaveni uzivatelem
# jmeno disku s kterym se bude pracovat
DISK=sdX

# jmeno LVM VG (pri pripojeni vice instalaci timto skriptem najednou, by stejne jmeno neumoznilo aktivovat vsechna LVM)
LVM_VG="lvm"

# velikost (tretiho) oddilu pro LUKS, pokud se ma pouzit cely zbytek disku uvest 100%
# pokud jen cast uvest napr. 10GB(nasobky 1000) nebo 10GiB(nasobky 1024)
LUKS_SIZE=100%

# velikost EFI oddilu, uvest vzdy s M,MB,G,GB(nasobky 1000) nebo MiB,GiB(nasobky 1024)
EFI_SIZE=512MiB

# velikosti lv oddilu pro system (rootfs), uvest napr. 20GB, pokud se ma pouzit cely LUKS/LVM tak uvest: 100%
ROOTFS_SIZE=20GiB

# velikosti lv oddilu pro /home, uvest napr. 20GB, pokud se nema pouzit nechat za = prazdno (nebo radek zakomentovat znakem #)
HOME_SIZE=20GiB

# velikost oddilu pro var oddil, pokud se nema pouzit nechat za = prazdno (nebo radek zakomentovat znakem #)
VAR_SIZE=20GiB

# velikost oddilu pro swap oddil, pokud se nema pouzit nechat za = prazdno (nebo radek zakomentovat znakem #)
SWAP_SIZE=2GiB

# nove verze *buntu/mint(?) pouzivaji pri instalaci a nevybrani swap oddilu automaticky swap soubor
# pokud je zde uvedene SWAPFILE=no bude swap soubor vcetne nastaveni ze systemu odebran
SWAPFILE=no

# je instalace provadena na SSD, USB Flash nebo SD kartu?
# pokud je zde uvedene FLASH=yes bude pro pripojeni systemoveho oddilu nastaven v fstab parametr noatime
FLASH=yes

# pred vytvorenim LUKS provest nejdrive zaplneni oddilu bordelem pro "zmateni nepritele" ?
# DOPORUCENO pokud na tomto zarizeni nebylo predtim jiz toto provedene...
BORDEL=yes

# varianty rozdeleni/zavadecu, moznosti (je potreba VZDY uvest BOOT=neco_z_toho a JEN jedna z voleb):
# BIOSMBR    - pripravi MBR tabulku s 1 oddil pro LUKS/LVM
# BIOSGPT    - pripravi GPT rozdeleni s 1 oddil pro BIOS, 2 oddil pro LUKS/LVM
# EFI        - pripravi GPT rozdeleni s 1 oddil pro EFI, 2 oddil pro LUKS/LVM
# BIOSGPTEFI - pripravi GPT rozdeleni s 1 oddil pro BIOS, 2 oddil pro EFI, 3 oddil pro LUKS/LVM
BOOT=BIOSGPTEFI

###### KONEC voleb pro nastaveni uzivatelem



# kontrola zda je script pusten pres bash
[ ! "${BASH}" ] && $(which echo) -e "\n${0} script NEbezi pod bash... pust me pomoci: sudo bash $(basename $0)\n" && exit 1

# kontrola zda je script pousten jako root nebo pres sudo
(( EUID )) && echo -e "\n${0} script je potreba pustit jako root nebo pres: sudo bash $(basename $0)\n" && exit 1

# kontrola zda pri zvolenem BOOT rezimu *EFI bezi 64bit instalace
if [[ "$(arch)" != "x86_64" && "${BOOT}" = *EFI* ]]; then echo -e "\n Pro zvoleny BOOT rezim ${BOOT} je potreba 64bit instalacni medium" && exit 1;  fi

# kontrola zda nastaveny disk existuje
[[ ! -b /dev/${DISK} ]] && echo -e "\nNastaveny disk ${DISK} NEexistuje...\n" && exit 1

# prirazeni k nastavenemu disku cisla oddilu pro EFI a LUKS
if [ "${BOOT}" = "BIOSMBR" ]; then
    LUKS_PART="1"
elif [ "${BOOT}" = "BIOSGPT" ]; then
    LUKS_PART="2"
elif [ "${BOOT}" = "EFI" ]; then
    EFI_PART="1"
    LUKS_PART="2"
elif [ "${BOOT}" = "BIOSGPTEFI" ]; then
    EFI_PART="2"
    LUKS_PART="3"
else
    echo -e "\n\nCHYBA: nespravne nastavena volba BOOT je nastaveno: "${BOOT}"\n\tmoznosti jsou: BIOSMBR, BIOSGPT, EFI, BIOSGPTEFI." && exit 1
fi
[[ $EFI_PART ]] && EFI="${DISK}${EFI_PART}"
LUKS="${DISK}${LUKS_PART}"

dotaz_pred_pokracovanim(){
	echo -e "\n Verze skriptu: $(basename ${0}) ${SCRIPT_VERSION}"
	echo -e "\n OPRAVDU CHCETE POKRACOVAT S DISKEM ${DISK} a KOMPLETNE ho SMAZAT???"
        echo -e "\t- rezim rozdeleni/zavadece: ${BOOT}"
	[[ ${EFI_PART} ]] && echo -e "\t- velikost oddilu pro EFI: ${EFI_SIZE}"
	echo -e "\t- velikost oddilu pro LUKS: ${LUKS_SIZE}"
	echo -e "\t- jmeno LVM VG: ${LVM_VG}"
	echo -e "\t\t- velikost LVM LV oddilu pro rootfs: ${ROOTFS_SIZE}"
	[[ ${HOME_SIZE} ]] && echo -e "\t\t- velikost oddilu pro /home: ${HOME_SIZE}" || \
		echo -e "\t\t- velikost oddilu pro /home: NEPOUZITO"
	[[ ${VAR_SIZE} ]] && echo -e "\t\t- velikost oddilu pro /var: ${VAR_SIZE}" || \
		echo -e "\t\t- velikost oddilu pro /var: NEPOUZITO"
	[[ ${SWAP_SIZE} ]] && echo -e "\t\t- velikost oddilu pro swap: ${SWAP_SIZE}" || \
		echo -e "\t\t- velikost oddilu pro swap: NEPOUZITO"
	[[ ${SWAPFILE} = "no" ]] && echo -e "\t- pripadny swap soubor z instalace BUDE odebran" || \
		echo -e "\t- pripadny swap soubor z instalace NEbude odebran"
	[[ ${FLASH} = "yes" ]] && echo -e "\t- instalace na SSD/USBFlash/SD, BUDE nastaven noatime" || \
		echo -e "\t- instalace na HDD, noatime NEbude nastaven"
	echo -e " Informace o disku z parted"
	parted /dev/${DISK} print 2>/dev/null | while read line; do echo -e "\t${line}"; done
	echo -e " POKRACOVAT se bude JEN pokud odpovite 3x za sebou bez mezery ano velkejma pismenama..."
	read odpoved
	[[ ${odpoved} = "ANOANOANO" ]] || exit
}

calc_efi_size(){
    if [ "${EFI_SIZE}" != "" ]; then
        EFI_JED="${EFI_SIZE//[0-9]}"
        EFI_SIZE="${EFI_SIZE/[M,G]*}"
        # kdyz je EFI_SIZE v M, MB, MiB, pricist 2M (neresim 2MiB Vs 2MB), u G,GB,GiB neresim 2M :)
        [[ $EFI_JED = *M* ]] && EFI_SIZE="$((${EFI_SIZE/[M,G,MiG,GiG]}+2))${EFI_JED}" || EFI_SIZE="${EFI_SIZE}${EFI_JED}"
    else
        # vychozi hodnota pokud by se na vrsku v nastavenim omylem zrusila na prazdno, EFI se pocita delat vzdy
        EFI_SIZE="514MiB"
    fi
}

calc_luks_size(){
    if [[ "${LUKS_SIZE}" != *%* ]]; then
        EFI_JED="${EFI_SIZE//[0-9]}"
        EFI_SIZE="${EFI_SIZE/[M,G]*}"
        LUKS_JED="${LUKS_SIZE//[0-9]}"
        LUKS_SIZE="${LUKS_SIZE/[M,G,T]*}"
        if [ "${EFI_JED}" = "${LUKS_JED}" ]; then
            LUKS_SIZE="$((${EFI_SIZE} + ${LUKS_SIZE}))${LUKS_JED}"
        else
            if [ "${EFI_JED}" = "M" -o "${EFI_JED}" = "MB" ]; then EFI_SIZE_B="$(( ${EFI_SIZE} * 1000 * 1000 ))"
            elif [ "${EFI_JED}" = "MiB" ]; then EFI_SIZE_B="$(( ${EFI_SIZE} * 1024 * 1024 ))"
            elif [ "${EFI_JED}" = "G" -o "${EFI_JED}" = "GB" ]; then EFI_SIZE_B="$(( ${EFI_SIZE} * 1000 * 1000 * 1000 ))"
            elif [ "${EFI_JED}" = "GiB" ]; then EFI_JED_B="$(( ${EFI_SIZE} * 1024 * 1024 * 1024 ))"
            fi
            if [ "${LUKS_JED}" = "M" -o "${LUKS_JED}" = "MB" ]; then LUKS_SIZE_B="$(( ${LUKS_SIZE} * 1000 * 1000 ))"
            elif [ "${LUKS_JED}" = "MiB" ]; then LUKS_SIZE_B="$(( ${LUKS_SIZE} * 1024 * 1024 ))"
            elif [ "${LUKS_JED}" = "G" -o "${LUKS_JED}" = "GB" ]; then LUKS_SIZE_B="$(( ${LUKS_SIZE} * 1000 * 1000 * 1000 ))"
            elif [ "${LUKS_JED}" = "GiB" ]; then LUKS_SIZE_B="$(( ${LUKS_SIZE} * 1024 * 1024 * 1024 ))"
            elif [ "${LUKS_JED}" = "T" -o "${LUKS_JED}" = "TB" ]; then LUKS_SIZE_B="$(( ${LUKS_SIZE} * 1000 * 1000 * 1000 * 1000 ))"
            elif [ "${LUKS_JED}" = "TiB" ]; then LUKS_SIZE_B="$(( ${LUKS_SIZE} * 1024 * 1024 * 1024 * 1024 ))"
            fi
            # soucet velikosti v bajtech
            LUKS_SIZE_B="$(( ${EFI_SIZE_B} + ${LUKS_SIZE_B} ))"
            # zaokrouhleni velikosti v bajtech na nasobky 512b)
            LUKS_SIZE="$(( ${LUKS_SIZE_B} / 512 * 512 ))b"
        fi
    fi
}

rozdeleni_disku(){
	echo -e "\n\n\n*** Rozdeleni disku..."
	echo -e "\tPOSLEDNI moznost PRERUSIT PROCES SMAZANI disku ${DISK}..."
	echo -e "\t(POKUD DISK NEBYL ROZDELEN POKRACUJE SE ROVNOU BEZ DOTAZU)"
	grep -q ${DISK} /proc/mounts && umount /dev/${DISK}[1-9]

        if [ "${BOOT}" = "BIOSMBR" ]; then
	    parted /dev/${DISK} mklabel msdos && \
	    parted /dev/${DISK} mkpart primary 0% ${LUKS_SIZE} && \
	    part_detect="$(parted /dev/${DISK} print | grep primary || true)" 
            # na MBR nelze ^^ detekce vytvoreneho LUKS protoze v MBR oddil nelze jmeno, takze detekce jen pritomnosti primarniho oddilu
            # a to  muze byt jen predchozi pozustatek pokud by uzivatel zrusil v predchozim kroku vytvoreni nove/prazdne tabulky oddilu
        elif [ "${BOOT}" = "BIOSGPT" ]; then
	    parted /dev/${DISK} mklabel gpt && \
	    parted /dev/${DISK} mkpart '"BIOS boot partition"' 0% 2M && \
	    parted /dev/${DISK} mkpart LUKS 2M ${LUKS_SIZE} && \
	    parted /dev/${DISK} set 1 bios_grub on && \
	    part_detect="$(parted /dev/${DISK} print | grep -A1 BIOS | grep LUKS || true)"
        elif [ "${BOOT}" = "EFI" ]; then
            [[ $EFI_SIZE ]] || EFI_SIZE="512M"
            calc_luks_size
	    parted /dev/${DISK} mklabel gpt && \
	    parted /dev/${DISK} mkpart '"EFI System Partition"' 0% ${EFI_SIZE} && \
	    parted /dev/${DISK} mkpart LUKS ${EFI_SIZE} ${LUKS_SIZE} && \
	    parted /dev/${DISK} set ${EFI_PART} boot on && \
	    parted /dev/${DISK} set ${EFI_PART} esp on && \
	    part_detect="$(parted /dev/${DISK} print | grep -A1 EFI | grep LUKS || true)"
        elif [ "${BOOT}" = "BIOSGPTEFI" ]; then
            calc_efi_size
            calc_luks_size
	    parted /dev/${DISK} mklabel gpt && \
	    parted /dev/${DISK} mkpart '"BIOS boot partition"' 0% 2M && \
	    parted /dev/${DISK} mkpart '"EFI System Partition"' 2M ${EFI_SIZE} && \
	    parted /dev/${DISK} mkpart LUKS ${EFI_SIZE} ${LUKS_SIZE} && \
	    parted /dev/${DISK} set 1 bios_grub on && \
	    parted /dev/${DISK} set ${EFI_PART} boot on && \
	    parted /dev/${DISK} set ${EFI_PART} esp on && \
	    part_detect="$(parted /dev/${DISK} print | grep -A1 EFI | grep LUKS || true)"
	fi

	[[ ! ${part_detect} ]] && echo -e "Rozdeleni disku nebylo provedeno, koncim..." && exit 1 || true
}

zaplneni_oddilu_pro_luks_bordelem(){
	if [ "${BORDEL}" = "yes" ]; then
		echo -e "\n\n\n*** Vytvareni LUKS bordelu pro \"zmateni nepritele\" na zarizeni ${LUKS}..."
		cryptsetup open --type plain --key-file /dev/random /dev/${LUKS} bordel
		dd bs=1M if=/dev/zero of=/dev/mapper/bordel status=progress
		cryptsetup luksClose bordel
		# zlikvidovat LUKS hlavicku
		dd if=/dev/urandom of=/dev/${LUKS} bs=1M count=10 status=progress
	fi
}

vytvoreni_luks(){
	echo -e "\n\n\n*** Vytvareni LUKS na zarizeni ${LUKS}..."
	### ted jiz vytvoreni finalniho LUKS (mozna nejsou parametry idealni, kdyztak at se nekdo jeste vyjadri)
	cryptsetup --cipher aes-xts-plain64 --key-size 512 --hash sha512 --use-random luksFormat /dev/${LUKS}
        if [ "$?" != "0" ]; then
            echo -e "\nProblem s vytvorenim LUKS, poustim znovu...\n\t(pokud chcete ZRUSIT, zmacknete nekolikrat CTRL+C)"
            sleep 2
            vytvoreni_luks
        fi
}
 
odemknuti_luks(){
	echo -e "\n\n\n*** Odemknuti LUKS oddilu pod nazvem \"luks\"..."
	cryptsetup luksOpen /dev/${LUKS} luks
        if [ ! -b /dev/mapper/luks ]; then
            echo -e "\nNEODEMCENO, zkuste znovu...\n(pokud chcete ZRUSIT, zmacknete nekolikrat CTRL+C)"
            sleep 2
            odemknuti_luks
        fi
}

vytvoreni_lvm(){
	echo -e "\n\n\n*** Vytvareni LVM na zarizeni ${LUKS} odemcenem jako \"luks\"..."
	### vytvareni LVM na odemcenem "luks"
	pvcreate /dev/mapper/luks
	# vytvoreni VG(VolumeGroup) s nazvem "${LVM_VG}"
	vgcreate ${LVM_VG} /dev/mapper/luks
	# vytvoreni LV(LogicalVolume) pro home s nazvem "home"
	[[ ${HOME_SIZE} ]] && lvcreate -L ${HOME_SIZE} -n home ${LVM_VG}
	# vytvoreni LV(LogicalVolume) pro var s nazvem "var"
	[[ ${VAR_SIZE} ]] && lvcreate -L ${VAR_SIZE} -n var ${LVM_VG}
	# vytvoreni LV(LogicalVolume) pro swap s nazvem "swap"
	[[ ${SWAP_SIZE} ]] && lvcreate -L ${SWAP_SIZE} -n swap ${LVM_VG}
	# vytvoreni LV(LogicalVolume) pro rootfs s nazvem "rootfs"
	if [ "${ROOTFS_SIZE}" != "100%" ]; then
            lvcreate -L ${ROOTFS_SIZE} -n rootfs ${LVM_VG}
        else
            lvcreate -l ${ROOTFS_SIZE}FREE -n rootfs ${LVM_VG}
        fi
}

formatovani_disku(){
	echo -e "\n\n\n*** Formatovani oddilu..."

	echo -e "\n - formatuji EFI"
	mkfs.vfat -v -n EFI /dev/${EFI}

	echo -e "\n - formatuji LV rootfs"
	mkfs.ext4 -v /dev/${LVM_VG}/rootfs -L rootfs

	[[ ${HOME_SIZE} ]] && (echo -e "\n - formatuji LV home"; mkfs.ext4 -v /dev/${LVM_VG}/home -L ${LVM_VG}-home)
	[[ ${VAR_SIZE} ]]  && (echo -e "\n - formatuji LV var";  mkfs.ext4 -v /dev/${LVM_VG}/var -L ${LVM_VG}-var; \
                mkdir -p /target; mount /dev/${LVM_VG}/rootfs /target; mkdir -p /target/var; umount -l /target)
	[[ ${SWAP_SIZE} ]] && (echo -e "\n - formatuji LV swap"; mkswap /dev/${LVM_VG}/swap -L ${LVM_VG}-swap)
}

instalace_systemu(){
	echo -e "\n\n\n*** Pousti se Instalace systemu bez GRUB zavadece..."
	echo -e "\tRozdeleni disku zvolit \"Neco jineho\" a dvojklikem vybrat:"
	echo -e "\t/dev/mapper/${LVM_VG}-rootfs, \"Pouzit jako\": Ext4, NEni treba formatovat(resp. pripravene je ext4), pripojnej bod /"
	[[ ${HOME_SIZE} ]] && echo -e "\t/dev/mapper/${LVM_VG}-home, \"Pouzit jako\": Ext4, NEni treba formatovat(resp. pripravene je ext4), pripojnej bod /home"
	[[ ${VAR_SIZE} ]] && echo -e "\t/dev/mapper/${LVM_VG}-var, \"Pouzit jako\": Ext4, NEni treba formatovat(resp. pripravene je ext4), pripojnej bod /var"
	echo -e "\n*** POZOR, po dokonceni instalace NERESTARTOVAT, ale vybrat \"Pokracovat ve zkouseni\" script bude pokracovat"
	ubiquity --no-bootloader
}

priprava_chroot(){
	echo -e "\n\n\n*** Priprava chroot..."
	vgchange -ay
	sleep 5
	### pripojeni ciloveho systemu a systemovych adresaru pokud neni pripojeno
	mountpoint -q /target || mount /dev/${LVM_VG}/rootfs /target
        until [ -d /target/boot ]; do sleep 1; done
	# pripojeni prvniho FAT32 oddilu
	mountpoint -q /target/boot/efi || (mkdir -p /target/boot/efi && mount /dev/${EFI} /target/boot/efi)
	# pripojeni systemovych 
	mountpoint -q /target/dev || mount --bind /dev /target/dev
	mountpoint -q /target/dev/pts || mount -t devpts devpts /target/dev/pts
	mountpoint -q /target/proc || mount -t proc proc /target/proc
	mountpoint -q /target/sys || mount -t sysfs sysfs /target/sys
	[[ ${VAR_SIZE} ]] && (mountpoint -q /target/var || mount /dev/${LVM_VG}/var /target/var)
}

nastaveni_odemknuti_grubem(){
	echo -e "\n\n\n*** Nastaveni GRUBu aby umoznil odemknuti LUKS..."
	### priprava odemknuti grubem
	# pridani parametru GRUBu aby nabidl odemknuti LUKS pri bootu
	echo "GRUB_ENABLE_CRYPTODISK=y" >> /target/etc/default/grub
}

nastaveni_odemknuti_initramfs_automaticky(){
	echo -e "\n\n\n*** Nastaveni initramfs pro automaticke (druhe) odemknuti LUKS..."
	## vytvoreni crypttab s informaci o LUKS
	# zjisteni UUID LUKS oddilu
	LUKS_UUID=$(blkid -s UUID -o value /dev/${LUKS})
	# pridani initramfs automatickeho klice 
	echo "luks UUID=${LUKS_UUID} /crypto_keyfile.bin luks,keyscript=/bin/cat" > /target/etc/crypttab

	# pridani "scriptu" co pri generovani/aktualizaci initramfs bude kopirovat klic do initramfs
	echo -e '#!/bin/sh\ncp /boot/crypto_keyfile.bin "${DESTDIR}"' > /target/etc/initramfs-tools/hooks/crypto_keyfile
	chmod +x /target/etc/initramfs-tools/hooks/crypto_keyfile

	# vytvoreni klice a pridani jako dalsi klic pro LUKS
	dd bs=512 count=4 if=/dev/urandom of=/target/boot/crypto_keyfile.bin
	chmod 000 /target/boot/crypto_keyfile.bin
	echo -e "ZADEJTE HESLO K LUKS ODDILU"
	cryptsetup luksAddKey /dev/${LUKS} /target/boot/crypto_keyfile.bin

	# zamezeni pristupu do /boot (kde je klic) uzivatelum
	chmod -R g-rwx,o-rwx /target/boot
}

chroot_instalace_grub(){
	# nastaveni DNS
	echo "nameserver 8.8.8.8" > /target/etc/resolv.conf
	# instalace GRUBu
        case "${BOOT}" in
            'BIOSMBR'|'BIOSGPT')
                echo -e "\n\n\n*** Instalace GRUB Legacy zavadece (v chroot)..."
                chroot /target grub-install --target=i386-pc /dev/${DISK}
            ;;
            'EFI')
                echo -e "\n\n\n*** Instalace GRUB EFI zavadece (v chroot)..."
                chroot /target apt install --yes grub-efi
                chroot /target grub-install --target=x86_64-efi --removable /dev/${DISK}
            ;;
            'BIOSGPTEFI')
                echo -e "\n\n\n*** Instalace GRUB Legacy a GRUB EFI zavadecu (v chroot)..."
                chroot /target apt install --yes grub-efi
                chroot /target grub-install --target=i386-pc /dev/${DISK}
                chroot /target grub-install --target=x86_64-efi --removable /dev/${DISK}
            ;;
        esac
	chroot /target update-grub
}

chroot_aktualizace_initramfs(){
	echo -e "\n\n\n*** Aktualizace initramfs (v chroot)..."
	# aktualizaci initramfs (ted navic bude obsahoval ten klic a cryptsetup)
	chroot /target update-initramfs -u -k all
}

nastaveni_systemu(){
	echo -e "\n\n\n*** Nastaveni systemu..."
	# pridani parametru noatime pri instalaci na ssd, usb flash, nebo sd kartu
	[[ ${FLASH} = "yes" ]] && sed "/${LVM_VG}-rootfs/s/errors/noatime,errors/" -i /target/etc/fstab
	# odstraneni swap souboru ktery novejsi verze *buntu/mint(?) automaticky vytvareji pri neprirazeni swap oddilu
	[[ ${SWAPFILE} = "no" ]] && (sed '/swapfile/d' -i /target/etc/fstab && rm -f /target/swapfile)
}
 
uklid(){
	echo -e "\n\n\n*** Odpojeni pripojenych oddilu, nemusi se uspesne dokoncit, coz nevadi..."
	# odmontovani
	umount /target/{boot/efi,dev/pts,dev,proc,sys}
	umount --force --lazy /target
	swapoff -a
	sleep 5

	# zavreni LVM (pokud pripojenej rootfs nekde vysi v pouzivani, neprovede se, ale nevadi)
	vgchange -an
 
	# zamknuti LUKS (pokud odemcenej LUKS nekde vysi v pouzivani, neprovede se, ale nevadi)
	cryptsetup luksClose luks

	echo -e "\n\n\n*** Dokonceno, muzete restartovat...."
}

dotaz_pred_pokracovanim

rozdeleni_disku
zaplneni_oddilu_pro_luks_bordelem
vytvoreni_luks
odemknuti_luks
vytvoreni_lvm
formatovani_disku

instalace_systemu

priprava_chroot
nastaveni_odemknuti_grubem
nastaveni_odemknuti_initramfs_automaticky
chroot_instalace_grub
chroot_aktualizace_initramfs

nastaveni_systemu

uklid
