#!/bin/bash
set -e
clear

#***************************************************
#* Funktion: mydebug()                             *
#* ===================                             *
#* Debug-Funktion zum Testen der Argumente, die an *
#* das Shellscript uebergeben werden.              *
#***************************************************
mydebug ()
{
    echo "DEBUG"
    echo "====="
    echo 
    echo "TARGET   = $TARGET"
    echo "CLEAN    = $CLEAN"
    echo "DESTDIR  = $DESTDIR"
    echo "SRC      = $SRC"
    echo "TOOLS    = $TOOLS"
    echo "USER     = $USER"
    echo
    echo "----------------------------------------"
    echo
}


#************************************************************
#* Funktion: usage()                                        *
#* =================                                        *
#* Benutzeranleitung für das Script mkrpi. Wird angewendet, *
#* wenn die Option -h oder eine unzulaessige Option einge-  *
#* geben wird.                                              *
#*                                                          *
#* Optionen:                                                *
#* ---------                                                *
#* Eine Liste der Optionen erhalten Sie mit                 *
#*    sudo ./mkrpi -h                                       *
#************************************************************
usage ()
{
#    clear
    echo $0 $*
    echo
    echo "************************************************************"
    echo "* mkrpi - Script zum Generieren des Raspbian-Kernels.      *"
    echo "*                                                          *"
    echo "* Optionen:                                                *"
    echo "* -a <Adr.> : IP-Adresse oder Hostname des Zielgeraetes.   *"
    echo "* -c        : Clean. Fuehrt make mrproper aus.             *"
    echo "* -d <Verz> : Zielverzeichnis für den Download des Kernel- *"
    echo "*             Sourcecodes und der Tools. Diese werden von  *"
    echo "*             https://www.github.com heruntergeladen.      *"
    echo "* -n        : Numcores. Anzahl der Prozessorkerne.         *"
    echo "* -o        : Aktuelle Konfiguration aus dem Target lesen. *"
    echo "* -p <Pre>  : CCPREFIX fuer die Tools. Der Vorgabewert ist *"
    echo "*             arm-linux-gnueabihf-.                        *"
    echo "* -s        : Der Kernel-Sourcecode wird heruntergeladen.  *"
    echo "* -t        : Wie -s, aber fuer Tools.                     *"
    echo "* -u <User> : User. Der Standarduser ist pi. Es kann aber  *"
    echo "*           : auch ein anderer Name eingetragen werden.    *"
    echo "* -h        : Zeigt diese Meldung an (Usage).              *"
    echo "************************************************************"
    exit 1;
}


#********************************************************
#* Funktion checkoptargs()                              *
#* =======================                              *
#* Prueft die Gueltigkeit von Optionen und Argumenten.  *
#* Wenn das erste Zeichen des angegebenen Arguments ein *
#* "-" ist, so ist dies ein Zeichen fuer ein fehlendes  *
#* fehlendes Argument. Nur Optionen beginnen mit "-".   *
#********************************************************
checkoptargs ()
{
    FIRSTCHAR="$(echo $1 | head -c 1)"  # Auswertung des ersten Zeichens des Arguments
    if [ "$FIRSTCHAR" = "-" ]
    then
        echo "$1 ist kein Argument."
        echo
        usage
    fi
}


#*****************************************************
#* Funktion: isnumber ()                             *
#* =====================                             *
# Prueft, ob ein Wert andere Zeichen als die Ziffern *
# 0...9 enthaelt.                                    *
#*****************************************************
isnumber ()
{
    if [ "$1" -eq "$1" ] 2>/dev/null
    then
        echo
    else
        echo Argument $1 ist keine Zahl.
        usage
        exit 1
    fi
} 
#*************************************************************
#* Funktion change2dir()                                     *
#* =====================                                     *
#* Wechselt in das angegebene Verzeichnis. Das Kommando 'cd' *
#* funktioniert nicht in dem Verzeichnis, aus dem ein Shell- *
#* Sript gestartet wird, da die aktuelle Shell Scripts nur   *
#* in Subshells ausfuehrt.                                   *
#*************************************************************
change2dir()
{
    pushd $1 > /dev/null
}


#*************************************************************
#* Funktion change2startdir()                                *
#* ==========================                                *
#* Wechselt zurueck in das Verzeichnis, aus dem das Script   *
#* gestartet wurde. Begruendung: Siehe Kommentar zu          *
#* change2dir.                                               *
#*************************************************************
change2startdir()
{
    popd > /dev/null
}


