#!/bin/bash

#    Ikki_USB_Creator.sh - Créer une clé USB bootable avec une partition persistante depuis un fichier iso
#    Copyright (C) 2007-2024  Julien Billard

#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.

#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.

#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <https://www.gnu.org/licenses/>.

# https://ikkiboot.tuxfamily.org
# Version: 2.7 - 29/06/2023

export LANG=C
set -e
label="Data"
script=$0
block_size=4

# Aide
usage() {
cat <<EOF

Usage: $0 -i [Iso] -L [Label]
Options:
  -i	Nom du fichier ISO
  -L	Nom de la partition persistante, par défaut "${label}"
  -t	Nom du périphérique de destination (Expert)
  -b	Taille des blocks en M pour dd, par défaut "${block_size}" (Expert)
  -D	Mode debug
  -h	Affiche ce message
	
Exemples:
  $0 -i Ikki_Boot.iso
  $0 -i Ikki_Boot.iso -L Job
  $0 -i Ikki_Boot.iso -b 10
  $0 -i Ikki_Boot.iso -t /dev/sdX
  $0 -i Ikki_Boot.iso -L Job -b 10
  $0 -i Ikki_Boot.iso -L Job -t /dev/sdX -b 10
	
EOF
}

# Gestion des options
while getopts ":i:L:t:b:Dh" option; do
    case "${option}" in
        i)
			iso=${OPTARG}
			;;
		L)
			label=${OPTARG}
			;;
		t)
			target=${OPTARG}
			;;
		b)
			block_size=${OPTARG}
			;;
	        D)
			set -x
			;;
		h|*)
			usage
			exit 1
			;;
    esac
done

# Vérifie si l'utilisateur est root
if [[ "${UID}" -ne 0 ]]; then
	echo
	echo "[${LOGNAME}] Vous devez exécuter ce script en tant que root."
	echo
	exit 1
fi

# Vérifie si la commande fdisk fonctionne
if ! [[ -x "$(command -v fdisk)" ]]; then
        echo
        echo "Vous devez vous connecter en root avec la commande :"
        echo "su -"
        echo
        exit 1
fi

