#!/bin/bash

version="1.5.2"

function license_notice {
echo "                 Hello $(whoami) ($UID) @ $HOSTNAME"
cat << EOF

    Noyau (french word for kernel) v$version, written by RIQUER Vincent.
    It's part of the Labapus (Linux Administration Bash And Perl Scripts)
    Project.

    Noyau v$version is aimed to ease the compilation of the Linux kernel.
    Copyright (C) 2002  RIQUER "script.fan" Vincent <script.fan@free.fr>

    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 2 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, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

EOF
}

# New experimental code using getopts
args="$@"

# Credits to Christophe Blaess 
# Code directly taken from his excellent book "Langages de scripts sous Linux"
# edited by Eyrolles
while getopts "d:e:cbminpkv-:" opt ; do
  case $opt in c) task=conf ; echo "-c -> Configure, compile, install" ;;
               b) task=comp ; echo "-b -> Compile, install" ;;
	       m) task=mod ; echo "-m -> Add modules" ;;
	       i) task=inst ; echo "-i -> Install" ;;
	       e) EDITOR=$OPTARG ; echo "-e -> editor : $EDITOR" ;;
	       d) sources=$OPTARG ; echo "-d -> Sources : $sources" ;;
	       p) pretend=0 ; #echo -e "-p doesn't work for the time being...\n                                     Sorry" ; exit 1 ;; 
	          echo "-p -> Virtual mode : don't do anything, only print what would have been done" ;;
	       v) verbose=0 ; echo "-v -> Verbose" ;;
	       n) no_license_notice=0 ;; # Yes, this is a undocumented option
	       				 # to prevent our script from printing
					 # its license 2 times when  launched
					 # as user and using the su capability
					 
	       k) use_proc=0; echo "-k -> use /proc/config.gz" ;;
	       -) case $OPTARG in
	                          no-color) color=0
				        echo "--no-color -> black/white output"
							   ;;
				  text) compile=config 
				        echo "--text -> make config" ;;
				  menu) compile=menuconfig
				        echo "--menu -> make menuconfig" ;;
				  x) compile=xconfig
				     echo "--x -> make xconfig" ;;
				  help) cat << EOF
usage : -c : configure, then build, then install
        -b : build, then install
	-m : add modules to a previously installed kernel
	-i : install an already compiled kernel

	-k : use /proc/config.gz instead of /root/saved-config. Falls back on 
	     /root/saved-config if CONFIG_IKCONFIG_PROC is not set in your 
	     kernel.

	-e <editor> : specify your preferred text editor (you may have to edit
	              the config file for your boot loader (default : \$EDITOR
		      or vim)

	-d <directory> : specify a path for kernel sources (default : 
	                 /usr/src/linux). 

	--no-color : disable colored output
	--text : configure using make config
	--menu : configure using make menuconfig
	--x : configure using make xconfig

	-p : don't do anything (for devs and testers) [  these two might  ]
	-v : verbose mode                             [ need some testing ]

	--help : you guessed ;)

EOF
                                  exit 0 ;;
                  esac
  esac
done
sleep 1 ; clear # clear getopts debugging messages after 1 sec

if [ $no_license_notice ]; then
  echo "Your UID is $UID, you are $(whoami) on $HOSTNAME";
else
  license_notice;
fi;

# If $EDITOR is set neither by command line option nor environment, default to
# vim <troll> MY preferred text editor... nano is fine too ;) </troll>
if [[ $EDITOR == "" ]]; then
  EDITOR='vim';
fi

################################################################################
#                          Function declarations                               #
################################################################################

if [ $color ]; then
  function color { # We do not want colored output so we make color a dummy
    a=a		   # function
  }
else
  function color {
    setterm $@
  }
fi

function error { # This is called when any important command called by the
  set +x         # script fails
  echo $'\a'
  color -background red
  cat << EOF


Exit status of the previously executed command wasn't 0. This means there
probably  was  an  error. To  prevent  undesired effects,  I stop  when a
command returns a non-zero status.

Hope you'll be able to resolve the problem, Bye !
EOF
  color -background black
  echo -e "\n"
  exit 1
}

function execute {                 # By using this function as a wrapper, we
  if [ $pretend ]; then            # are able to work in normal, verbose, or
    echo -e "\n [not executed] $@" # don't-do-anything modes
    read -p "[ press return ]"
  elif [ $verbose ];then
    echo " + $@"
    bash -c "$@" || error
  else
    bash -c "$@" || error
  fi
}