#*************************************************************
#* Funktion checkroot()                                      *
#* ====================                                      *
#* Wenn ein Script mit root-Rechten ausgefuehrt werden soll, *
#* dann entfernen Sie bitte die Kommentarzeichen.            *
#*************************************************************
if ! [ $(id -u) = 0 ]; then
   echo "Fehler: Dieses Script muss als root ausgefuehrt werden (sudo voranstellen)."
   exit 1
fi


#***********************************
#* Optionen pruefen und auswerten. *
#***********************************
if [ $# = 0 ]
then
    echo "Keine Optionen verwendet angegeben."
    usage
fi


#**************************************
#* Vorbereitung von Script-Variablen. *
#**************************************
CLEAN=N                         # make mrproper aufrufen (J/N).
TARGET=                         # IP-Adresse oder Hostename des Zielgeraetes.
DESTDIR=.                       # Zielverzeichnis (Stamm) des Kernel-Sourcecodes und der Tools.
SRC=N                           # Legt fest, ob der Kernel-Sourcecode heruntergeladen werden soll.
TOOLS=N                         # Legt fest, ob die Tools heruntergeladen werden sollen.
TCPATH=/opt/toolchain/bin/      # Pfad zur verwendeten Toolchain.
CCPREFIX=arm-linux-gnueabihf-   # Prefix für die Programme der Toolchain

USER=pi                         # Standardbenutzer ist pi.
OLDCONFIG=N                     # Konfiguration aus dem Target auslesen.
NUMCORES=1                      # Anzahl der Prozessorkerne


#***************************************************
#* Anwendung von getopts                           *
#* =====================                           *
#* Kommandozeile: Optionen und Argumente abfragen. *
#***************************************************
while getopts ":a:cd:hn:ostu:" opt
do
    case $opt in
        a) TARGET=$OPTARG
           checkoptargs $TARGET
           ;;
        c) CLEAN=Y
           ;;
        d) DESTDIR=$OPTARG
           checkoptargs $DESTDIR
           ;;
        h) usage
           ;;
        n) NUMCORES=$OPTARG
           checkoptargs $NUMCORES
           isnumber $NUMCORES
           ;;
        o) OLDCONFIG=Y
           ;;
        p) CCPREFIX=$OPTARG
           checkoptargs $CCPREFIX
           ;;
        s) SRC=Y
           ;;
        t) TOOLS=Y
           ;;
        u) USER=$OPTARG
           checkoptargs $USER
           ;;
       \?) echo "Ungueltige Option: -$OPTARG" >&2
           ;;
        :) echo "Option -$OPTARG: Fehlendes Argument. Das Script wird beendet." >&2
           exit 1
           ;;
    esac
done


#*********************************************************
#* Pruefen, ob ein Verzeichnis fuer den Download des     *
#* Kernel-Sourcecode und/oder der Tools angegeben wurde. *
#*********************************************************
checkoptargs $DESTDIR
if [ "${DESTDIR}" == "." ]
then
    echo "DestDir (Source + Tools) = `pwd`." >&2
else
    echo "DestDir (Source + Tools) = ${DESTDIR}." >&2
fi
echo


#*************************************************************************
#* Pruefen, ob das Zielverzeichnis fuer den Kernel-Sourcecode existiert. *
#* Das Verzeichnis wird angelegt, wenn es noch nicht existiert.          *
#*************************************************************************
if [ ! -d ${DESTDIR} ]
then
    mkdir ${DESTDIR}
fi
echo

#*********************************************************
#* Kernel-Sourcecode herunterladen, wenn $DOWNLOAD == Y. *
#* Es wird nur die aktuellste Version geladen.           *
#*********************************************************
if [ $SRC == Y ]
then
    change2dir ${DESTDIR}
    echo "Kernel-Sourcecode wird geholt."
    git clone --depth 1 https://www.github.com/raspberrypi/linux.git
    echo "Download abgeschlossen."
fi
echo

