#!/usr/bin/perl -w

# base_install_client.pl - help automate install process brt client
#
# Copyright (C) 2005 Leann Ogasawara Open Source Development labs
#
# written by Leann Ogasawara <ogasawara@osdl.org>
#
# 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

use warnings;
use strict;
use Term::ANSIColor;

my $i;
my $j;
my $level = -1;
my $user;
my $ret;
my $BOOT = 1;
my $ROOT = 0;
my $message;
my $q1;
my $q2;
my $tar;
my $begin;
my $end;
my $node;
my $drive;
my $grub_drive;
my $drive_num;
my $part;
my $cpu;
my $fstab_root;
my $fstab_boot;
my $disk;
my $system_root;
my $time;

my @partition = (
		 {
			 name => "root",
			 partition => "",
			 mounted => "",
			 fs => "",
		 },
		 {
			 name => "boot",
			 partition => "",
			 mounted => "",
			 fs => "",
		 },
);

my @step = (
	    {#0
		    msg => "creating environment variables . . .",
		    command => "/usr/sbin/env-update 2>&1",
	    },
	    {#1
		    msg => "Loading variables into memory . . .",
		    command => "source \"/etc/profile\" 2>&1",
	    },
	    {#2
		    msg => "Grabbing brt public key from keyserver . . .",
		    command => "gpg --keyserver wwwkeys.eu.pgp.net --recv-keys EB64280B 2>&1",
	    },
	    {#3
		    msg => "Creating /var/lock/brt_sync.lock file  . . .",
		    command => "echo $time > /var/lock/brt_sync.lock 2>&1",
	    },
	    {#4
		    msg => "Syncing portage tree . . .",
		    command => "emerge --sync 2>&1",
	    },
	    {#5
		    msg => "Emerging kernel . . .",
		    command => "emerge --nodeps vanilla-sources 2>&1",
	    },
	    {#6
		    msg => "Copying over kernel config file . . .",
		    command => "cp /boot/brt_kernel.config /usr/src/linux/.config 2>&1",
	    },
	    {#7
		    msg => "Installing modules . . .",
		    command => "make modules_install 2>&1",
	    },
	    {#8
		    msg => "Copying over bzImage . . .",
		    command => "cp arch/i386/boot/bzImage /boot/brt-bzImage 2>&1",
	    },
	    {#9
		    msg => "Copying over System.map . . .",
		    command => "cp System.map /boot/System.map-brt 2>&1",
	    },
	    {#10
		    msg => "Copying /proc/mounts to /etc/mtab . . .",
		    command => "cp /proc/mounts /etc/mtab 2>&1",
	    },
);

sub proceed {
	my ($input) = @_;
	my $val;

	#strip leading and trailing whitespace from input
	$input =~ s/^\s+|\s+$//g;

	if ($input eq 'y' || $input eq 'Y') {
		$val = 0;
	}
	elsif ($input eq 'n' || $input eq 'N') {
		$val = 1;
	} else {
		$val = 2;
	}
	return $val;
}

sub check_step {
	my ($stmt1, $stmt2) = @_;
	my $repeat;
	my $input;
	my $val;

	do {

	        $repeat = 0;
		print $stmt1;

		$input = <STDIN>;

		$val = proceed($input);

		if ($val == 1) {
			print $stmt2;
			$input = <STDIN>;
		}
		elsif ($val == 2) {
			print "Invalid command, please try again\n";
			$repeat = 1;
		} else {
			$input = 0;
		}
	} while ($repeat);
	return $input;
}

sub print_status {
	my ($color, $status, $msg) = @_;
	print color ("bold $color");
	print "[$status]\n";
	print "$msg";
	print color ("reset");
}

sub file_error {
	my ($type) = @_;
	my $msg;
	$msg = "Error $type file.  Exiting brt_install.pl\n";
	print_status ("red", "ERROR", $msg);
	exit 1;
}

sub process {
	my ($start, $finish) = @_;
	for ($i = $start; $i <= $finish; $i++) {
		print "$step[$i]->{msg}";
		$message = `$step[$i]->{command}`;
		if ($?) {
			print_status ("red", "ERROR", $message);
			return 1;
		} else {
			print_status ("green", "OK", "");
		}
	}
	return 0;
}

sub kernel_compile {
	my ($config) = @_;
	do {
		$ret = system ("make $config");

		if ($ret) {
			$message = "Error configuring kernel. Exiting environmnet.\n";
			return 1;
		} else {
			print "Kernel configured.\n";
			$q1 = "Do you need to make any additional changes? y/n:  ";
			$q2 = "Please press Return to continue . . .";
			$ret = check_step ($q1, $q2);
			$ret = !$ret;
			$config = "menuconfig";
		}
	} while ($ret);

	return 0;
}

#create environment variables and load them into memory
$begin = 0;
$end = 1;
$ret = process ($begin, $end);
if ($ret) {
    exit 1;
}

#read in partition information
print "Reading in partition infromation . . .";

if (-f "partition.dat") {
	open(FILE_IN, "< partition.dat") || file_error("opening");
	$node = "partition";
	$j = 0;
	$system_root = <FILE_IN>;
	for(<FILE_IN>){
		$i = 0;
		for $message (split) {
			$partition[$i]->{$node} = $message;
			$i++;
		}
		if ($j) {
			$node = "fs";
		} else {
			$node = "mounted";
		}
		$j++;
	}

	close(FILE_IN) || file_error ("closing");
	print_status ("green", "OK", "");
} else {
	$message = "Can't find partition.dat file.\n";
	print_status("red", "OK", $message);
	exit 1;
}