function root {
  read -n 1 -p "Do you want to start a su session now ? [y/n]  "
  echo ""
  case $REPLY in
    'y')
      su -c "$0 -n $args"
      ;;
    'n')
      exit 1
      ;;
    *)
      root
      ;;
  esac
  exit
}

function whattodo {
  cat << EOF
What do you want me to do ?
  1) Configure, compile and install
  2) Compile and install
  3) Add / remove modules
  4) Install only

EOF
  read -n 1
  case $REPLY in
    '1')
      task=conf
      ;;
    '2')
      task=comp
      ;;
    '3')
      task=mod
      ;;
    '4')
      task=inst
      ;;
    *)
      whattodo
      ;;
  esac
  echo ""
}

function usage {
  cat << EOF
  t - text - for configuration in text mode without ncurses             (config)
  m - menu - for a nice ncurses text mode menu configuration        (menuconfig)
  X - X11  - for a fully graphical configuration. X has to be started. (xconfig)

EOF
  read -n 1 -p "Pick one [t/m/X] : "
  case $REPLY in
    't')
      compile=config
      ;;
    'm')
      compile=menuconfig
      ;;
    'X')
      compile=xconfig
      ;;
    *)
      echo ""
      usage
      ;;
  esac

  echo ""
}

function source_dir {
  cat << EOF
Your kernel sources are not in /usr/src/linux. You should at least have
a symbolic link /usr/src/linux pointing to the sources of the kernel you want
to compile and use, or else you'll have troubles each time you'll try to
compile anything.

I can help you create a symlink to your source directory
EOF
  read -p "Where are the unpacked kernel sources ? "
  echo ""
  if [ -d $REPLY ]; then
    sources=$REPLY;
  else
    source_dir
  fi
}

function edit_xtraver {
  XTRVER=$(cat $sources/Makefile | grep -x "EXTRAVERSION = .*")
  XTRVER=${XTRVER#*= }
  read -n 1 -p "The kernel extraversion is now set to \"$XTRVER\". Do you want to change it ? [y/n]  "
  echo
  case $REPLY in
    'y')
      read -p "What do you want to change this for ?  "
      echo
      execute "sed -e s/EXTRAVERSION\ =\ *$XTRVER/EXTRAVERSION\ =\ $REPLY/ $sources/Makefile > Makefile.tmp"
      execute "mv -f Makefile.tmp $sources/Makefile"
      edit_xtraver
      ;;
    'n')
      ;;
    *)
      edit_xtraver
      ;;
  esac
}

function kernel_version {
  echo "Checking version of $sources..."
  if [ -r $sources/Makefile ]; then
    MAJVER=$(cat $sources/Makefile | grep -x "VERSION = .*")
    export MAJVER=${MAJVER#*= }
    PTCHVER=$(cat $sources/Makefile | grep -x "PATCHLEVEL = .*")
    export PTCHVER=${PTCHVER#*= }
    SUBLEV=$(cat $sources/Makefile | grep -x "SUBLEVEL = .*")
    export SUBLEV=${SUBLEV#*= }
    XTRVER=$(cat $sources/Makefile | grep -x "EXTRAVERSION = .*")
    export XTRVER=${XTRVER#*= }
    export kversion="$MAJVER.$PTCHVER.$SUBLEV$XTRVER"
  fi
  if [ $? == 0 ]; then
    read -n 1 -p "The version of the kernel in $sources is $kversion. Is this OK ? [y/n]  "
    echo ""
    case $REPLY in
      'y')
        ;;
      'n')
        echo "Argh !"
        function choose_again {
          read -n 1 -p "Do you want to choose another one ? [y/n]  "
          echo
          case $REPLY in
            'y')
              source_dir
#	      kernel_version
              ;;
            'n')
              exit 1
              ;;
            *)
              choose_again
              ;;
          esac
        }
        choose_again
        ;;
      *)
        kernel_version
        ;;
    esac
    edit_xtraver;
  else
    echo "$sources doesn't contain the kernel sources"
    source_dir
  fi
}

function symlink {
  echo "Do you want me to create a symlink (/usr/src/linux) pointing to $sources ?"
  read -n 1 -p "[y/n]  "
  echo ""
  case $REPLY in
    'y')
      execute "ln -s $sources /usr/src/linux"
      ;;
    'n')
      ;;
    *)
      symlink
      ;;
  esac      
}

