#!/bin/bash

#: Title       : S.A.K.C. - SUSE Automated Kernel Compiler
#: Date Created: Wed Dec  8 19:10:59 CST 2010
#: Last Edit   : Sat May 14  8:49:00 CST 2011
#: Author      : J. McDaniel
#: Version     : 2.5
#: Description : Kernel Compile Script for openSUSE
#: Options     : sakc [-h --help] [kernel_file_name.bz2]
#: Notes       : klist bash script added to sakc with version 2.5

TITLE="            S.A.K.C. - SUSE Automated Kernel Compiler - Version 2.50            "

FILE=$1

#
# Written for the openSUSE forums on Saturday May 14, 2011
#

#
# Copy and Paste the text of this script into a text editor and save 
# it as the file sakc in your home area bin folder (~/bin/sakc).
# This script must be marked executable to be used.  Please run 
# the following Terminal command: chmod +x ~/bin/sakc
# To use sakc, download the latest kernel source files from ...
# http://www.kernel.org/ into your download(s) folder.
# Open up a terminal session, change to your download(s) folder
# and run the command: sakc kernel_name
#

#
# Make Sure the Following Folder/File names are correct and exist!!!
#

# Where do your Keep/Download Your Kernel Source Files? This Folder Name Must Exist!

kernel_folder=~/Downloads

# Where do you want to place your Compiled Kernels? This Folder Name Must Exist!

compile_folder=~/Kernel

# Where is SAKC located and what is it called  (folder/name)
# Don't Like the name sakc?  Save it as anything you like, 
# but make sure this is the name/location that you used!

sakc_name=~/bin/sakc

#
# Kernel Compile/Configuration Log File. Do you wish to save all information for viewing later?
#

log_file=true
log_file_location=~/Documents

#
# Do You Wish SAKC to play a Sound When the Compile is complete? (true / false)
# play is included with the --> sox <-- application found in YaST
#

Play_Sound=true
wav_Player=/usr/bin/play
wav_File=/usr/share/sounds/alsa/test.wav

# GPL Statement Output

function show_gpl {
echo "S.A.K.C. is designed to compile a kernel source file in openSUSE."
echo "Copyright (C) 2011 by James D. McDaniel, jmcdaniel3@austin.rr.com"
echo
echo "This program is free software; you can redistribute it and/or modify"
echo "it under the terms of the GNU General Public License as published by"
echo "the Free Software Foundation; either version 2 of the License, or"
echo "(at your option) any later version."
echo 
echo "This program is distributed in the hope that it will be useful,"
echo "but WITHOUT ANY WARRANTY; without even the implied warranty of"
echo "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the"
echo "GNU General Public License for more details."
echo 
echo "You should have received a copy of the GNU General Public License"
echo "along with this program; if not, write to the Free Software"
echo "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA"
echo
}

script_start=$(date +%m/%d/%y-%H:%M:%S)

#
# Set Number of Compile Jobs based on number of CPU's times two
#
Number_CPUS=$(getconf _NPROCESSORS_ONLN)
Jobs=$(($Number_CPUS+$Number_CPUS))

#
# Time Display Function.  Do you want the Elasped time displayed while your compile is running?  
#
show_time=true

#
# S.A.K.C. Function Blocks ****************************************************
#

#
# Display All Text in Color as requested
#
# syntax: print_color line col fgrd_color bgrd_color #lines "text"...
#
# 0: Black 1: Blue 2: Green 3: Cyan 4: Red  5: Magenta 6: Yellow 7: White
#
function print_color {
  WIDTH=$(tput cols)
  HEIGHT=$(tput lines)
  line_os=0
  if [ $(($WIDTH)) -le  80  ] ; then
    col_os=0
  else
    col_os=$((($WIDTH - 80) / 2 ))
  fi
  s_line=${1}
  s_col=${2}
  fgrd=${3}
  bgrd=${4}
  maxnum=${5}
  counter=0
  while [ $(( counter )) -lt $(( maxnum + 1 )) ] ; do
    tput cup $(( s_line + counter + line_os)) $(( s_col + col_os ))
    tput bold
    tput setf $(( fgrd ))
    tput setb $(( bgrd ))
    echo "${6}$(tput sgr0)"
    let counter=counter+1
    shift
  done
}

#
# Display Elapsed Time While doing the compile / This runs in the background
#
function time_display {
  tput cup $(( 14 + line_os)) $(( 41 + col_os ))
  echo -n "Elapsed Time: 0   minute(s) "
  while true ; do let comp_time=comp_time+1 && sleep 60 && tput cup $(( 14 + line_os)) $(( 55 + col_os )) && echo -n "$comp_time$(tput sgr0)" ; done &
PID1=$!
}

