#!/bin/bash
###########################################################################
# Copyright (c) 2000-2002 Justin Piszcz <war@starband.net> 
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the
# Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
###########################################################################

# Define program version.
PROGRAM_VERSION="0.8.9"

gd()
{
  export LILO_CONFIG="/etc/lilo.conf"
  export GRUB_CONFIG="/boot/grub/menu.lst"
}

global_checks() 
{

  root_check()  
  {
        if [ $UID != 0 ]; then
                printf "\033[1;33mERROR: You must be root to run this program.\033[0m\n"
                printf "\033[1;33mERROR: Exiting..."
                exit
        fi
  }

  build_check()
  {
        if [ "$BUILD_DIR" != 1 ]; then
          BUILD_DIR="/usr/src/linux"
     		elif [ "$BUILD_DIR" = 1 ]; then
          BUILD_DIR="$PWD"
    		fi
  }
 
  link_check()
  {
    if [ "$BUILD_DIR" = "/usr/src/linux" ]; then
      if [ ! -h "$BUILD_DIR" ]; then
        printf "\033[1;33mERROR: File $BUILD_DIR is not a symbolic link.\033[0m\n"
        printf "\033[1;33mERROR: Exiting...\033[0m\n"
        exit
      fi
    fi
  }

  sanity_check()
  {
        if [ ! -e "$BUILD_DIR"/Makefile ]; then
          printf "\033[1;33mERROR: A Makefile was not found in this directory.\033[0m\n"
          printf "\033[1;33mERROR: Make sure you are in the right directory if using the -b option.\033[0m\n"
          printf "\033[1;33mERROR: Exiting...\033[0m\n"
          exit
       fi
  }

  space_check()  
  {
        cd /usr/src
        space_availible=`df -kP . | grep dev | head -1 | awk '{print $4}'`
        minimum_space_needed=204800

        if [ $space_availible -lt $minimum_space_needed ]; then
                printf "\033[1;33mERROR: You need at least 200MB free for:\033[0m\n"
                printf "\033[1;33mERROR: 1) Kernel download.\033[0m\n"
                printf "\033[1;33mERROR: 2) Decompression.\033[0m\n"
                printf "\033[1;33mERROR: 3) Compilation.\033[0m\n"
                printf "\033[1;33mERROR: 4) Installation.\033[0m\n"
                printf "\033[1;33mERROR: Please make some space availible and try again.\033[0m\n"
                printf "\033[1;33mERROR: Exiting...\033[0m\n"
                exit
        fi
  }

  config_check()
  {
    if [ ! -e "$BUILD_DIR"/include/linux/autoconf.h ] && [ -e "$BUILD_DIR"/.config ]; then
          printf "\033[1;33mERROR: I see you have moved a previous configuration file into $BUILD_DIR.\033[0m\n"
          printf "\033[1;33mERROR: Type 'make oldconfig' to configure any new options for this kernel.\033[0m\n"
          printf "\033[1;33mERROR: Then run ik again.\033[0m\n"
          printf "\033[1;33mERROR: Exiting...\033[0m\n"
          exit
    elif [ ! -e "$BUILD_DIR"/include/linux/autoconf.h ] || [ ! -e "$BUILD_DIR"/.config ]; then
          printf "\033[1;33mERROR: You must first run: make [oldconfig|config|menuconfig|xconfig]\033[0m\n"
          printf "\033[1;33mERROR: In $BUILD_DIR and save kernel configuration.\033[0m\n"
          printf "\033[1;33mERROR: Exiting...\033[0m\n"
          exit
    fi
  }


  lilo_default_check()
  {
    default=`cat $LILO_CONFIG | grep -v '#' | grep default`
    if [ -z "$default" ]; then
      printf "\033[1;33mERROR: No default entry found in lilo.conf.\033[0m\n"
      printf "\033[1;33mERROR: Add a default=kernel-x.y.z in the top of $LILO_CONFIG.\033[0m\n"
      printf "\033[1;33mERROR: Exiting...\033[0m\n"
      exit
   fi
  }

  grub_default_check()
  {
    default=`cat $GRUB_CONFIG | grep -v '#' | grep default`
    if [ -z "$default" ]; then
      printf "\033[1;33mERROR: No default entry found in menu.lst.\033[0m\n"
      printf "\033[1;33mERROR: Add a default=kernel-x.y.z in the top of menu.lst.\033[0m\n"
      printf "\033[1;33mERROR: Exiting...\033[0m\n"
      exit
   fi
  }

  dual_boot_check()
  {
    LILO=`cat /proc/cmdline | grep BOOT_IMAGE`
     
    if [ -z "$LILO" ]; then
      boot="grub"
      grub_default_check
    elif [ ! -z "$LILO" ]; then
      boot="lilo"
      lilo_default_check
    fi
 }

  bootloader_check()
  {
    gd 
  
    if [ -e $LILO_CONFIG ] && [ -e $GRUB_CONFIG ]; then
      dual_boot_check
    elif [ -e $GRUB_CONFIG ] && [ ! -e $LILO_CONFIG ]; then
      boot="grub"
      grub_default_check
    elif [ -e $LILO_CONFIG ] && [ ! -e $GRUB_CONFIG ]; then
      boot="lilo"
      lilo_default_check
    elif [ ! -e $LILO_CONFIG ] && [ ! -e $GRUB_CONFIG ]; then
      printf "\033[1;33mERROR: No bootloader could be found on this system.\033[0m\n"
      printf "\033[1;33mERROR: Exiting...\033[0m\n"
      exit
    fi
  }

  boot_check()
  {
    if [ ! -d /boot ]; then
      printf "\033[1;33mERROR: Could not find a boot directory.\033[0m\n"
      printf "\033[1;33mERROR: Exiting...\033[0m\n"
      exit
   fi
  }

  module_check()
  {
    MODULE_CONFIG_CHECK=`cat "$BUILD_DIR"/.config | grep CONFIG_MODULES | cut -f2 -d'='`
   
    if [ "$MODULE_CONFIG_CHECK" = "y" ]; then
        export MODULES=1
    elif [ "$MODULE_CONFIG_CHECK" != "y" ]; then
        export MODULES=0
    fi
  }

}