function clean_confirm {
  if [ -f $sources/.config ]; then
    cat << EOF
I'm  going to clean the source directory (make mrproper),  but I found a .config
file  in it.  This  means you probably have  configured this kernel before. If I
run  make mrproper,  the .config  will be lost.  But - how lucky you are - I can
save it now !
EOF
    if [ -f /root/saved-config ] && [ ! $use_proc ]; then
      if [[ $(md5sum $sources/.config | sed 's/ .*//' ) == $(md5sum /root/saved-config | sed 's/ .*//' ) ]]; then
        echo "The .config found in $sources and /root/saved-config are identical.";
      else
        echo "I found a saved config file /root/saved-config,  which is the place where I save config files, but this kernel's .config and /root/saved-config differs."
        read -n 1 -p "Do you want me to copy the .config in /root/saved-config ? [y/n]  "
        echo ""
        case $REPLY in
          'y')
            execute "cp $sources/.config /root/saved-config"
            echo "Don't worry, it's safe :)"
            ;;
          'n')
            echo "OK as you wish..."
            ;;
          *)
            clean_confirm
            ;;
        esac
      fi
    else
      echo -e "Anyway, we're going to use /proc/config.gz... No need to save the config, just\nkeep using /proc/config.gz ;)"
    fi
  fi
}

function config_file {
  read -p "Type the complete path to your saved config file or type none : "
  case $REPLY in
    'none')
      echo "Starting from default config"
      ;;
    *)
      if [ -r $REPLY ]; then
        execute "cp $REPLY .config"
        echo "$REPLY successfully loaded";
      else
        echo "$REPLY : No such file or invalid permissions"
        config_file
      fi
      ;;
  esac
  echo ""
}

function ask_lilo {
  read -n 1 -p "Do you use LILO ? [y/n]  "
  echo ""
  case $REPLY in
    'y')
      cat << EOF
Now you should add an entry in your /etc/lilo.conf pointing to your old kernel
that you should label 'rescue' or anything like this in case the new one don't
work.

Your new kernel is $kernel
Your old kernel is $kernel.old

EOF

      read -n 1 -p "Do you want to edit your /etc/lilo.conf now (RECOMMENDED) ?
[y/n]
 "
      case $REPLY in
        'y')
          execute "$EDITOR /etc/lilo.conf"
          ;;
        'n')
          ;;
        *)
          echo ""
          ask_lilo
          ;;
      esac

      color -foreground blue

      echo ""
      echo "Reinstalling LILO boot loader"
      execute lilo
      ;;
    'n')
      read -n 1 -p "Do you use grub ? [y/n] "
      echo
      case $REPLY in
        'y')
	  echo
	  read -n 1 -p "Do you want to edit your /boot/grub/grub.conf ?"
	  echo
	  case $REPLY in
	    'y')
	      execute "$EDITOR /boot/grub/grub.conf";;
	    'n');;
	    *)
	      echo ""
	      ask_lilo
	      ;;
	  esac
      esac
      ;;
    *)
      ask_lilo
      ;;
  esac
}

function ask_reboot {
  echo ""
  read -n 1 -p "Do you want to reboot now ? [y/n]  "
  case $REPLY in
    'y')
      echo ""
#      echo "It has taken $(times) to compile the kernel !"
      execute "shutdown -r now \"Thanks for using Noyau v$version. See you soon :)\""
      ;;
    'n')
      echo ""
#      echo "It has taken $(times) to compile the kernel !"
      echo "Thanks for using Noyau v$version. See you soon :)"
      ;;
    *)
      echo ""
      ask_reboot
      ;;
  esac
}

################################################################################
#                          The code, the real one                              #
################################################################################

color -foreground blue

if [ ! $UID == 0 ]; then
  color -background red
  echo -e "\a"
  echo "You MUST be root to compile the kernel !"
  color -background black
  echo ""
  root;
fi

if [ ! $task ] ; then # if the user didn't specify anything on the command-line
  whattodo            # We ask him what he wants us to do
fi

if [ $sources ]; then
  if [ ! -d $sources ]; then
    echo "You specified a non-existing directory !"
    exit 1
  fi
elif [ -d /usr/src/linux ]; then
  sources=/usr/src/linux;
else
  source_dir # tell me where the sources are !
  symlink
fi

# But we ask the user if it's the right sources we're going to compile
kernel_version

cd $sources
      