#
# Extract the base Kernel Folder Name from .tar.bz2 File Name
#
function folder_name {
  shortname=$(basename $FILE)
  NUM=${#shortname}
  folder="${shortname:0:$(($NUM-8))}"
  NUM=${#folder}
}

#
# S.A.K.C. Main Header Display
#
function display_header {

  tput clear

  print_color 1 0 7 0 1 "$(date +%m/%d/%y)"
  print_color 1 $((80-NUM)) 7 0 1 "$folder"

  print_color 3 0 7 2 1 "$TITLE"
  l1="--------------------------------------------------------------------------------"
  l2=""
  l3="--------------------------------------------------------------------------------"
  l4=""
  l5="--------------------------------------------------------------------------------"
  l6=" Num          Function                    Status                      Exit Code "
  l7="--------------------------------------------------------------------------------"
  print_color 2 0 3 0 7 "$l1" "$l2" "$l3" "$l4" "$l5" "$l6" "$l7"

  l1="  1.  Kernel File Decompression:                                                "
  l2=""
  l3="  2.  Kernel File Configuration:                                                "
  l4=""
  l5="  3.  Kernel File Compile Process:                                              "
  l6=""
  l7="  4.  Kernel File Installation:                                                 "
  print_color 10 0 7 0 7 "$l1" "$l2" "$l3" "$l4" "$l5" "$l6" "$l7"
  l1="--------------------------------------------------------------------------------"
  l2=""
  l3="--------------------------------------------------------------------------------"
  print_color 18 0 3 0 3 "$l1" "$l2" "$l3" 
}

#
# S.A.K.C. top status display 
#
function status_display {

  case $1 in

    1) print_color 5 0 7 1 1 "          Your Kernel file is now being uncompressed.  Please Wait ...          " ;;
    2) print_color 5 0 6 1 1 "          Your Kernel file is now being Configured.    Please Wait ...          " ;;
    3) print_color 5 0 7 4 1 "        Would you like to modify your Kernel configurations in a GUI?           " ;;
    4) print_color 5 0 7 1 1 "          Your Kernel file is now being Compiled.      Please Wait ...          " ;;
    5) print_color 5 0 7 4 1 "              Your Kernel file has been Compiled Successfully!                  " ;;
    6) print_color 5 0 6 1 1 "          Your Kernel file is now being Installed.     Please Wait ...          " ;;
    7) print_color 5 0 7 4 1 "      Would you like to view your Kernel Config/Compile/Install Log File?       " ;;
    8) print_color 5 0 7 1 1 "                Your Kernel file Has Been Installed Successfully                " ;;
    *) ;;

  esac
  tput cup $(( 5 + line_os)) $(( 75 + col_os ))
}

#
# S.A.K.C. Kernel Function progress display 
#
function progress_display {
  for ((i=1;i<=$1;++i)) ; do 
    case $i in
      1) ON_LINE=10
	 Exit_Code=$uncompress_exit ;;
      2) ON_LINE=12
	 Exit_Code=$configure_exit ;;
      3) ON_LINE=14
	 Exit_Code=$compile_exit ;;
      4) ON_LINE=16
         Exit_Code=$install_exit ;;
      *) ;;
    esac
    print_color $(( ON_LINE )) 74 7 0 1 "$Exit_Code"
    if [ $(( Exit_Code )) -ge 1 ] ; then
      print_color $(( ON_LINE )) 41 4 0 1 "Failed!   "
      exit $Exit_Code
    else
      print_color $(( ON_LINE )) 41 7 0 1 "Completed!   "
    fi
  done
}

#
# Get User Input Display
#
function get_input {
  print_color 19 10 7 0 1 " Please make your selection and press <enter> (Y=Yes/N=No): "
  tput cup $(( 19 + line_os)) $(( 69 + col_os ))
  read CHOICE
  print_color 19 10 7 0 1 "                                                            "
}

#
# Get User Input & password Display
#
function get_password {
  print_color 19 9 7 0 1 " Press the <enter> key to proceed to your Kernel Instalation "
  tput cup $(( 19 + line_os)) $(( 69 + col_os ))
  read CHOICE
  print_color 19 9 7 0 1 "                                                             "
  tput cup $(( 16 + line_os)) $(( 41 + col_os ))
  sudo dir > /dev/null
  tput cup $(( 16 + line_os)) $(( 41 + col_os )) 
  echo "                "
}

#
# Prompt for user input in bold while, for startup error messages
#
function enter_prompt {
  echo
  tput bold
  tput setf 7
  tput cup $(( 4 + line_os)) $(( 0 + col_os ))
  echo -n "$1$(tput sgr0)"
  read CHOICE
  echo
}