install_kernel()
{
  clear
  printf "\033[1;32m\t\t#########################################\033[0m\n"
  printf "\033[1;34m\t\t\t\tik v$PROGRAM_VERSION\033[0m\n"
  printf "\033[1;31m\t\t     Automated installing activated.\033[0m\n"
  printf "\033[1;31m\t\t         Self-checking included.\033[0m\n"
  printf "\033[1;32m\t\t#########################################\033[0m\n\n"

cfe()
{
  if [ $? != 0 ]; then
    printf "\033[1;33mERROR: Aborting ik due to an error.\033[0m\n"
    exit
  fi
}

gv()
{
  if [ "$boot" = "lilo" ]; then
    LILO_ROOT_PARTITION=`cat $LILO_CONFIG | grep -v '#' | grep root | awk '{print $1,$2,$3}' | head -1`
    LILO_DEFAULT_CONF=`cat $LILO_CONFIG | grep -v '#' | grep default | cut -f2 -d'='| cut -f1 -d' '`
  elif [ "$boot" = "grub" ]; then
    GRUB_ROOT_PARTITION=`cat $GRUB_CONFIG | grep -v '#' | grep root | grep '=' | head -1 | awk '{print $4}'`
    GRUB_OLD_CONF=`cat $GRUB_CONFIG | grep -v '#' | grep default | head -1 | cut -f2 -d'='`
    GRUB_NEW_CONF=`cat $GRUB_CONFIG | grep -v '#' | grep -c title` 
    GRUB_ROOT=`cat $GRUB_CONFIG | grep -v '#' | grep root | grep ',' | head -1 | awk '{print $1,$2}'`
    GRUB_ADDITIONAL_OPTIONS=`cat $GRUB_CONFIG | grep -v '#' | grep kernel | head -1 | awk '{print $5,$6,$7,$8,$9,$10}'`
    GRUB_BOOT_PARTITION=`cat /etc/fstab | grep boot`
  fi

  if [ -e "$BUILD_DIR"/.version ]; then
    BUILD_VERSION=`cat "$BUILD_DIR"/.version | awk '{print $1}'`
  elif [ ! -e "$BUILD_DIR"/.version ]; then
    BUILD_VERSION=1
  fi

  VERSION=`grep VERSION "$BUILD_DIR"/Makefile | head -1 | cut -f2 -d'=' | awk '{print $1}'`
  PATCHLEVEL=`grep PATCHLEVEL "$BUILD_DIR"/Makefile | head -1 | cut -f2 -d'=' | awk '{print $1}'`
  SUBLEVEL=`grep SUBLEVEL "$BUILD_DIR"/Makefile | head -1 | cut -f2 -d'=' | awk '{print $1}'`
  EXTRAVERSION=`grep EXTRAVERSION "$BUILD_DIR"/Makefile | head -1 | cut -f2 -d'=' | awk '{print $1}'`
  KERNELRELEASE=`printf $VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION`
}

lilo()
{
  gv
  cat < $LILO_CONFIG | sed 's/^default='$LILO_DEFAULT_CONF'/default='$KERNELRELEASE-$BUILD_VERSION'/g' > $LILO_CONFIG
  chmod 600 $LILO_CONFIG
  printf "\nimage=/boot/$KERNELRELEASE-$BUILD_VERSION\n" >> $LILO_CONFIG
  printf "\tlabel=$KERNELRELEASE-$BUILD_VERSION\n"       >> $LILO_CONFIG
  printf "\tread-only\n"                                 >> $LILO_CONFIG
  printf "\t$LILO_ROOT_PARTITION\n"                      >> $LILO_CONFIG
  /sbin/lilo > /dev/null 2>&1
  cfe
}

grub()
{
  gv
  cat < $GRUB_CONFIG | sed 's/^default='$GRUB_OLD_CONF'/default='$GRUB_NEW_CONF'/g'                                 > $GRUB_CONFIG
  chmod 600 $GRUB_CONFIG
  printf "\ntitle $KERNELRELEASE-$BUILD_VERSION\n"                                                                 >> $GRUB_CONFIG
  printf "       $GRUB_ROOT\n"                                                                                     >> $GRUB_CONFIG

  if [ ! -z "$GRUB_BOOT_PARTITION" ]; then
    printf "       kernel /$KERNELRELEASE-$BUILD_VERSION ro $GRUB_ROOT_PARTITION $GRUB_ADDITIONAL_OPTIONS\n"       >> $GRUB_CONFIG
  elif [ -z "$GRUB_BOOT_PARTITION" ]; then
    printf "       kernel /boot/$KERNELRELEASE-$BUILD_VERSION ro $GRUB_ROOT_PARTITION $GRUB_ADDITIONAL_OPTIONS\n"  >> $GRUB_CONFIG
  fi
}

move()
{
  gv
  /bin/cp "$BUILD_DIR"/System.map /boot/System.map-$KERNELRELEASE-$BUILD_VERSION
  /bin/cp "$BUILD_DIR"/arch/i386/boot/bzImage /boot/$KERNELRELEASE-$BUILD_VERSION
  /bin/ln -sf /boot/System.map-$KERNELRELEASE-$BUILD_VERSION /boot/System.map
  chmod 755 /boot/System.map-$KERNELRELEASE-$BUILD_VERSION
  chmod 755 /boot/$KERNELRELEASE-$BUILD_VERSION
}

make_dep() 
{
  gv
  if [ "$FAST" != 1 ]; then
    printf "\033[1;31mMaking dep.\033[0m\n"
    if [ "$LOG" = 1 ]; then
      make -j 2 dep > "$BUILD_DIR"/ik-$BUILD_VERSION.log 2>&1
      cfe
    elif [ "$LOG" != 1 ]; then
      make -j 2 dep > /dev/null 2>&1
      cfe
    fi
  printf "\033[1;34mMade dep\033[0m .................................................. [\033[1;32m  16%% COMPLETE\033[0m ]\n"
  fi
}

make_clean()
{
  gv
  if [ "$FAST" != 1 ]; then
    printf "\033[1;31mMaking it clean.\033[0m\n"
    if [ "$LOG" = 1 ]; then
      make -j 2 clean >> "$BUILD_DIR"/ik-$BUILD_VERSION.log 2>&1
      cfe
    elif [ "$LOG" != 1 ]; then
      make -j 2 clean > /dev/null 2>&1
      cfe
    fi
  printf "\033[1;34mMade it clean\033[0m ............................................. [\033[1;32m  33%% COMPLETE\033[0m ]\n"
  fi
}
 
make_bzImage()
{
  gv
  printf "\033[1;31mMaking bzImage.\033[0m\n"

  if [ "$LOG" = 1 ]; then
    make -j 2 bzImage >> "$BUILD_DIR"/ik-$BUILD_VERSION.log 2>&1
    cfe
  elif [ "$LOG" != 1 ]; then
    make -j 2 bzImage > /dev/null 2>&1
    cfe
  fi

  printf "\033[1;34mMade bzImage\033[0m .............................................. [\033[1;32m  80%% COMPLETE\033[0m ]\n"
}

make_modules()
{
  gv
  if [ "$MODULES" = 1 ]; then
    printf "\033[1;31mMaking the modules.\033[0m\n"
    if [ "$LOG" = 1 ]; then
      make -j 2 modules >> "$BUILD_DIR"/ik-$BUILD_VERSION.log 2>&1
      cfe
    elif [ "$LOG" != 1 ]; then
      make -j 2 modules > /dev/null 2>&1
      cfe
    fi
    printf "\033[1;34mModules have been made\033[0m .................................... [\033[1;32m  85%% COMPLETE\033[0m ]\n"
  fi
}

make_modules_install()
{
  gv
  if [ "$MODULES" = 1 ]; then
    printf "\033[1;31mInstalling the modules.\033[0m\n"
    if [ "$LOG" = 1 ]; then
      make -j 2 modules_install >> "$BUILD_DIR"/ik-$BUILD_VERSION.log 2>&1
      cfe
    elif [ "$LOG" != 1 ]; then
      make -j 2 modules_install > /dev/null 2>&1
      cfe 
    fi
    printf "\033[1;34mModules have been installed\033[0m ............................... [\033[1;32m  98%% COMPLETE\033[0m ]\n"
  fi
}

set_deps()
{
  gv

  if [ "$MODULES" = 1 ]; then
    printf "\033[1;31mSetting dependencies for the modules.\033[0m\n"
    if [ "$LOG" = 1 ]; then
        /sbin/depmod -a -F /boot/System.map-$KERNELRELEASE-$BUILD_VERSION $KERNELRELEASE >> "$BUILD_DIR"/ik-$BUILD_VERSION.log 2>&1 
        cfe
    elif [ "$LOG" != 1 ]; then
        /sbin/depmod -a -F /boot/System.map-$KERNELRELEASE-$BUILD_VERSION $KERNELRELEASE > /dev/null 2>&1
        cfe
    fi
    printf "\033[1;34mDependencies have been set\033[0m ................................ [\033[1;32m  99%% COMPLETE\033[0m ]\n"
  fi
}

build()
{
  printf "\033[1;31mCompiling kernel.\n"
  make_dep
  make_clean
  make_bzImage
  make_modules
  make_modules_install
  move
  set_deps  
  printf "\033[1;34mInstallation is complete\033[0m .................................. [\033[1;32m 100%% COMPLETE\033[0m ]\n"
}

setup()
{
  if [ "$boot" = "lilo" ]; then
    lilo
  elif [ "$boot" = "grub" ]; then
    grub
  fi
}

init()
{
  printf "\033[1;34mChecking dependencies\033[0m ..................................... [\033[1;32m   1%% COMPLETE\033[0m ]\n"
  global_checks
  printf "\033[1;34mChecking root\033[0m ............................................. [\033[1;32m   2%% COMPLETE\033[0m ]\n"
  root_check
  printf "\033[1;34mChecking for symbolic link\033[0m ................................ [\033[1;32m   3%% COMPLETE\033[0m ]\n"
  link_check 
  printf "\033[1;34mChecking for custom kernel build directory\033[0m ................ [\033[1;32m   4%% COMPLETE\033[0m ]\n"
  build_check 
  printf "\033[1;34mChecking for proper build directory\033[0m ....................... [\033[1;32m   5%% COMPLETE\033[0m ]\n"
  sanity_check
  printf "\033[1;34mChecking for boot directory\033[0m ............................... [\033[1;32m   6%% COMPLETE\033[0m ]\n"
  boot_check
  printf "\033[1;34mChecking for bootloader\033[0m ................................... [\033[1;32m   7%% COMPLETE\033[0m ]\n"
  bootloader_check
  printf "\033[1;34mChecking for proper configuration\033[0m ......................... [\033[1;32m   8%% COMPLETE\033[0m ]\n"
  config_check
  printf "\033[1;34mChecking for module support\033[0m ............................... [\033[1;32m   9%% COMPLETE\033[0m ]\n"
  module_check
  printf "\033[1;34mChecking space\033[0m ............................................ [\033[1;32m  10%% COMPLETE\033[0m ]\n"
  space_check
  printf "\033[1;34mChecking complete\033[0m ......................................... [\033[1;32m  11%% COMPLETE\033[0m ]\n"
  cd "$BUILD_DIR"
}

ik()
{
  init
  gv
  build
  setup
}  
ik
}