# Vérifie si un paramètre a été utilisé
if [[ $# -eq 0 ]]; then 
	usage
	exit 1
fi

# Vérifie si l'option -i a été utilisée
if [[ -z "${iso}" ]]; then
	usage
	exit 1
fi

# Vérifie si l'option -b a été utilisée et test la valeur
if [[ -n "${block_size}" ]]; then
	if [[ "${block_size}" -eq "${block_size}" ]] 2>/dev/null ; then
		if [[ "${block_size}" -lt 1 ]] || [[ "${block_size}" -gt 100 ]]; then
			echo
			echo "La taille des blocks doit être comprise en 1 et 100"
			echo
			exit 1
		fi
	else
		echo
		echo "La taille des blocks doit être un entier"
		echo
		exit 1
	fi
fi

# Test si le fichier est un .iso
len=${#iso}
len=$((len-3))
if [[ "${iso:len}" != "iso" ]]; then
	usage
	exit 1
fi

# Vérifie si le fichier ISO existe
if [[ ! -f "${iso}" ]]; then
	echo
    echo "Le fichier ${iso} n'existe pas";
	echo
    exit 1
fi

# Vérifie si le fichier ISO est dans le même répertoire que le script
if [[ $(dirname "${iso}") != $(dirname "${script}") ]]; then
	echo
	echo "Le fichier ISO doit être dans le même répertoire que ce script"
	echo
    exit 1
fi

if [[ -z "${target}" ]]; then
	{
		# Liste les périphériques amovible de type disque
		list_key=$(lsblk -nbdpo NAME,SIZE,TYPE,HOTPLUG | grep -Ev " 0.disk" | grep -E ".disk.*1$")
	} || {
		echo
		echo "Aucune clé USB n'a été détecté"
		echo
		exit 1
	}

	# Nombre de disque amovible détecté
	nbr_word=$(echo "${list_key}" | wc -w)
	nbr_key=$((nbr_word / 4))

	if [[ "${nbr_key}" -eq 1 ]]; then
		target=$(echo "${list_key}" | awk '{print $1}')
		target_space=$(echo "${list_key}" | awk '{print $2}')
		echo
		echo "Une clé USB a été détectée :"

		lsblk -dpo MODEL,NAME,SIZE | grep -E "${target}"
		echo
		while [[ "${confirmation}" != "o" ]] && [[ "${confirmation}" != "n" ]] ; do
			read -rp "Confirmez-vous l'utilisation de cette clé o/n ? " confirmation
		done
	elif [[ "${nbr_key}" -gt 1 ]]; then
		echo
		echo "Plusieurs clés USB ont été détectées :"
		echo
		lsblk -dpo MODEL,NAME,SIZE,TYPE,HOTPLUG | grep -Ev " 0.?.disk" | grep -E ".disk.*1$" | rev | cut -d ' ' -f3- | rev | sed s/disk//g
		echo
		echo "Une seule clé USB doit être branchée"
		echo
		exit 1
	fi
	
else
	#T est $target
	{
		list_key=$(lsblk -nbdpo NAME,SIZE,TYPE,HOTPLUG | grep -E "${target}.*disk.*1$")
	} || {
		echo
		echo "Le périphérique de destination ${target} n'est pas amovible"
		echo
		exit 1
	}
	echo
	echo "Périphérique de destination :"
	lsblk -dpo MODEL,NAME,SIZE | grep -E "${target}"
	target_space=$(echo "${list_key}" | awk '{print $2}')
	echo
	while [[ "${confirmation}" != "o" ]] && [[ "${confirmation}" != "n" ]] ; do
		read -rp "Confirmez-vous l'utilisation de cette clé o/n ? " confirmation
	done
	
fi

if [[ "${confirmation}" = "n" ]]; then
	exit 1
fi

# Vérifie si la clé est en cours d'utilisation
target_use=$(mount | grep "${target}" | awk '{print $3}')
if [[ -n "${target_use}" ]]; then
	echo
	echo "La clé USB est actuellement utilisé dans :"
	echo "${target_use}"
	echo
	echo "Démontez la clé USB et relancez le script"
	exit 1
fi

iso_space=$(du -b "${iso}" | awk '{print $1}')

# Vérifie la taille de la clé par rapport au fichier ISO
if [[ "${iso_space}" -gt "${target_space}" ]]; then
	echo
	echo "Une clé d'une plus grande capacité est nécessaire pour ce fichier ISO"
	echo
	exit 1
fi

# On écrit l'image ISO sur la clé USB
target_space=$((target_space/1024/1024/1024))

while [[ "${confirmation}" != "OUI" ]] && [[ "${confirmation}" != "NON" ]] ; do
	echo
	read -rp "Etes-vous sûr de vouloir effacer le disque ${target} de ${target_space} Go (OUI/NON) : " confirmation
done
if [[ "${confirmation}" == "OUI" ]] ; then
	echo
	echo "1) Ecriture de l'image ISO sur la clé"
	echo
	echo "dd if=${iso} of=${target} bs=${block_size}M status=progress && sync" 
	dd if="${iso}" of="${target}" bs="${block_size}"M status=progress && sync
else
	exit 1
fi
sleep 5
echo
echo "2) Création de la partition exFAT sur ${target}"

# Test du nombre de partition
count_part=$(lsblk "${target}" | wc -l)
list_count_part=$((count_part - 2))

if [[ "${list_count_part}" -eq 3 ]] ; then
	# On supprime la 3ème partition
	(
	echo d                  # Del partition
	echo 3                  # Partition number
	echo w                  # Write changes
	) | fdisk "${target}"
fi
	# On créé la partition exFAT
	(
	echo n                  # Add a new partition
	echo p                  # Primary partition
	echo 3			# Partition number
	echo                    # First sector (Accept default)
	echo                    # Last sector (Accept default)
	echo t 			# Type
	echo 3		 	# Partition number
	echo 7 			# exFAT
	sleep 5 || true
	echo w                  # Write changes
	echo q                  # Quit
	) | fdisk "${target}"

# On attend que la 3ème partition soit détectée
until fdisk -l | grep "${target}"3 1> /dev/null
do
  sleep 1
done

# Formatage de la partition en exFAT
mkfs.exfat -L "${label}" -c 4096 "${target}"3
sync

echo
echo "La clé USB a été créé avec succès"
echo