#
# Setup Name and Location of your Log File
#
function start_log {
  ext=$(date +%m%d%y.%H%M%S)
  if $log_file ; then
    log_file_name=$log_file_location"/"$folder"."$ext".txt"
  else
    log_file_name="/dev/null"
  fi
# Start The Log File Output if Selected
  echo "$TITLE" > $log_file_name
  echo " " >> $log_file_name
  echo " S.A.C.K. Start: $script_start of kernel: $folder " >> $log_file_name
  echo " " >> $log_file_name
}

function log_heading {
echo " " >> $log_file_name
echo "*********** Command: $1 *********************" >> $log_file_name
echo " " >> $log_file_name
}

function log_complete {
echo " " >> $log_file_name
echo " Compile Start: $start_of_compile             Compile Finish: $end_of_compile " >> $log_file_name
echo "  Script Start: $script_start              Script Finish: $script_stops " >> $log_file_name
echo " " >> $log_file_name
echo "$TITLE" >> $log_file_name
}

#
# Common Text to Display When an Error is Detected
#
function error_message {
  tput clear
  echo "$TITLE"
  echo
  echo "$1"
  echo
}

#
# Help used here simular to found in findgrub script
#

function help {
    cat << EOFHELP

$TITLE

Your S.A.K.C. Startup and help options are:

$0 -h --help :to show this help 

OR

$0 [kernel_file_name.bz2]

The kernel_file_name.bz2 name is optional and will be requested if not supplied.

EOFHELP
show_gpl
exit 0
}

#
# S.A.K.C. Display Error Messages *********************************************
#          

# Make sure script was not started as root

tput clear

if [ $UID -eq 0 ] ; then
  l1=""
  l2=" Do Not Start $(basename $0) as a root user!  Your password will be "
  l3=" requested later when needed to install your new Kernel.  "
  print_color 0 0 7 4 4 "$TITLE" "$l1" "$l2" "$l3"
  enter_prompt "Press <enter> to exit..."
  exit 2
fi

#
# Determine if the compile_folder exists
#
if [[ -d "$compile_folder" ]] ; then
  cd "$compile_folder"
else
  error_message "The Kernel Compile Folder: $compile_folder, does not exist!"
  echo "Please create or change this folder name and start $(basename $0) again."
  echo
  exit 1
fi

#
# Make sure the sakc script file exists in the folder specified
#
if [ ! -e "$sakc_name" ] ; then
  error_message "The S.A.K.C. Kernel Source File Compiler: $sakc_name, was not found!"
  exit 1
fi

#
# Display Help if requested.  Example from Findgrub
#

case "$1" in
    -h|--help) help ;;
esac

#
# Orginal Klist File Functions Go Here: *************************************************
#