examples()
{
  echo "  ik -b -i: Install the kernel from the directory you are in."
  echo "  ik -d -i: Install the kernel with debug output on."
  echo "  ik -e   : Show these examples."
  echo "  ik -f -i: Compile fast by skipping make dep and make clean."
  echo "  ik -h   : Prints help menu."
  echo "  ik -i   : Install the kernel and save the configuration file."
  echo "  ik -l   : Logs all make output to build_directory/ik-buildversion.log"
  echo "  ik -r -i: Use newest config from /usr/src/cfg and install kernel."
  echo "  ik -s -i: Not required, the kernel configuration is automatically saved "
  echo "            upon each kernel recompile."
}

usage()
{
  echo "usage: ik [-bdefhijrs]"
  echo "    -b     Build from current directory."
  echo "    -d     Debug."
  echo "    -e     Example usage of ik."
  echo "    -f     Compile fast by skipping make dep and make clean."
  echo "    -h     Prints help menu."
  echo "    -i     Install the kernel and saves configuration file."
  echo "    -l     Log to build_directory/ik-buildversion.log."
  echo "    -r     Use newest saved kernel configuration file."
  echo "    -s     Save kernel configuration file."
}

retrieve_config()
{
  global_checks
  root_check
  link_check

  if [ ! -d /usr/src/cfg ]; then
     echo "No cfg directory found."
     echo "Creating cfg directory..."
     mkdir /usr/src/cfg
     echo "No configuration files exist."
     echo "Please run ik -i or ik -s and then ik -r -i will be availible."
     exit
  fi

  NUMCONFIG=`ls /usr/src/cfg | wc -l | awk '{print $1}'`
  SECOND=`date +%s`

  if [ "$NUMCONFIG" != 0 ]; then
    NCONFIG=`ls -1t /usr/src/cfg | head -1`
   elif [ "$NUMCONFIG" = 0 ]; then
     echo "Please run ik -i or ik -s and then ik -r -i will be availible."
     exit
  fi

  if [ -e "$BUILD_DIR"/.config ]; then  
    mv "$BUILD_DIR"/.config $BUILD_DIR/.config-$SECOND
  fi

  echo "Restoring from /usr/src/cfg/$NCONFIG"
  sleep 5
 
  cp /usr/src/cfg/$NCONFIG "$BUILD_DIR"/.config
  cd "$BUILD_DIR" 
  make oldconfig
}

save_config()
{
  global_checks
  root_check
  link_check

 if [ ! -d /usr/src/cfg ]; then
    mkdir /usr/src/cfg
 fi
  
  PREFIX=`date +%Y%m%d.%s`
  
  if [ ! -e "$BUILD_DIR"/.config ]; then
     echo "No current config found in $BUILD_DIR."
     exit 
  fi

  cp "$BUILD_DIR"/.config /usr/src/cfg/config-$PREFIX
}
  
  
if [ $# = 0 ]; then
  usage
  exit
fi

ARGS=`getopt bdefhijlrs $*`

eval set -- "$*"

while true
do
  case "$1" in 
  -b) export BUILD_DIR=1
      shift
      ;;
  -d) set -vx 
      shift
      ;;
  -e) examples
      shift
      ;;
  -f) export FAST=1
      shift
      ;;
  -h) usage
      shift
      ;;
  -i) install_kernel 
      save_config 
      shift
      ;;
  -l) export LOG=1
      shift
      ;;
  -r) retrieve_config
      shift
      ;;
  -s) save_config 
      shift
      ;;
   *) exit 
      ;;
   esac
done