#grp gpg keys from keyserver. . . 
#if that fails, try downloading gpgkey file and import keys manually
$begin = 2;
$end = 2;
$ret = process ($begin, $end);
if ($ret) {
    print "Okay, downloading the brt public key from the keyserver failed.\nLets try downloading the brt public key file and install the public key manually. . .";
    $message = `wget -P $partition[$BOOT]->{mounted}/ http://developer.osdl.org/dev/brt/downloads/brt.gpgkey 2>&1`;
    if ($?) {
	print_status ("red", "ERROR", $message);
	exit 1;
    } else {
	$message = `gpg --import /boot/brt.gpgkey 2>&1`;
	if ($?) {
	    print_status ("red", "ERROR", $message);
	    exit 1;
	} else {
		print_status ("green", "OK", "");
	    }
    }
} elsif ($ret) {
    exit 1;
}

#update portage tree and download kernel
$begin = 3;
$end = 5;
$time = time();
$ret = process ($begin, $end);
if ($ret) {
    exit 1;
}

print "cd to kernel directory . . .";
$ret = chdir("/usr/src/linux");
if (!$ret) {
	$message = "Unable to cd into /usr/src/linux.  Exiting environment.\n";
	print_status ("red", "ERROR", $message);
	exit 1;
} else {
	print_status ("green", "OK", "");
}

#if user supplied a kernel config file, copy it to /usr/scr/linux/.config
if (-e "/boot/brt_kernel.config")
{
	$begin = 6;
	$end = 6;
	$ret = process ($begin, $end);
	if ($ret) {
	    exit 1;
	}
	$ret = kernel_compile("oldconfig");
	if ($ret) {
	    exit 1;
	}
} else {
        $ret = kernel_compile("menuconfig");
	if ($ret) {
	    exit 1;
	}
}

$message = `cat /proc/cpuinfo | grep -rn "processor" | wc`;
$message =~ m/(\d+)/;
$cpu = $1 * 2;

#compile kernel, install modules, install kernel
print "Compiling kernel . . .";
$message = `make -j $cpu 2>&1`;
if ($?) {
	print_status ("red", "ERROR", $message);
	exit 1;
} else {
	print_status ("green", "OK", "");
}
$begin = 7;
$end = 9;
$ret = process ($begin, $end);
if ($ret) {
    exit 1;
}

print "Creating /etc/fstab . . .";
$fstab_boot = "";
$fstab_root = "$partition[$ROOT]->{partition}\t/\t\t\t$partition[$ROOT]->{fs}\t\tdefaults\t1 1\n";

if ( -f "/etc/fstab.temp") {
	$message = `cat /etc/fstab.temp | grep "[[:space:]]""$partition[$BOOT]->{mounted}""[[:space:]]"`;
	if (!$? && $partition[$BOOT]->{partition}) {
		$fstab_boot = $message;
	}
}

open(FILE_OUT, "> /etc/fstab") || file_error("opening");
print FILE_OUT "#<partition>\t\t<mountpoint>\t\t<type>\t\t<opts>\t\t<dump/pass>\n";
print FILE_OUT $fstab_boot;
print FILE_OUT $fstab_root;
print FILE_OUT "none\t\t/proc\t\t\tproc\t\tdefaults\t0 0\n";
print FILE_OUT "none\t\t/dev/shm\t\ttmpfs\t\tdefaults\t0 0\n";
close (FILE_OUT) || file_error ("opening");

print_status ("green", "OK", "");

#Copy over /proc/mounts to /etc/mtab
$begin = 10;
$end = 10;
$ret = process ($begin, $end);
if ($ret) {
    exit 1;
}

$ret = system ("passwd");
if ($ret) {
	$message = "Trouble setting root password.  Exiting environment\n";
	exit 1;
}

#parse out information for grub menu
if ( $partition[$BOOT]->{partition} ) {
    $disk = $partition[$BOOT]->{partition};
} else {
    $disk = $system_root;
}

$disk =~ m/\/dev\/(\D+)(\d+)/;
$drive = $1;
$grub_drive = $drive;
$part = $2;
$drive =~ m/(.*)(.$)/;
$drive = $1;
$drive_num = $2;

if (!($drive && $drive_num && $part)) {
    $message = "Trouble creating grub.conf.  Exiting environment.\n";
    print_status ("red", "ERROR", $message);
    exit 1;
}

$drive_num = ord($drive_num) - 97;
$part = int($part) - 1;

print "Editing grub.conf . . .";
open (FILE_OUT, ">> /boot/grub/menu.lst") || file_error("opening");
print FILE_OUT "\ntitle brt base install\n";

if ( $partition[$BOOT]->{partition} ) {
    print FILE_OUT "kernel ($drive$drive_num,$part)/brt-bzImage root=$partition[$ROOT]->{partition}\n";
} else {
    print FILE_OUT "kernel ($drive$drive_num,$part)/boot/brt-bzImage root=$partition[$ROOT]->{partition}\n";
}

close (FILE_OUT) || file_error("closing");
print_status ("green", "OK", "");

print "\nbase_install_client.pl has successfully finished installing\n";
print "the brt base install on the client side.  Now we need to do a\n";
print "little cleanup and then boot into our new image.  Please execute\n";
print "the following commands:\n\n";
print "\t./base_install_mgr.pl clean $partition[$ROOT]->{mounted}\n\n";
print "\treboot\n\n";

exit 0;
