#!/bin/bash

#//////////////////////////////////////#
# Affiche l'aide du script             #
#                                      #
# @stdout Aide d'utilisation du script #
#//////////////////////////////////////#
usage(){
    echo "Usage : $0 <architecture> (i386, amd64)"
}

#/////////////////////////////////////////////////////////////#
# Teste si l'utilisateur est loggué en root ou non            #
#                                                             #
# @return Renvoie 0 si l'utilisateur est root sinon renvoie 1 #
#/////////////////////////////////////////////////////////////#
is_root(){
    if [[ $(id -u) -eq 0 ]]; then
        return 0 ;
    else
        return 1 ;
    fi
}

#///////////////////////////////////////////////////////////#
# Vérifie la présence des programmes utilisés par le script #
#                                                           #
# @return Renvoie 0 si tous les programmes sont présents    #
#///////////////////////////////////////////////////////////#
check_installed_software(){
    if [[ -z $(which ar) || -z $(which genisoimage) || -z $(which wget) || -z $(which tar) || -z $(which zcat) || -z $(which cpio) ]]; then 
        return 1 ;
    else
        return 0 ;
    fi
}

#////////////////////////////////////////////////////////////////////////#
# Télécharge l'image ISO en version netinstall de l'architecture désirée #
#                                                                        #
# @param in $1 Architecture de l'ISO à télécharger                       #
# @stdout Nom du fichier de l'image ISO téléchargée                      #
#////////////////////////////////////////////////////////////////////////#
download_iso_netinstall(){
    local ISO=$(wget -q -O- http://cdimage.debian.org/debian-cd/current/$1/iso-cd/|sed -nr 's/.*(debian.+?netinst.iso).*/\1/p')
    [[ -z $ISO ]] && {
        exit 1
    }
    wget "http://cdimage.debian.org/debian-cd/current/$1/iso-cd/$ISO" -O $ISO
    echo $ISO
}

#////////////////////////////////////////////////////////////////////#
# Extrait les fichiers d'une image ISO dans un répertoire temporaire #
#                                                                    #
# @param in $1 chemin de l'image ISO                                 #
# @stdout Chemin où se trouvent les fichiers extraits                #
#////////////////////////////////////////////////////////////////////#
function extract_files_from_iso(){
    local MOUNT_DIR=$(mktemp -d)
    local ISO_DIR=$(mktemp -du)
    mount -o loop $1 $MOUNT_DIR
    cp -a $MOUNT_DIR $ISO_DIR
    umount $MOUNT_DIR
    rmdir $MOUNT_DIR
    echo $ISO_DIR
}

#/////////////////////////////////////////////////////////////////////////////////////////////#
# Affiche le nom des paquets contenant les derniers firmwares non libres présents dans Debian #
#                                                                                             #
# @stdout Liste des paquets contenant les derniers firmwares non libres                       #
#/////////////////////////////////////////////////////////////////////////////////////////////#
list_firmware(){
    local FIRMWARE_DEB=$(wget -q -O- 'http://ftp.debian.org/debian/pool/non-free/f/firmware-nonfree/?C=N;O=D;V=1;F=0' | sed -nr "s/^<li><a href=\"(.+?\.deb)\".*/\1/p")
    local FIRMWARE_NAME=$(echo "$FIRMWARE_DEB" | cut -f1 -d_ | uniq)
    local NAME
    for NAME in ${FIRMWARE_NAME[@]}; do
        echo "$FIRMWARE_DEB" | grep -m1 "$NAME"_
    done
}

#///////////////////////////////////////////////////////#
# Télécharge et extrait les paquets passés en paramètre #
#                                                       #
# @stdout Répertoire contenant les fichiers extraits    #
#///////////////////////////////////////////////////////#
download_and_extract_firmware(){
    local FIRMWARE_DIR=$(mktemp -d)
    cd $FIRMWARE_DIR

    while [[ $# -gt 0 ]]; do
        wget -q -O $1 "http://ftp.debian.org/debian/pool/non-free/f/firmware-nonfree/$1"
        ar x $1 data.tar.gz
        tar xvf data.tar.gz './lib/firmware' &> /dev/null
        rm $1 data.tar.gz
        shift
    done

    cd $OLDPWD
    echo $FIRMWARE_DIR
}

#///////////////////////////////////////////////////#
# Intègre les firmwares dans les initrd trouvés     #
#                                                   #
# @param $1 Répertoire où se trouvent le(s) initrd  #
# @param $2 Répertoire où se trouvent les firmwares #
#///////////////////////////////////////////////////#
merge_firmware_initrd(){
    local INITRD
    for INITRD in $(find $1 -name initrd.gz); do
        local TMP_DIR=$(mktemp -d)
        cd $TMP_DIR
        zcat $INITRD | cpio -i &> /dev/null
        cp -a $2/lib/firmware .
        find . -print0 | cpio -0 -H newc -o 2> /dev/null | gzip -c > $INITRD
        cd $OLDPWD
        rm -rf $TMP_DIR
    done
}

#////////////////////////////////////////////////////////////////////////////#
# Mise à jour des sommes MD5                                                 #
#                                                                            #
# @param $1 Répertoire où se trouve le fichier de sommes MD5 à mettre à jour #
#////////////////////////////////////////////////////////////////////////////#
update_md5sum(){
    cd $1
    find . -type f ! -name md5sum.txt -exec md5sum {} \; > md5sum.txt
    cd $OLDPWD
}

#/////////////////////////////////////////////////////////////////////////#
# Génère une image ISO à partir d'un répertoire                           #
#                                                                         #
# @param $1 Répertoire contenant les fichiers à intégrer dans l'image ISO #
# @param $2 Chemin vers le fichier à générer                              #
#/////////////////////////////////////////////////////////////////////////#
build_iso_image(){
    genisoimage -no-emul-boot -r -J -boot-load-size 4 -boot-info-table -b isolinux/isolinux.bin -c isolinux/boot.cat -o $2 $1 &> /dev/null
}


#///////////////////////#
# Vérifications de base #
#///////////////////////#
check_installed_software
[[ $? -eq 1 ]] && {
    echo "Certains programmes nécessaires au fonctionnement du script n'ont pas été trouvés." >&2
    exit 1
}

[[ $# < 1 ]] && usage && exit 1
ARCH=$1

! is_root && {
    echo 'Ce script a besoin des droits root !' >&2
    exit 1
}

#///////////////////////////////#
# Téléchargement de l'image ISO #
#///////////////////////////////#
echo "Téléchargement de l'image ISO"
ISO=$(download_iso_netinstall $ARCH)
[[ $? -eq 1 ]] && {
    echo "Erreur : l'image ISO netinstall de l'architecture « $ARCH » n'a pas été trouvée." >&2
    exit 1
}

#/////////////////////#
# On crée l'image ISO #
#/////////////////////#
echo "Extraction des fichiers de l'image ISO"
ISO_DIR=$(extract_files_from_iso $ISO)
echo "Téléchargement des firmwares"
FIRMWARE_DIR=$(download_and_extract_firmware $(list_firmware))
echo "Intégration des firmwares"
merge_firmware_initrd $ISO_DIR $FIRMWARE_DIR
echo "Création de l'image ISO finale"
update_md5sum $ISO_DIR
NEW_ISO=${ISO/./.homemade.}
build_iso_image $ISO_DIR $NEW_ISO
echo "Image ISO originale : $ISO"
echo " Nouvelle image ISO : $NEW_ISO"

#////////////////////////////////////////#
# On nettoie les répertoires temporaires #
#////////////////////////////////////////#
rm -rf $FIRMWARE_DIR $ISO_DIR