#
# Determine if a kernel file name was given at start
#
if [ $# -eq 0 ] ; then

#
# Determine if the kernel_folder (default is ~/Downloads) Exists
#
  if [[ -d "$kernel_folder" ]] ; then

    menu=true

    while $menu ; do

      tput clear
      echo "$TITLE"
      echo
      echo "S.A.K.C. Location/Name: $sakc_name"
      echo
      echo " Kernel Compile Folder: $compile_folder"
      echo " Kernel Source  Folder: $kernel_folder"
      echo 

      counter=0
      declare -a kernels
#
# Find and display all files that start with linux* and end with .tar.bz2
#
      for i in "$kernel_folder"/linux*.tar.bz2 ; do 
#
# Determine if the kernel source file exists
#
	if [ -f $i ] ; then

	  let counter=counter+1
	  kernels[$counter]=$i 
	  echo " $counter) $(basename ${kernels[$counter]})"

	fi

      done
#
# Determine if any Kernel Source Files were found
#
      if [[ $counter -eq 0 ]]; then

	echo
	echo "No Kernel Source Files were found in $kernel_folder!"
	echo
	exit 1

      fi
#
# Main Program Prompt Displayed Here
#
      echo
      echo -n "Enter the Kernel Source File Number to Compile (q=Quit): "
      read CHOICE
#
# Determine if input ($CHOICE) is an integer number and in range, look for Q to 
# Quit. If menu is not set to false, the menu will just be redisplayed as you 
# did not enter a valid menu option number for a kernel source file to compile.
#
      if [[ $CHOICE =~ ^[0-9]+$ ]] ; then
	if [[ $CHOICE -le $counter ]] && [[ $CHOICE -gt 0 ]]; then
	  menu=false
	fi
      else
	if [[ $CHOICE == [Qq] ]] ; then
	  exit 0
	fi
      fi

    done

    $sakc_name ${kernels[$CHOICE]}

  else
#
# The Kernel Source File Folder (default=~/Downloads) was not found
#
    error_message "The Kernel Source File Folder: $kernel_folder, does not exist!"
    exit 1

  fi

  exit 0

else

#
# End Of Added Klist Program Here ************************************************
#

# Make sure we got kernel source file name as a command line argument

  if [ $# -eq 0 ] ; then
    l1=""
    l2=" Command Syntax is: $(basename $0) kernel_source_file_name.tar.bz2  "
    l3=""
    print_color 0 0 7 4 4 "$TITLE" "$l1" "$l2" "$l3"
    enter_prompt "Press <enter> to exit..."
    exit 1
  fi

# Determine if kernel file-name is present

  if [ ! -e $FILE ] ; then
    l1=""
    l2=" The Kernel Source file: --> $1 <-- was not Found!  "
    l3=""
    print_color 0 0 7 4 4 "$TITLE" "$l1" "$l2" "$l3"
    enter_prompt "Press <enter> to exit..."
    exit 10
  fi

#
# S.A.K.C. Main Program Starts Here *******************************************
#

  folder_name
  start_log
  display_header

#
# S.A.K.C. Kernel Decompression ***********************************************
#

# Your Kernel file is now being uncompressed.  Please Wait ...
  status_display 1

  tar -vxjf $FILE > /dev/null 2>&1
  uncompress_exit=$?

# 1.  Kernel File Decompression: Completed!
  progress_display 1

  cd $folder

#
# S.A.K.C. Kernel Configuration ***********************************************
#

# Your Kernel file is now being Configured.    Please Wait ...
  status_display 2

  log_heading "make mrproper"

# Fix any left over compile issues before we start again

  make mrproper >> $log_file_name 2>&1

# Get the Configuration for the running kernel

  zcat /proc/config.gz >.config 

  log_heading "make oldconfig"

# Take the defaults for all new kernel module configurations

  yes "" | make oldconfig >> $log_file_name 2>&1
  configure_exit=$?

# Would you like to modify your Kernel configurations in a GUI?
  status_display 3

  get_input

  if [[ $CHOICE == [Yy] ]] ; then
    tput clear
    make menuconfig 
    configure_exit=$?
    display_header
  fi

# 2.  Kernel File Configuration: Completed!
  progress_display 2

#
# S.A.K.C. Kernel Compile *****************************************************
#

  start_of_compile=$(date +%m/%d/%y-%H:%M:%S)

# Your Kernel file is now being Compiled.      Please Wait ...
  status_display 4

  if $show_time ; then
    time_display
  fi

  if [ $Jobs -ge 2 ] ; then

    log_heading "make -j$Jobs"
  
    make -j$Jobs >> $log_file_name 2>&1
    compile_exit=$?

  else

    log_heading "make"

    make >> $log_file_name 2>&1
    compile_exit=$?
  fi

# Kill Background Elasped Time Display shown during the compile
  if $show_time ; then
    disown $PID1
    kill -9 $PID1
  fi

# 3.  Kernel File Compile Process: Completed!
  progress_display 3

  end_of_compile=$(date +%m/%d/%y-%H:%M:%S)

# Your Kernel file has been Compiled Successfully!
  status_display 5

#
# Play a Sound file When the Compile is Complete
#

  which $wav_Player > /dev/null 2>&1
  error_code1=$?

  which $wav_File > /dev/null 2>&1
  error_code2=$?

  if $Play_Sound ; then
    if [ $(( error_code1 )) -eq 0 ] || [ $(( error_code2 )) -eq 0 ] ; then
      $wav_Player -q $wav_File > /dev/null 2>&1
    fi
  fi

#
# S.A.K.C. Kernel Install *****************************************************
# 

  get_password

# Your Kernel file is now being Installed.     Please Wait ...
  status_display 6

  log_heading "make modules_install install"

  sudo make modules_install install >> $log_file_name 2>&1
  install_exit=$?

# 4.  Kernel File Installation: Completed!
  progress_display 4

#
# S.A.K.C. is Complete ********************************************************
#

  script_stops=$(date +%m/%d/%y-%H:%M:%S)

  log_complete

  if $log_file ; then
# Would you like to view your Kernel Config/Compile Log File?
    status_display  7
    get_input
    if [[ $CHOICE == [Yy] ]] ; then
      less $log_file_name
    fi
  fi

# Your Kernel file Has Been Installed Successfully
  status_display  8

  print_color 18 0 7 1 1 " Compile Start: $start_of_compile             Compile Finish: $end_of_compile "
  print_color 20 0 7 1 1 "  Script Start: $script_start              Script Finish: $script_stops "
  tput cup 24 0

#
# Everything had to be indented by two when Klist functions were added to sakc
#

fi

exit 0
# End Of Script