if [[ $task == "conf" || $task == "mod" ]] ; then
  # Checking which configure method the user wants us to launch
  if [ ! compile ] ; then usage ; fi

  # We want to clean the source dir, but if the sources have already been
  # configured, this will erase the .config. We propose to save it.
  clean_confirm
  echo "Cleaning the source directory from any binary"
  execute "make mrproper > /dev/null 2> /dev/null"

  # Loading old config if it exists, and if we can't find it, we ask the user if
  # he wants to use a saved config file and which one.
  if [ $use_proc ] && [ -f /proc/config.gz ]; then
    execute "gunzip -c /proc/config.gz > .config"
  elif [ -f /root/saved-config ]; then
    echo "Loading saved kernel configuration"
    execute "cp /root/saved-config .config"
  else
    echo $'\a'
    color -background red
    cat << EOF


No saved configuration found, Hoping this is OK.
Noyau v$version assumes you saved your last kernel config in /root/saved-config, and
copy the configuration to this file when config is over.
If you saved your configuration in another place, you can always import it using
the "Load saved configuration file" function in the configuration menu.
EOF
    color -background black
    echo ""
    config_file
  fi

  # this is make config/menuconfig/xconfig
  echo "Loading configuration interface..."
  execute "make $compile"

  color -foreground yellow
  echo "Saving config in /root/saved-config"
  execute "cp -f .config /root/saved-config"

fi

if [[ $task = "comp" || $task = "conf" ]] ; then

  color -foreground black -background white

  cat << EOF


OK, now compiling the sources. Standard output is redirected to /dev/null and
errors are logged in /root/erreurs-noyau.log (there are always errors when
compiling a kernel, but if the sources are clean and you didn't make any
mistakes, it would be fine).

Two seperated bips and three unseperated bips will warn you when compilation is
finished. I suggests you to take a book or to go to the pub or, if your machine
is fast, just make a cup of green tea and put some ginger in it (directly in
your Tux decorated mug). You'll see it's delicious :)
EOF

  color -foreground green -background black


  echo ""
  echo ""
  echo "Let's go !"
  echo ""

  if [ $MAJVER -eq "2" ]; then
    if [ $PTCHVER -le "4" ]; then

      echo "=================================MAKE DEP======================================="
      echo "=================================MAKE DEP=======================================" > /root/erreurs-noyau.log

      echo "" >> /root/erreurs-noyau.log

      execute "make dep > /dev/null 2>> /root/erreurs-noyau.log"

      echo "" >> /root/erreurs-noyau.log

      echo "===============================MAKE BZIMAGE====================================="
      echo "===============================MAKE BZIMAGE=====================================" >> /root/erreurs-noyau.log

      echo "" >> /root/erreurs-noyau.log

      execute "make bzImage > /dev/null 2>> /root/erreurs-noyau.log"

      echo "" >> /root/erreurs-noyau.log

      echo "===============================MAKE MODULES====================================="
      echo "===============================MAKE MODULES=====================================" >> /root/erreurs-noyau.log

      echo "" >> /root/erreurs-noyau.log

      execute "make modules > /dev/null 2>> /root/erreurs-noyau.log"

      echo "" >> /root/erreurs-noyau.log

      echo "============================MAKE MODULE_INSTALL================================="
      echo "============================MAKE MODULE_INSTALL=================================" >> /root/erreurs-noyau.log

      echo "" >> /root/erreurs-noyau.log

      execute "make modules_install > /dev/null 2>> /root/erreurs-noyau.log"

      echo "" >> /root/erreurs-noyau.log

    elif [ $PTCHVER -eq "6" ]; then
      echo -e "Detected new 2.6 kernel...\nmaking all then modules_install"
      echo "======================================MAKE======================================"
      echo "======================================MAKE======================================" >> /root/erreurs-noyau.log

      echo "" >> /root/erreurs-noyau.log

      execute "make > /dev/null 2>> /root/erreurs-noyau.log"

      echo "" >> /root/erreurs-noyau.log

      echo "============================MAKE MODULE_INSTALL================================="
      echo "============================MAKE MODULE_INSTALL=================================" >> /root/erreurs-noyau.log
    
      echo "" >> /root/erreurs-noyau.log
    
      execute "make modules_install > /dev/null 2>> /root/erreurs-noyau.log"

      echo "" >> /root/erreurs-noyau.log
    
    else

      color -background red
      echo "I don't know this kernel. Try compiling manually or modifying Noyau to support this kernel"
      color -background black -foreground white
      exit 1

    fi

  else

    color -background red
    echo "I don't know this kernel. Try compiling manually or modifying Noyau to support this kernel"
    color -background black -foreground white
    exit 1

  fi