#***************************************************************
#* Tools werden in das angegebene Verzeichnis heruntergeladen, *
#* Wenn das angegebene Verzeichnis nicht existiert, wird es    *
#* erzeugt.                                                    *
#***************************************************************
if [ $TOOLS == Y ]
then
    change2dir ${DESTDIR}
    echo "Tools werden geholt."
    TOOLSDIR=${DESTDIR}
    git clone --depth 1 https://www.github.com/raspberrypi/tools.git
    echo "Download abgeschlossen."
fi
echo
  

#
#----- HIER BEGINNT DER KOMPILIERVORGANG -----
#    

#*****************************************************
#* In das Verzeichnis mit dem Sourcecode wechseln... *
#*****************************************************
change2dir ${DESTDIR}/linux

#*************************************
#* 'make mrproper' ausfuehren (J/N). *
#*************************************
if [ $CLEAN == Y ]
then
    echo
    echo "make mrproper  : Wird ausgefuehrt." >&2
    make mrproper
else
    echo
    echo "make mrproper  : Wird nicht ausgefuehrt." >&2
fi

#*******************************************
#* Versionsinfo aus dem Makefile anzeigen. *
#*******************************************
echo
echo "Aktuelle Kernelversion:"
head -n 3 Makefile
echo
            
#************************************************
#* Aktuelle Konfiguration aus dem Target lesen. *
#************************************************
if [ "$OLDCONFIG" = "Y" ]
then
    echo
    echo "Konfiguration wird aus dem Target gelesen..."
    sudo scp $USER@$TARGET:/proc/config.gz ${DESTDIR}/linux
    echo 
    echo "Konfiguration wird entpackt."
    gunzip -c config.gz > ${DESTDIR}/linux/.config
    ARCH=arm CROSS_COMPILE=${CCPREFIX} make oldconfig
    echo
    echo "Debug-Informationen werden herausgefiltert..."
    grep -v DEBUG_INFO < .config > newconfig
    echo "... und neue Konfiguration wird erzeugt."
    mv newconfig .config
    ARCH=arm CROSS_COMPILE=${CCPREFIX} make oldconfig
fi    

#**************************************************
#* Jetzt wird der Kernel kompiliert. Dies kann    *
#* sehr lange dauern und hängt von der Leistungs- *
#* faehigkeit Ihres PC ab (Anzahl der CPU-Kerne   *
#* und RAM).                                      *
#**************************************************
echo
echo "Kompilierung startet."
ARCH=arm CROSS_COMPILE=${TCPATH}${CCPREFIX} make -j $NUMCORES

#*******************************
#* Erzeugen der Kernelmodule.  *
#*******************************
echo
echo "Kernel-Module werden erzeugt."
ARCH=arm CROSS_COMPILE=${TCPATH}${CCPREDIX} INSTALL_MOD_PATH=../modules make modules_install

#*****************************************************
#* Unkomprimiertes Kernel-Image erzeugen aus zImage. *
#*****************************************************
echo
echo "Komprimiertes Kernel-Image zImage wird dekomprimiert."
change2dir $DESTDIR/tools/mkimage
./imagetool-uncompressed.py $DESTDIR/linux/arch/arm/boot/zImage

#*********************************************
#* Kernel-Image wird zum Target uebertragen. *
#*********************************************
echo "Kernel-Image wird an $TARGET uebertragen."
mv kernel.img kernel_new.img
scp kernel_new.img $USER@$TARGET:/home/$USER/tmp

#*************************************
#* Kernelmodule werden komprimiert.  *
#*************************************
echo
echo "Kernelmodule werden komprimiert."
change2dir $DESTDIR/modules
tar czf modules.tgz *
scp modules.tgz $USER@$TARGET:/home/$USER/tmp

change2startdir

#***************
#* F E R T I G *
#***************
clear
echo "Der neue Kernel ist fertig und befindet sich im Verzeichnis /home/$USER/tmp auf dem Target."
echo "Das Modul-Archiv ist fertig und befindet sich im Verzeichnis /home/$USER/tmp auf dem Target."
echo
echo "Weitere Schritte"
echo "================"
echo "Aendern Sie auf dem Zielsystem (Target) mit chown und chgrp den Besitzer fuer beide Dateien"
echo "nach root, wie im Abschnitt 5.2.2 unter \"Ändern des Besitzers und der Gruppe der übertragenen"
echo "Dateien\" beschrieben. Folgen Sie dann den in den Abschnitten \"Kernel-Image installieren\""
echo "und \"Kernel-Module installieren\" beschriebenen Schritten."