fi
if [[ $task = "mod" ]] ; then
  if [ $PTCHVER -le "4" ]; then
    echo "=================================MAKE DEP======================================="
    echo "=================================MAKE DEP=======================================" >> /root/erreurs-noyau.log
    echo "" >> /root/erreurs-noyau.log
    execute "make dep > /dev/null 2>> /root/erreurs-noyau.log"
  fi
    
  echo "===============================MAKE MODULES====================================="
  echo "===============================MAKE MODULES=====================================" >> /root/erreurs-noyau.log

  echo "" >> /root/erreurs-noyau.log

  execute "make modules > /dev/null 2>> /root/erreurs-noyau.log"

  echo "" >> /root/erreurs-noyau.log

  echo "============================MAKE MODULE_INSTALL================================="
  echo "============================MAKE MODULE_INSTALL=================================" >> /root/erreurs-noyau.log

  echo "" >> /root/erreurs-noyau.log

  execute "make modules_install > /dev/null 2>> /root/erreurs-noyau.log"

fi

color -foreground blue

cat << EOF

====================================== OK ======================================
================================ DONE COMPILING ================================
EOF

if [[ $task = "conf" || $task = "comp" || $task = "inst" ]] ; then
# We need to know where does the user saves his kernel. First tests usual
# places, then asks the user
case $XTRVER in
  '') if [ -f /vmlinuz ]; then
        kernel=/vmlinuz;
      elif [ -f /boot/vmlinuz ]; then
        kernel=/boot/vmlinuz;
      else
        echo "I'm in trouble... I don't know where you want me to put your brand new kernel... ($kversion)"
        read -p "Where do I have to put it ?  "
        echo
        kernel=$REPLY
      fi
      ;;
  *)  if [ -f /vmlinuz$XTRVER ]; then
        kernel=/vmlinuz$XTRVER;
      elif [ -f /boot/vmlinuz$XTRAVER ]; then
        kernel=/boot/vmlinuz$XTRAVER;
      elif [ -f /vmlinuz ]; then
        kernel=/boot/vmlinuz$XTRAVER
        dontmv='1';
      elif [ -f /boot/vmlinuz ]; then
        kernel=/boot/vmlinuz$XTRAVER
        dontmv='1';
      else
        echo "I'm in trouble... I don't know where you want me to put your
brand new kernel... ($kversion). I suggest you to append the EXTRAVERSION ($XTRVER) to the name."
        read -p "Where do I have to put it ?  "
        echo
        kernel=$REPLY
      fi
      ;;
esac

#if [ $XTRAVER != "" ]; then
#  if [ -f /vmlinuz$XTRAVER ]; then
#    kernel=/vmlinuz$XTRAVER;
#  elif [ -f /boot/vmlinuz$XTRAVER ]; then
#    kernel=/boot/vmlinuz$XTRAVER;
#  elif [ -f /vmlinuz ]; then
#    kernel=/vmlinuz$XTRAVER;
#  elif [ -f /boot/vmlinuz ]; then
#    kernel=/boot/vmlinuz$XTRAVER;
#  else
#    echo "I'm in trouble... I don't know where you want me to put your brand new kernel... ($kversion)"
#    read -p "Where do I have to put it ?  "
#    echo
#    kernel=$REPLY
#  fi
#else
#  if [ -f /vmlinuz ]; then
#    kernel=/vmlinuz;
#  elif [ -f /boot/vmlinuz ]; then
#    kernel=/boot/vmlinuz;
#  else
#    echo "I'm in trouble... I don't know where you want me to put your brand new kernel... ($kversion)"
#    read -p "Where do I have to put it ?  "
#    echo
#    kernel=$REPLY
#  fi
#fi

if [ -f $kernel ]; then
  mv -f $kernel ${kernel}.old
  echo "Your old kernel, which had the same name as the new one, has been moved to ${kernel}.old";
fi

execute "cp $sources/arch/i386/boot/bzImage $kernel 2>> /root/erreurs-noyau.log"

echo "" >> /root/erreurs-noyau.log

execute "mv /boot/System.map /boot/System.map.old 2>> /root/erreurs-noyau.log"

echo "" >> /root/erreurs-noyau.log

execute "cp $sources/System.map /boot/System.map$XTRVER 2>> /root/erreurs-noyau.log"

# Ten bips to warn you that compilation is achieved and lilo.conf is opened for
# editing
echo $'\a'
sleep 2
echo $'\a'
sleep 2
echo $'\a'
sleep 1
echo $'\a'
sleep 1
echo $'\a'

ask_lilo

ask_reboot

fi

color -foreground white
