#!/usr/bin/perl
#
# $Revision: 1.196.1 $
# Copyright 2009 Teleflora.
#
# Apply updates to the underlying Linux operating system.
# Primarily:
#	Apply redhat errata.
#	Register with redhat
#	(Un) Register with redhat.
#	Upgrade packages as needed for either RTI v14 or Daisy 8.
#

use strict;
use warnings;
use English;
use Getopt::Long;
use POSIX;
use File::Basename;


my $CVS_REVISION = '$Revision: 1.196.1 $';
my $TIMESTAMP = strftime("%Y%m%d%H%M%S", localtime());
my $PROGNAME = basename($0);

my $HELP = 0;
my $VERSION = 0;
my $BAREMETAL = 0;
my $RTIV12 = 0;
my $RTIV14 = 0;
my $DAISYV8 = 0;
my $OSPATCHES = 0;
my $RHNSYSTEMID = 0;
my $HWPATCHES = 0;
my $RHNREG = 0;
my $REBOOT = 0;
my $SWAPON = 0;
my $FORENSICS = 0;
my $OSTOOLS = 0;
my $UPS = 0;
my $UPS_SERIAL = 0;
my $UPS_SERIAL_PORT = "/dev/ttyS0";
my $MOTD = 0;
my $SAMBA = 0;
my $INITTAB = 0;
my $ONETIMEROOT = 1;
my $IPADDR = "";
my $HOSTNAME = "";
my $TFSERVER = "rtihardware.homelinux.com";
my $KEEPDHCP = "";
my $KEEPKERNELS = 8;
my $YUMCONF = 0;
my $UPDATEDB = 0;

my $CUPSTMP = 0;
my $CUPSCONF = 0;
my $CUPSCONF_MAXJOBS = 1;
my $CUPSCONF_DISABLETEMPFILES = 1;
my $CUPSCONF_TIMEOUTS = 1;
my $CUPSCONF_ERRORPOLICY = 1;
my $PURGEPRINT = 0;
my $PURGERPMS = 0;
my $HARDWARE = "";
my $OS = "";

#
# Alternate os and root for testing.
#
my $ALTROOT = "";
my $ALTOS = "";
#
# Values for $ARCH: "", "x86" (32 bit), "x64" (64 bit)
#
my $ARCH = "";
#
# Values for $POSDIR: "", "/d/daisy", "/usr2/bbx"
#
my $POSDIR = "";
#
# $DAISY and $RTI are 0 (FALSE) or 1 (TRUE)
#
my $DAISY = 0;
my $RTI = 0;
#
# Path to the logfile - it will either be in the POS tree or if no POS
# has yet been installed, then the log file will be in /tmp.
#
my $LOGFILE_PATH = "";
#
# The rev numbers are "magic" and this script has to be edited and a new
# release of ostools produced if they change - less than desirable.
#
my $BBJ = "2145830.jar.gz";
my $BLM = "blm.2145830.jar.gz";
my $JRE_X64 = "jre-6u16-linux-x64-rpm.bin"; # Get update 16 from java.com
my $JRE_X86 = "jre-6u16-linux-i586-rpm.bin";
#
# Used for fork of aide database rebuild
#
my $PID = 0;


GetOptions(
	"help" => \$HELP,
	"version" => \$VERSION,
	"baremetal" => \$BAREMETAL,
	"rti12" => \$RTIV12,
	"rti14" => \$RTIV14,
	"daisy8" => \$DAISYV8,
	"cupstmp" => \$CUPSTMP,
	"cupsconf" => \$CUPSCONF,
	"purgeprint" => \$PURGEPRINT,
	"purgerpms" => \$PURGERPMS,
	"ups" => \$UPS,
	"ups-serial" => \$UPS_SERIAL,
	"ups-serial-port=s" => \$UPS_SERIAL_PORT,
	"motd" => \$MOTD,
	"samba" => \$SAMBA,
	"inittab" => \$INITTAB,
	"ospatches" => \$OSPATCHES,
	"rhnsystemid" => \$RHNSYSTEMID,
	"ostools" => \$OSTOOLS,
	"hwpatches" => \$HWPATCHES,
	"rhnreg" => \$RHNREG,
	"hardboot" => \$REBOOT,
	"reboot" => \$REBOOT,
	"swapon" => \$SWAPON,
	"forensics" => \$FORENSICS,
	"onetimeroot" => \$ONETIMEROOT,
	"ipaddr=s" => \$IPADDR,
	"hostname=s" => \$HOSTNAME,
	"tfserver=s" => \$TFSERVER,
	"keepdhcp" => \$KEEPDHCP,
	"keepkernels=s" => \$KEEPKERNELS,
	"yumconf" => \$YUMCONF,
	"updatedb" => \$UPDATEDB,
	"altroot=s" => \$ALTROOT,
	"altos=s" => \$ALTOS,
);



# --version
if($VERSION != 0) {
	print("OSTools Version: __OSTOOLS_VERSION__\n");
	print("$PROGNAME $CVS_REVISION\n");
	exit(0);
}

# --help
if($HELP != 0) {
	usage();
	exit(0);
}


if (-d '/d/daisy') {
	$POSDIR = '/d/daisy';
	$DAISY = 1;
} elsif (-d '/usr2/bbx') {
	$POSDIR = '/usr2/bbx';
	$RTI = 1;
} else {
	$POSDIR = "";
	showinfo("Can not detect that a POS has been installed - assuming none.");
}


$OS = determine_os();

$ARCH = processor_arch();


# We must be root to do these things.
if ($EUID != 0) {
    showinfo("$PROGNAME must be run as root or with sudo");
    exit(1);
}

	showinfo("Starting $PROGNAME $CVS_REVISION...");

	# --rhnreg
	if($RHNREG != 0) {
		register_redhat();
	}

	# --baremetal
	if($BAREMETAL != 0) {
		showinfo("Using Teleflora Package Server: \"$TFSERVER\"");
		baremetal_install();
	}

	# --ospatches
	if($OSPATCHES != 0) {
		update_ospatches();
	}

	# --rhnsystemid
	if($RHNSYSTEMID != 0) {
		exit(report_rhn_system_id());
	}

	# --ostools
	if($OSTOOLS != 0) {
		exit(update_ostools());
	}

	# --hwpatches
	if($HWPATCHES != 0) {
		exit(update_hwpatches());
	}

	# --rti14
	if($RTIV14 != 0) {
		my $ipaddr = ($IPADDR eq "") ? "192.168.1.21" : $IPADDR;
		exit(install_rtiv14_packages($ipaddr));
	}


	# --rti12
	if($RTIV12 != 0) {
		install_rtiv12_packages();
	}


	# --daisy8
	if($DAISYV8 != 0) {
		install_daisyv8_packages();
	}

	# --ipaddr=x.x.x.x
	if ($IPADDR) {
		configure_ip_addr($IPADDR);
	}

	# --hostname=somename
	if ($HOSTNAME) {
		update_hostname($HOSTNAME);
	}

	# --cupstmp
	if ($CUPSTMP != 0) {
		cups_clean_tempfiles();
	}

	# --cupsconf
	if ($CUPSCONF != 0) {
		cups_edit_conf();
	}

	# --purgeprint
	if($PURGEPRINT != 0) {
		purge_printjobs();
	}

	# --purgerpms
	if($PURGERPMS != 0) {
		purge_rpms();
	}

	# --ups
	if ($UPS || $UPS_SERIAL) {
		exit(install_apcupsd());
	}

	# --motd
	if($MOTD != 0) {
		exit(modify_motd());
	}

	# --samba
	if($SAMBA != 0) {
		if(-d "/usr2/bbx/bbxd") {
			exit(modify_samba("rti"));
		} elsif (-d "/d/daisy") {
			exit(modify_samba("daisy"));
		} else {
			print("Error: Could not identify which POS is installed. No samba changes were made.\n");
		}
	}

	# --inittab
	if($INITTAB != 0) {
		exit(modify_inittab());
	}

	# --updatedb
	if($UPDATEDB != 0) {
		exit(modify_updatedb());
	}

	# --hardboot
	# --reboot
	if($REBOOT != 0) {
		exit(hard_reboot());
	}

	# --swapon
	if($SWAPON != 0) {
		exit(swapon());
	}

	# --forensics
	if($FORENSICS != 0) {
		exit(forensics());
	}

	# --yumconf
	if ($YUMCONF) {
		update_yum_config();
	}


exit(0);
###################################################
###################################################
###################################################


sub usage
{
	print(<< "EOF");
$PROGNAME Usage:

$PROGNAME --version
$PROGNAME --help
$PROGNAME --baremetal
$PROGNAME --rti12 [--tfserver=rtihardware.homelinux.com]
$PROGNAME --rti14 [--tfserver=rtihardware.homelinux.com]
$PROGNAME --daisy8 [--tfserver=rtihardware.homelinux.com] [--keepdhcp]
$PROGNAME --ostools
$PROGNAME --reboot

-- Advanced Options --
$PROGNAME --ipaddr=192.168.1.x
$PROGNAME --hostname=somename
$PROGNAME --keepkernels=6
$PROGNAME --cupstmp
$PROGNAME --cupsconf
$PROGNAME --purgeprint
$PROGNAME --purgerpms
$PROGNAME --ups
$PROGNAME --ups-serial
$PROGNAME --ups-serial-port=/dev/ttySn 
$PROGNAME --motd
$PROGNAME --samba
$PROGNAME --ospatches
$PROGNAME --rhnsystemid
$PROGNAME --hwpatches
$PROGNAME --inittab
$PROGNAME --rhnreg
$PROGNAME --swapon
$PROGNAME --yumconf
$PROGNAME --updatedb
$PROGNAME --forensics > /tmp/forensics.txt
EOF

}



# Register with the redhat portal.
# Make sure our rhn daemon is enabled.
sub register_redhat
{
	my $svctag = "";
	my $vendor = "";
	my $hardware = "";
	my $rpm_url = "";

	system("grep Cent /etc/redhat-release > /dev/null 2> /dev/null");
	if($? == 0) {
		showinfo("CentOS does not need to register.");
		return;
	}

	showinfo("Obtaining a Redhat License...");


	# Get our service tag number
	# Get the "type of" hardware we are on. 
	# (Note this could be inaccurate if we bare-metal restore to a different box.)
	open(PIPE, "/usr/sbin/dmidecode | grep -A 5 \"System Information\" |");
	while(<PIPE>) {
		chomp;
		if(/(Manufacturer:)(\s+)(\S+)/) {
			$vendor = $3;
		}
		if(/(Serial Number:)(\s+)(\S+)/) {
			$svctag = uc($3);
		}
		if(/(Product Name:)([[:print:]]+)([\s*\d+\s*]+)$/) {
			$hardware = $2;
		}

	}
	close(PIPE);



	# Redhat Workstation -> Redhat Enterprise Update
	# THis to keep our redhat licensing up-to-snuff.
	# Note this process is per an email from Ian at Redhat.
	system("rpm -qa | grep redhat-release | grep 'redhat-release-5Client' > /dev/null 2> /dev/null");
	if($? == 0) {
		showinfo("Upgrading Redhat Workstation to Redhat Enterprise Linux...");
		# Replace RPMs.
		if("$ARCH" eq "x64") {
			$rpm_url = "http://$TFSERVER/ks/redhat-release-5Server-5.5.0.2.x86_64.rpm";
			system("rpm -Uvh --oldpackage $rpm_url");
		} else {
			$rpm_url = "http://$TFSERVER/ks/redhat-release-5Server-5.5.0.2.i386.rpm";
			system("rpm -Uvh --oldpackage $rpm_url");
		}
	}

	my $profile_name = "--profilename \"$svctag $vendor $hardware\"";
	my $activation_key = "--activationkey=0ad77379739f3e7b6c3263070a1ab0dc";

	system("/usr/sbin/rhnreg_ks --force $profile_name $activation_key");


	foreach my $service_name ("rhnsd", "yum-updatesd") {
		if (-f "/etc/rc.d/init.d/$service_name") {
			system("/sbin/chkconfig --level 3 $service_name on");
			system("/sbin/chkconfig --level 5 $service_name on");
		}
	}

	#
	# Grab and print system ID here.
	# Verify that the Redhat Network Registration succeeded.
	# And let the user know.
	#
	my $rhn_system_id = get_rhn_system_id();

	if ($rhn_system_id ne "") {
		showinfo("Redhat system id: $rhn_system_id");
	} else {
		showerror("Unable to obtain a Redhat License...");
	}
}


#
# Sort of a "post install" set of steps for a new server.
#
sub baremetal_install
{

	identify_hardware();
	register_redhat();

	remount_partition("/", "/");
	remount_partition("SWAP-sda2", "swap");
	remount_partition("SWAP-sda3", "swap");
	remount_partition("SWAP-sda4", "swap");


	showinfo("Configuring System...");
	system("yum install -y nmap");

	modify_inittab();
	modify_updatedb();
	modify_motd();
	install_apcupsd();
	cups_edit_conf();

	# Update our OS Tools.
	#update_ostools();

}


#
# Modify system config file: /etc/sysconfig/network-scripts/ifcfg-eth0
#
# change BOOTPROTO=dhcp --> BOOTPROTO=static
# add IPADDR=192.168.1.21
# add NETMASK=255.255.255.0
# add GATEWAY=192.168.1.1
#
sub configure_ip_addr
{
	my $ipaddr = $_[0];
	my $conf_file = '/etc/sysconfig/network-scripts/ifcfg-eth0';
	my $new_conf_file = "$conf_file.$$";

	showinfo("Setting Host IP Address (eth0) to \"$ipaddr\"...");
	if ($ipaddr !~ /^([\d]+)\.([\d]+)\.([\d]+)\.([\d]+)$/) {
		showerror("invalid: $ipaddr");
		return;
	}

	my $is_invalid = 0;
	foreach my $s (($1, $2, $3, $4)) {
		if ($1 != 192 || $2 != 168 || $3 != 1 || $4 < 2 || $4 > 254) {
			$is_invalid = 1;
			last;
		}
	}
	if ($is_invalid) {
		showerror("invalid: $ipaddr");
		return;
	}

	unless (-f "$conf_file") {
		showerror("$conf_file does not exist.");
		return;
	}

	unless (open(OLD, "< $conf_file")) {
		showerror("Could not open $conf_file for read.");
		return;
	}

	unless (open(NEW, "> $new_conf_file")) {
		showerror("Could not open $new_conf_file for write.");
		close(OLD);
		return;
	}

	my $is_already_static = 0;
	while (<OLD>) {
		if (/^BOOTPROTO=static/) {
			$is_already_static = 1;
		} elsif (/^BOOTPROTO=dhcp/) {
			print(NEW "BOOTPROTO=static\n");
		} else {
			# By default, just copy what we read.
			print(NEW $_);
		}
	}

	close(OLD);
	close(NEW);

	if ($is_already_static) {
		showerror("System already configured for static IP address.");
		system("rm $new_conf_file");
		return;
	}

	# It's an error if the new conf file is zero length at this point.
	if (-z $new_conf_file) {
		showerror("new conf file is zero length.");
		system("rm $new_conf_file");
		return;
	}

	# Open new conf file again to append some more lines.
	unless (open(NEW, ">> $new_conf_file")) {
		showerror("Could not open $new_conf_file for append.");
		close(OLD);
		return;
	}
	print(NEW "# Configuration generated by $PROGNAME $CVS_REVISION $TIMESTAMP\n");
	print(NEW << "EOF");
IPADDR=$ipaddr
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
EOF
	close(NEW);

	# Assume conf file was successfully transformed... so replace the old one with the new.
	system("chmod --reference=$conf_file $new_conf_file");
	system("chown --reference=$conf_file $new_conf_file");
	system("mv $new_conf_file $conf_file");

	print("Reboot or run \"# service network restart\" to activate network changes.\n");
}


sub update_hostname
{
	my $newname = $_[0];

	if ( ! defined($newname) || ($newname eq "") ) {
		showerror("No New Hostname specified to change to.");
		return;
	}

	showinfo("Updating Hostname to \"$newname\"...");

        #
        # On Redhat systems, the steps for changing the hostname are:
        # 1) edit /etc/sysconfig/network
        # 2) edit /etc/hosts
        # 3) run the hostname command
        # 4) reboot or at least restart the network service
        #

	system("perl -p -i -e 's/^HOSTNAME=.*/HOSTNAME=$newname/' /etc/sysconfig/network");
	if ($? != 0) {
                showerror("Error setting hostname: could not change /etc/sysconfig/network.");
                return;
        }


	# edit hosts file.
        open(OLDFILE, "< /etc/hosts");
        open(NEWFILE, "> /etc/hosts.$$");
        while (<OLDFILE>) {
                if (/^127.0.0.1[ \t]+/) {
                        print(NEWFILE "127.0.0.1\t$newname localhost.localdomain localhost\n");
                } else {
                        print(NEWFILE "$_");
                }
        }
        close(OLDFILE);
        close(NEWFILE);
	system("mv /etc/hosts.$$ /etc/hosts");


        system("hostname $newname");
        if ($? != 0) {
                showerror("Error setting hostname: hostname command error.");
                return "";
        }

        showinfo("Reboot system after installation to complete change of hostname to $newname.");

        return ($newname);
}





sub update_ospatches
{

	unless ( ($OS eq "RHEL4") || ($OS eq "RHEL5") || ($OS eq "RHWS5") ) {
		return;
	}

	showinfo("Installing OS Patches...");


	# Redhat Enterprise Client Workstation -> Redhat Enterprise Server Update
	# THis to keep our redhat licensing up-to-snuff.
	# Note this process is per an email from Ian at Redhat.
	system("rpm -qa | grep redhat-release | grep 'redhat-release-5Client' > /dev/null 2> /dev/null");
	if($? == 0) {
		print("Will Upgrade Redhat Enterprise Client Workstation to Redhat Enterprise Server Linux...\n");
		# Replace RPMs.
		if("$ARCH" eq "x64") {
			system("rpm -Uvh --oldpackage http://$TFSERVER/ks/redhat-release-5Server-5.5.0.2.x86_64.rpm");
		} else {
			system("rpm -Uvh --oldpackage http://$TFSERVER/ks/redhat-release-5Server-5.5.0.2.i386.rpm");
		}
	}

	identify_hardware();

	my $rhn_update_logfile = "/tmp/RHNupdate.log";
	my $hostname = qx(hostname -a);
	my $recipient = "rhn\@rtimail.homelinux.com";

	#
	# Look at the path... if this script is being run under Altiris on
	# either RHEL4 or RHEL5 systems, then both the "up2date" script and
	# the "yum" script, both written in Python, need to have their library path
	# set back to the standard default or it gets a "missing symbol" error
	# from the set of libs used in the Altirus env.
	#
	my $LDLIBPATH = "";
	if ($ENV{'PATH'} =~ /^\/opt\/altiris/) {
		$LDLIBPATH = "LD_LIBRARY_PATH=/lib:/usr/lib";
	}

	# Do our OS Upgrade here.
	# Note, no upgrades for RH72, FC3, or FC5.
	if($OS eq "RHEL4") {

		purge_rpms();

		# "-uf" = update system and force installation
		my $up2date_cmd = '/usr/sbin/up2date -uf';
		system("$LDLIBPATH $up2date_cmd | tee $rhn_update_logfile");
		if ($? == 0) {
			system("mail -s \"RHN update for $hostname\" $recipient < $rhn_update_logfile");
		}

		#
		# Only install the digi drivers into the kernel on rti systems.
		#
		if ($RTI) {
			update_ospatches_kernel_fixup();
		}

	} elsif ( ($OS eq "RHEL5") || ($OS eq "RHWS5") ) {

		#
		# comment out the line in /etc/yum.conf which disables kernel updates
		#
		update_yum_config();

		purge_rpms();

		loginfo("yum clean -y all");
		system("$LDLIBPATH yum clean -y all | tee $rhn_update_logfile");

		loginfo("yum update -y");
		system("$LDLIBPATH yum update -y | tee --append $rhn_update_logfile");
		if ($? == 0) {
			system("mail -s \"RHN update for $hostname\" $recipient < $rhn_update_logfile");
		}

		#
		# Only install the digi drivers into the kernel on rti systems.
		#
		if ($RTI) {
			update_ospatches_kernel_fixup();
		}
	}

	# It is possible that our OS updated sshd, in which case,
	# the 'tfremote' hard links should be re-established. By doing so,
	# tfremote will use the 'newly updated' sshd.
	if (-f "/usr/sbin/tfremote" && -f "/usr/sbin/sshd") {
		system("rm -f /usr/sbin/tfremote");
		system("ln /usr/sbin/sshd /usr/sbin/tfremote");
	}

	reset_aide_database();
}


#
# For each installed kernel, install the Digi drivers if not already installed.
# If the drivers are needed and not downloaded yet, download them.
#
sub update_ospatches_kernel_fixup
{
	my $tmpdir = '/tmp';			# use /tmp for working storage
	my $kern_modules_path = '/lib/modules';	# location of kernel modules
	my $kern_drivers_dir = 'misc';		# subdir for kernel drivers

	# the digi drivers tar file is assumed to contain two files: dgap.ko and dgrp.ko
	my $digi_drivers_tarfile = 'ES4Digidrivers.tar.gz';
	if ( ($OS eq "RHEL5") || ($OS eq "RHWS5") ) {
		$digi_drivers_tarfile = 'WS5digi.tar.gz';
	}
	my $digi_dgap_file = 'dgap.ko';
	my $digi_dgrp_file = 'dgrp.ko';
	my $digi_drivers_path = "$tmpdir/$digi_drivers_tarfile";
	my $digi_dgap_path = "$tmpdir/$digi_dgap_file";
	my $digi_dgrp_path = "$tmpdir/$digi_dgrp_file";

	# the digi drivers tar file should be available on the ostools web site
	my $ostools_url = "http://$TFSERVER/ostools";
	my $digi_drivers_url = "$ostools_url/$digi_drivers_tarfile";

	showinfo("Installing Digi Drivers...");

	my @kernel_list = glob("$kern_modules_path/*");
	unless (@kernel_list) {
		showerror("directory of kernel modules empty: /lib/modules.");
		return;
	}

	foreach my $thiskern (@kernel_list) {

		#
		# This path should look like: /lib/modules/2.6.18-194.8.1.el/misc
		#
		my $kern_drivers_path = "$thiskern/$kern_drivers_dir";

		# if there is no drivers dir, make one
		unless (-d "$kern_drivers_path") {
			system("mkdir $kern_drivers_path");
		}
		unless (-d "$kern_drivers_path") {
			showerror("kernel drivers directory missing: $kern_drivers_path.");
			next;
		}

		# if both drivers are present, nothing to do
		next if (-f "$kern_drivers_path/$digi_dgap_file" && -f "$kern_drivers_path/$digi_dgrp_file");

		#
		# One or more drivers not installed...
		# So download drivers if not already downloaded and then install them
		#
		unless (-f $digi_drivers_path) {

			showinfo("Downloading Digi Drivers from $digi_drivers_url...");

			system("curl -o $digi_drivers_path $digi_drivers_url");
			if ($? != 0) {
				showerror("download of digi drivers failed: $digi_drivers_url.");
				return;
			}
			system("cd $tmpdir && tar zxf $digi_drivers_path");
			if ($? != 0) {
				showerror("untar of digi drivers failed: $digi_drivers_path.");
				return;
			}
		}

		showinfo("Installing Digi Drivers in kernel $thiskern...");

		# install the drivers
		system("cp $digi_dgap_path $kern_drivers_path");
		system("chown root:root $kern_drivers_path/$digi_dgap_file");
		system("chmod 664 $kern_drivers_path/$digi_dgap_file");
		system("cp $digi_dgrp_path $kern_drivers_path");
		system("chown root:root $kern_drivers_path/$digi_dgrp_file");
		system("chmod 664 $kern_drivers_path/$digi_dgrp_file");
	}

	if (-f $digi_drivers_path) {
		system("rm $digi_drivers_path");
		system("rm $digi_dgap_path");
		system("rm $digi_dgrp_path");
	}
}

sub update_yum_config
{
        my $timestamp = strftime("%Y-%m-%d_%H%M%S", localtime());
        my $conf_file = '/etc/yum.conf';
        my $new_conf_file = "$conf_file-$timestamp";

        # grep returns non-zero if search pattern not found
        system("grep '^exclude=kernel' $conf_file > /dev/null 2> /dev/null");
        if ( (WIFEXITED($?) != 0) && (WEXITSTATUS($?) != 0) ) {
                return(1);
        }

        unless (-s "$conf_file") {
                showerror("$conf_file does not exist...  Will skip edits.");
                return(2);
        }

        unless (open(OLD, "< $conf_file")) {
                showerror("Could not open $conf_file for read... Will skip edits.");
                return(3);
        }

        unless (open(NEW, "> $new_conf_file")) {
                showerror("Could not open $new_conf_file for write... Will skip edits.");
                close(OLD);
                return(4);
        }
        while (<OLD>) {
                chomp;

                if ( /^(\s*)exclude=kernel/ ) {
                        print(NEW "# --- following line commented out ---\n");
                        print(NEW "# $_\n");
			next;
                }

                # By default, just copy what we read.
                print(NEW "$_\n");

        }

        close(OLD);
        close(NEW);

        # If we created a new conf file that is zero sized, that is bad.
        if (-z $new_conf_file) {
                showerror("Copy of $conf_file is a zero size file. Will skip edits.");
                system("rm $new_conf_file");
                return(5);
        }

        # Assume conf file was successfully transformed... so replace the old one with the new.
        system("chmod --reference=$conf_file $new_conf_file");
        system("chown --reference=$conf_file $new_conf_file");
        system("mv $new_conf_file $conf_file");

	return(0);
}


# Just grab and run an install script from our website.
# Let that script do the hard work.
sub update_ostools
{
	print("Updating Teleflora OS Tools...\n");
	system("wget -O - http://$TFSERVER/ostools/install-ostools.pl | sudo perl - --update");
	return($?);
}


#
# Fetch various patches related to hardware; in particular, BIOS updates, disk controllers, and so forth.
# These are typically Dell "bios/firmware" updates.
#
sub update_hwpatches
{
	my @progs = ();
	my $thisprog = "";
	identify_hardware();



	system("/usr/sbin/dmidecode | grep \" Dell \" > /dev/null 2> /dev/null");
	if($? == 0) {
		# These steps taken basically right off of...
		# http://linux.dell.com/repo/hardware/latest/
		system("rm -f /tmp/bootstrap.cgi");
		system("wget -q -O /tmp/bootstrap.cgi http://linux.dell.com/repo/hardware/latest/bootstrap.cgi");
		system("chmod a+rx /tmp/bootstrap.cgi");
		system("sudo /tmp/bootstrap.cgi");
		system("rm -f /tmp/bootstrap.cgi");
		if("$OS" eq "RHEL4") {
			system("up2date -i dell_ft_install");
		} else {
			system("yum install -y dell_ft_install");
		}
		system("sudo inventory_firmware");
		system("sudo update_firmware");
	}



	if("$HARDWARE" eq "t410") {
		@progs = ();
		print("Updating Firmware for Dell Poweredge T410 Server...\n");


		# "Remote Access Utilities"
		push(@progs, "http://ftp.us.dell.com/sysman/OM_6.1.0_MgmtStat_A00.tar.gz");

		foreach $thisprog (@progs) {
			system("cd /tmp && wget $thisprog");
		}
	}




	if("$HARDWARE" eq "t300") {
		@progs = ();
		print("Updating Firmware for Dell T300 Server...\n");


		# DSET
		push(@progs, "http://ftp.us.dell.com/diags/dellset_v1.9.0.131_A02.bin");

		# DRAC
		push(@progs, "http://ftp.us.dell.com/sysman/RAC_FRMW_LX_R253040.BIN");

		# "Remote Access Utilities"
		push(@progs, "http://ftp.us.dell.com/sysman/OM_6.1.0_MgmtStat_A00.tar.gz");

		foreach $thisprog (@progs) {
			system("cd /tmp && wget $thisprog");
		}
	}

	if("$HARDWARE" eq "1800") {

		@progs = ();


		# "Remote Access Utilities"
		push(@progs, "http://ftp.us.dell.com/sysman/OM_6.1.0_MgmtStat_A00.tar.gz");

		foreach $thisprog (@progs) {
			system("cd /tmp && wget $thisprog");
		}
	}


	if("$HARDWARE" eq "t3500") {
		print("Updating Firmware for Dell T3500 Server...\n");

		# Toolkit for managing BIOS settings from within linux.
		system("cd /tmp && wget -O - http://ftp.us.dell.com/sysman/cctk-linux-1.1.0-77.tar.gz | tar -xzvf -");
		if("$OS" eq "RHEL4") {
			system("rpm -ivh /tmp/cctk*.rpm");
		} else {
			system("yum localinstall -y /tmp/cctk*.rpm");
		}

	}

	if("$HARDWARE" eq "t3400") {
		@progs = ();


		foreach $thisprog (@progs) {
			system("cd /tmp && wget $thisprog");
		}
	}

	if("$HARDWARE" eq "390") {
		print("Updating Firmware for Dell 390 Server...\n");

		foreach $thisprog (@progs) {
			system("cd /tmp && wget $thisprog");
		}

	}

	if("$HARDWARE" eq "380") {
		print("Updating Firmware for Dell 380 Server...\n");

		foreach $thisprog (@progs) {
			system("cd /tmp && wget $thisprog");
		}
	}

}


# Disable X-WIndows for those older FC3, FC5 and RHEL4 customers.
# This falls under the PCI auspice of "disabling sfotware without a business need."
sub modify_inittab
{
	# inittab
	if (-f "/etc/inittab") {
		showinfo("Modifying inittab.");
		open(OLDFILE, "< /etc/inittab");
		open(NEWFILE, "> /etc/inittab.$$");
		while(<OLDFILE>) {

			# PCI 2.2.2
			if(/(:)(\s*)(initdefault)(\s*)(:)/i) {
				print(NEWFILE "id:3:initdefault:\n");
				next;
			}

			print(NEWFILE);
		}
		close(OLDFILE);
		close(NEWFILE);

		if(! -z "/etc/inittab.$$") {
			system("mv /etc/inittab.$$ /etc/inittab");
		}
	}

	return(0);
}

#
# Make sure the daily 'locate' db update is enabled.  And to do that,
# we need to make sure the contents of /etc/updatedb.conf file is appropriate.
#
# The updatedb job is run out of /etc/cron.daily cron job so it will
# normally be run every day.  However, we believe that FC3 installations
# of Linux have some logic like the following in the "locate" cron job:
#
#	. /etc/updatedb.conf
#	[ "$DAILY_UPDATE" != "YES" ] && exit 0
#
# So, if a line like "DAILY_UPDATE=YES" does not appear in the
# /etc/updatedb.conf file, then the cron job will not run.
#
# We do know that RHEL5 does not have this logic and in fact updatedb
# outputs a diagnostic if the conf file is changed to add "DAILY_UPDATE"...
#
sub modify_updatedb
{
    #
    # We were using the perl "constant" module for the constants below
    # but RH72 doesn't have it so we must resort to just local vars.
    #
    my $UPDATEDB_REMOVE_IT = 0;
    my $UPDATEDB_ADD_IT = 1;
    my $UPDATEDB_LEAVE_IT = 2;

    my $conf_file = "$ALTROOT/etc/updatedb.conf";

    unless (-f $conf_file) {
	showinfo("$conf_file: file does not exist");
	return(0);
    }

    my $edit_action = $UPDATEDB_REMOVE_IT;

    #
    # Set flag for "remove it" systems.
    #
    if ($OS eq "RHEL5" || $OS eq "RHEL4" || $OS eq "FC5" || $OS eq "RH72") {
	$edit_action = $UPDATEDB_REMOVE_IT;

    #
    # Set flag for "add it" systems.
    #
    } elsif ($OS eq "FC3") {
	$edit_action = $UPDATEDB_ADD_IT;

    #
    # anything else, we don't know what to do, so do nothing.
    #
    } else {
	showinfo("No action taken for OS type: $OS");
	return(0);
    }

    #
    # OK, we have to modify the file.
    #
    showinfo("Modifying updatedb config file: $conf_file.");
    open(OLDFILE, "< $conf_file");
    open(NEWFILE, "> $conf_file.$$");
    while (<OLDFILE>) {
	if (/^(\s*)(DAILY_UPDATE)(.+)(YES)/) {
	    if ($edit_action == $UPDATEDB_REMOVE_IT) {
		print(NEWFILE "### $PROGNAME $TIMESTAMP: following line commented out\n");
		print(NEWFILE "### $_");
		next;
	    } elsif ($edit_action == $UPDATEDB_ADD_IT) {
		$edit_action = $UPDATEDB_LEAVE_IT;
	    }
	}
	print(NEWFILE $_);
    }

    if ($edit_action == $UPDATEDB_ADD_IT) {
	print(NEWFILE "DAILY_UPDATE=YES\n");
    }
    close(OLDFILE);
    close(NEWFILE);

    if (! -z "$conf_file.$$") {
	system("mv $conf_file.$$ $conf_file");
	if ($? != 0) {
	    showerror("Can't move new instance of $conf_file into place");
	    showinfo("$conf_file unchanged");
	    system("rm $conf_file.$$");
	    return(1);
	}
    }

    showinfo("New instance written: $conf_file");

    return(0);
}

#
# Clear out the login banner file, /etc/motd.
#
# There is no PCI requirement driving this file's contents.
#
sub modify_motd
{
        my $conf_file = "$ALTROOT/etc/motd";
        my $new_conf_file = "$conf_file.$$";

	showinfo("Truncating Login Banner File: /etc/motd...");

        if (! -f "$conf_file") {
                showerror("File does not exist: $conf_file...  Will skip edits.");
                return(1);
        }

	# make new empty motd file
	system("touch $new_conf_file");

	# did we successfully make a new motd file?
        if (! -f "$new_conf_file") {
                showerror("Can't make new motd file: $new_conf_file...  Will skip edits.");
                return(1);
        }

        # replace the old one with the new.
        system("chmod --reference=$conf_file $new_conf_file");
        system("chown --reference=$conf_file $new_conf_file");
        system("mv $new_conf_file $conf_file");
        if ($? != 0) {
                showerror("Can't replace old motd file.");
		system("rm -f $new_conf_file");
                return(1);
        }

	return(0);
}


sub modify_samba
{
	my $pos = $_[0];


	unless (-f "/etc/samba/smb.conf") {
		showerror("/etc/samba/smb.conf does not exist.");
		return;
	}
	open(FILE, "> /etc/samba/smb.conf");


	####################################
	#### RTI Samba Config
	####################################
	if("$pos" eq "rti") {

		# Do nothing if an smb.conf is already in place.
		system("grep usr2 /etc/samba/smb.conf > /dev/null 2> /dev/null");
		if($? == 0) {
			showinfo("RTI /etc/samba/smb.conf already appears to be modified. Will not touch this file.");
			return;
		}

		

		print(FILE "# RTI Samba Configuration\n");
		print(FILE "# Automatically generated by $PROGNAME $CVS_REVISION $TIMESTAMP\n");
		print(FILE "#\n");
		print(FILE << 'xxxEOFxxx');


#
#======================= Global Settings =====================================
[global]


server string = RTI Server
hosts allow = 192.168. 127. 10.
domain master = no
local master = no
preferred master = no
os level = 0
dns proxy = no
smb ports = 139
log file = /var/log/samba/%m.log
max log size = 50
socket options = TCP_NODELAY SO_RCVBUF=8192 SO_SNDBUF=8192
idmap uid = 16777216-33554431
idmap gid = 16777216-33554431
username map = /etc/samba/smbusers


#======================= Printer Settings =====================================
printcap name = /etc/printcap
cups options = raw

[printers]
	comment = All Printers
	path = /var/spool/samba
	browseable = no
	printable = yes

#======================= Shares =====================================
[odbc_dict]
	comment = ODBC Data Dictionary
	path = /usr2/bbx/odbc_dict
	writeable = yes
	guest ok = yes
[mapping]
        comment = Mapping
        path = /usr2/bbx/delivery
        writeable = yes
        guest ok = yes
	create mask = 0666
[tmp]
        comment = Temporary Files
        path = /tmp
        writeable =  yes
   	read only = no
   	public = yes
        guest ok = yes
[wirerec]
        comment = Wire Service Reconciliations
        path = /usr2/bbx/bbxtmp
        read only = no
        guest ok = no

[reports]
        comment = RTI Reports
        path = /usr2/bbx/reports
        read only = no
        guest ok = no

xxxEOFxxx


	####################################
	#### Daisy Samba Config
	####################################
	} elsif ("$pos" eq "daisy") {


		# Do nothing if an smb.conf is already in place.
		system("grep daisy /etc/samba/smb.conf > /dev/null 2> /dev/null");
		if($? == 0) {
			showinfo("Daisy /etc/samba/smb.conf already appears to be modified. Will not touch this file.");
			return;
		}

		print(FILE "# Daisy Samba Configuration\n");
		print(FILE "# Automatically generated by $PROGNAME $CVS_REVISION $TIMESTAMP\n");
		print(FILE "#\n");
		print(FILE << 'xxxEOFxxx');


#
#======================= Global Settings =====================================
[global]

workgroup = daisy
server string = daisyhost
netbios name = daisyhost
hosts allow = 192.168. 127. 10.
writable = yes
domain master = no
local master = no
preferred master = no
os level = 0
dns proxy = no
smb ports = 139
log file = /var/log/samba/%m.log
max log size = 50
socket options = TCP_NODELAY SO_RCVBUF=8192 SO_SNDBUF=8192
idmap uid = 16777216-33554431
idmap gid = 16777216-33554431
username map = /etc/samba/smbusers
guest account = daisy
security = share
encrypt passwords = yes


#======================= Printer Settings =====================================
printcap name = /etc/printcap
cups options = raw

[printers]
	comment = All Printers
	path = /var/spool/samba
	browseable = yes
	guest ok = yes
	writeable = no
	printable = yes
	public = yes
	

#======================= Shares =====================================

[homes]
	comment = Home Directories
	browseable = no
        writable = no

[export]
        comment = Daisy share
        path = /d/daisy/export
        writable = yes
	browseable = yes
	guest ok = yes
	printable = no
	public = yes
xxxEOFxxx
	}

	close(FILE);
	system("/sbin/service smb restart");
}



#
# Remove older kernels except three most recent.
# This to work around undersized /boot partitions on our older
# RHEL4 and RHWS5 machines.
#
sub purge_rpms
{
	my $thiskernel = "";
	my $thisrpm = "";
	my $thisfile = "";
	my $keepcount = 0;
	my $bootdir = '/boot';
	my $kernels = "$bootdir/vmlinuz-*";

	showinfo("Removing Old Kernels...");

	# Keep the "n" most recent kernels, where "n" == $KEEPKERNELS.
	# Remove everything else.

	showinfo("Searching $bootdir for Old Kernels...");

	open(FILES, "ls -dt $kernels 2>/dev/null |");
	while (<FILES>) {
		chomp;
		$thiskernel = $_;

		#
		# The kernel file must exist and should since we just found it
		#
		next unless (-e $thiskernel);

		#
		# Keep last $KEEPKERNELS kernels
		#
		$keepcount++;
		next if($keepcount <= $KEEPKERNELS);

		open(RPM, "rpm -qf $thiskernel |");
		while(<RPM>) {
			chomp;
			$thisrpm = $_;
			showinfo("Removing Kernel  $thisrpm...");
			system("rpm -e $thisrpm");
		}
		close(RPM);
	}
	close(FILES);

	# Any other RPM packages which we should delete here?
	# eg. 'X', GCC, etc.


	return(0);
}






#
# Install OS pre-requisites for RTI v14.
#
sub install_rtiv14_packages
{
	my $ipaddr = $_[0];
	my @array = ();
	my $bbj_nozip = "";
	my $line = "";
	my $need_to_change = 0;
	my $xmx = "512m";


	showinfo("Installing RTI v14 Software Dependencies...");
	showinfo("Using Teleflora Package Server \"$TFSERVER\"");

	remount_partition("/teleflora", "/usr2");

	# if booting "DHCP", convert to static at specified IP addr
	my $conf_file = '/etc/sysconfig/network-scripts/ifcfg-eth0';
	my $pattern = 'BOOTPROTO=dhcp';
	system("grep $pattern $conf_file > /dev/null 2> /dev/null");
	if($? == 0) {
		configure_ip_addr($ipaddr);
	}

	# Install Fetchmail
	system("yum -y install fetchmail");
	system("yum install -y uucp");
	system("yum install -y ksh");

	create_default_users("rti");

	#system("/usr2/bbx/bin/rtiuser.pl --add tfsupport");
	#system("/usr2/bbx/bin/rtiuser.pl --enable-admin tfsupport");
	#system("/usr2/bbx/bin/rtiuser.pl --add rti");




	# Install apache
	showinfo("Installing Apache...");
	if( ($OS eq "RHEL5") || ($OS eq "RHWS5") ) {
		system("yum -y install httpd");
	}
	if("$OS" eq "RHEL4") {
		system("up2date --install httpd");
	}

	# Samba
	system("grep delivery /etc/samba/smb.conf > /dev/null 2> /dev/null");
	if($? != 0) {
		modify_samba("rti");
	}


	# Install Java
	showinfo("Installing Java JRE...");
	if("$ARCH" eq "x86") {
		if(! -f "/tmp/$JRE_X86") {
			system("wget --proxy=off --cache=off -O /tmp/$JRE_X86 http://$TFSERVER/ks/$JRE_X86");
		}
		if(! -f "/tmp/$JRE_X86") {
			showerror("Could not download file http://$TFSERVER/ks/$JRE_X86");
		} else {
			system("chmod a+rx /tmp/$JRE_X86");
			system("/tmp/$JRE_X86");
		}

	} else {
		if(! -f "/tmp/$JRE_X64") {
			system("wget --proxy=off --cache=off -O /tmp/$JRE_X64 http://$TFSERVER/ks/$JRE_X64");
		}
		if(! -f "/tmp/$JRE_X64") {
			showerror("Could not download file http://$TFSERVER/ks/$JRE_X64");
		} else {
			system("chmod a+rx /tmp/$JRE_X64");
			system("/tmp/$JRE_X64");
		}
	}
	# Link correct java
	system("rm -f /usr/bin/java");
	system("ln -s /usr/java/latest/bin/java /usr/bin/java");

	# Install BBj
	if(-d "/usr2/basis") {
		loginfo("Moving current /usr2/basis/ to /usr2/basis-backup/...");
		system("mv /usr2/basis /usr2/basis-backup");
	} else {
		loginfo("/usr2/basis/ did not previously exist...");
	}


	
	showinfo("Installing BBj...");
	if(! -f "/tmp/$BBJ") {
		system("wget --proxy=off --cache=off -O /tmp/$BBJ http://$TFSERVER/ks/$BBJ");
		if(! -f "/tmp/$BBJ") {
			showerror("Could not download file http://$TFSERVER/ks/$BBJ");
		}
	}

	#Create bbjinstallsettings.txt
	open(BBJINST, "> /tmp/bbjinstallsettings.txt");
        print(BBJINST << 'EOF');
-V LICENSE_ACCEPT_BUTTON="true"
-V LICENSE_REJECT_BUTTON="false"
-P installLocation="/usr2/basis/"
-V IS_SELECTED_INSTALLATION_TYPE=custom
-P BBjFtrBean.active=true
-P BBjThinClientFtr_bean.active=true
-P BBjSvcs_FtrBean.active=true
-P BBjEUTFtr_bean.active=true
-P EMFeatureBean.active=true
-P adminFeatureBean.active=true
-P BBjUtilsFtr_bean.active=true
-P GMLFeatureBean.active=true
-P BWUFeatureBean.active=true
-P STDFeatureBean.active=true
-P EXTFeatureBean.active=true
-P MKRecoverFeatureBean.active=true
-P AutoLicFeatureBean.active=true
-P CLlibFeatureBean.active=true
-P JLlibFeatureBean.active=true
-P BBjDevelToolsFtr_bean.active=true
-P perfAnalyzerFeatureBean.active=false
-P compilerListerFeatureBean.active=true
-P configuratorFeatureBean.active=false
-P guiBuilderFeatureBean.active=false
-P blmFeatureBean.active=true
-P BLMadminFeatureBn.active=true
-P basisIDEfeatureBean.active=false
-P documentationFeatureBean.active=false
-P jdbcFeatureBean.active=true
-P TrainingfeatureBean.active=true
-P DemosBean.active=true
-P BaristafeatureBean.active=false
-P AddOnfeatureBean.active=false
EOF
	close(BBJINST);
	if( (-f "/tmp/$BBJ")
	&&  (-f "/tmp/bbjinstallsettings.txt")
	) {
		$bbj_nozip = $BBJ;
		$bbj_nozip =~ s/\.gz//g; # blah.jar.gz -> blah.jar
		system("gzip -dc /tmp/$BBJ > /tmp/$bbj_nozip");
		system("java -jar /tmp/$bbj_nozip -options /tmp/bbjinstallsettings.txt -silent");
	}


	# Figure out how much memory we have, and hence, what our default java "xmx" values should be set to.
	open(MEM, "< /proc/meminfo");
	while(<MEM>) {
		chomp;
		if(/MemTotal:/) {
			@array = split(/\s+/);

			# Less than a gig of memory
			if( int($array[1]) < 1000000) {
				$xmx = "512m";

			# Betweeen 1GB and 2GB
			} elsif( (int($array[1]) > 1000000) && (int($array[1]) < 2000000) )  {
				$xmx = "768m";

			# Betweeen 2GB and 3GB
			} elsif( ( int($array[1]) > 2000000) && ( int($array[1]) < 3000000))  {
				$xmx = "1024m";

			# Betweeen 3GB and 4GB
			} elsif( ( int($array[1]) > 3000000) && ( int($array[1]) < 4000000))  {
				$xmx = "1536m";

			# 4GB ++
			} else {
				$xmx = "2048m"
			}
		}
	}
	close(MEM);


	# Update BBj.properties File
	if(-f "/usr2/basis/cfg/BBj.properties") {
		loginfo("Backing up BBj.properties");
		system("mv /usr2/basis/cfg/BBj.properties /usr2/basis/cfg/BBj.properties.original");
	}
	loginfo("Updating BBj.properties");
	open(BBJPROP, "> /usr2/basis/cfg/BBj.properties");
	print(BBJPROP "# BBj Properties File\n");
	print(BBJPROP "# This file auto-generated by $PROGNAME $CVS_REVISION $TIMESTAMP\n");
	print(BBJPROP "# This file auto-generated on date: " . localtime() . "\n");
	print(BBJPROP "#\n");
	print(BBJPROP "#\n");


	print(BBJPROP << 'EOF');
#BBj Services Properties
basis.cacheDirectory=/usr2/basis/cache
basis.java.args.BBjCpl=-XX\:NewSize\=24m -client
basis.java.args.BBjLst=-XX\:NewSize\=24m -client
EOF
print(BBJPROP "basis.java.args.BBjServices=-Xmx$xmx -Xms256m ");

	print(BBJPROP << 'EOF');
 -XX\:MaxPermSize\=96m -XX\:NewSize\=64m -XX\:+UseConcMarkSweepGC -XX\:+CMSIncrementalMode -XX\:CMSIncrementalSafetyFactor\=20 -XX\:CMSInitiatingOccupancyFraction\=70 -XX\:MaxTenuringThreshold\=4 -XX\:SurvivorRatio\=14 -server -XX\:CompileCommandFile\=/usr2/basis/cfg/.hotspot_compiler -Dnetworkaddress.cache.ttl\=10 -Dsun.net.inetaddr.ttl\=10 -Djava.awt.headless\=true -verbose\:gc -Xloggc\:/usr2/basis/log/gc.log -XX\:+PrintGCDetails -XX\:+PrintGCTimeStamps -XX\:+PrintGCApplicationConcurrentTime -XX\:+PrintGCApplicationStoppedTime
basis.java.args.BasisIDE=-XX\:CompileCommandFile\=/usr2/basis//cfg/.hotspot_compiler
basis.java.args.Default=-Xmx128m -Xms128m -XX\:NewRatio\=4 -XX\:MaxPermSize\=128m -XX\:NewSize\=24m -client -XX\:CompileCommandFile\=/usr2/basis//cfg/.hotspot_compiler
basis.java.classpath=/usr2/basis//lib/BBjUtil.jar\:/usr2/basis//lib/BBjIndex.jar\:/usr2/basis//lib/FontChooser.jar\:/usr2/basis//lib/DemoClientFiles.jar\:/usr2/basis//lib/ClientObjects.jar\:/usr2/basis//lib/examples.jar\:/usr2/basis//lib/jfreechart-experimental.jar\:/usr2/basis//lib/jna.jar\:/usr2/basis//lib/swingx.jar\:/usr2/basis//lib/TimingFramework.jar\:/usr/java/latest/lib/ext/jdic_stub_unix.jar
basis.java.jvm.BBjServices=/usr/java/latest/bin/java
basis.java.jvm.Default=/usr/java/latest/bin/java
basis.java.skin=
basis.pdf.fontpath=
com.basis.bbj.bridge.BridgeServer.bindAddr=0.0.0.0\:2007
com.basis.bbj.bridge.BridgeServer.maxClients=100
com.basis.bbj.bridge.BridgeServer.start=false
com.basis.bbj.comm.FacadeFactory.suppressClientObjErrorsOnVoidMethods=true
com.basis.bbj.comm.InterpreterServer.backLog=110
com.basis.bbj.comm.InterpreterServer.bindAddr=127.0.0.1\:2005
com.basis.bbj.comm.InterpreterServer.maxClients=500
com.basis.bbj.comm.InterpreterServer.start=false
com.basis.bbj.comm.PortRequestServer.bindAddr=127.0.0.1\:2008
com.basis.bbj.comm.PortRequestServer.maxClients=500
com.basis.bbj.comm.PortRequestServer.start=true
com.basis.bbj.comm.ProxyManagerServer.bindAddr=127.0.0.1\:2009
com.basis.bbj.comm.ProxyManagerServer.maxClients=100
com.basis.bbj.comm.ProxyManagerServer.start=false
com.basis.bbj.comm.RuntimeMgr.notifyUserOnInternalError=false
com.basis.bbj.comm.RuntimeMgr.releaseOnLostConnection=true
com.basis.bbj.comm.RuntimeMgr.requireAllSendMsgResponses=false
com.basis.bbj.comm.RuntimeMgr.suppressPrinterAckBack=true
com.basis.bbj.comm.RuntimeMgr.suppressUIAckBack=true
com.basis.bbj.comm.RuntimeMgr.useDvkLicenseIfPresent=true
com.basis.bbj.comm.SecureThinClientServer.backLog=110
com.basis.bbj.comm.SecureThinClientServer.bindAddr=0.0.0.0\:2103
com.basis.bbj.comm.SecureThinClientServer.disallowConsole=true
com.basis.bbj.comm.SecureThinClientServer.maxClients=500
com.basis.bbj.comm.SecureThinClientServer.start=true
com.basis.bbj.comm.SecureThinClientServer.webUser=rti
com.basis.bbj.comm.TerminalServer.backLog=110
com.basis.bbj.comm.TerminalServer.bindAddr=127.0.0.1\:2004
com.basis.bbj.comm.TerminalServer.maxClients=500
com.basis.bbj.comm.TerminalServer.start=true
com.basis.bbj.comm.ThinClientProxyServer.backLog=110
com.basis.bbj.comm.ThinClientProxyServer.bindAddr=127.0.0.1\:2006
com.basis.bbj.comm.ThinClientProxyServer.err=/usr2/basis/log/ThinClientProxyServer.err
com.basis.bbj.comm.ThinClientProxyServer.keepLogs=7
com.basis.bbj.comm.ThinClientProxyServer.maxClients=500
com.basis.bbj.comm.ThinClientProxyServer.out=/usr2/basis/log/ThinClientProxyServer.out
com.basis.bbj.comm.ThinClientProxyServer.sizeM=10
com.basis.bbj.comm.ThinClientProxyServer.start=false
com.basis.bbj.comm.ThinClientProxyServer.waitTime=0
com.basis.bbj.comm.ThinClientServer.backLog=110
com.basis.bbj.comm.ThinClientServer.bindAddr=0.0.0.0\:2003
com.basis.bbj.comm.ThinClientServer.disallowConsole=true
com.basis.bbj.comm.ThinClientServer.encryptConnection=true
com.basis.bbj.comm.ThinClientServer.maxClients=500
com.basis.bbj.comm.ThinClientServer.start=false
com.basis.bbj.comm.ThinClientServer.translateAppletCmdLine=false
com.basis.bbj.comm.ThinClientServer.translateCmdLine=false
com.basis.bbj.comm.ThinClientServer.webUser=rti
com.basis.bbj.serverPinning=true
com.basis.bbj.sessionPinning=false
com.basis.filesystem.localPort=2000
com.basis.filesystem.localServer=127.0.0.1
com.basis.filesystem.remote.securedataserver.encrypter=com.basis.filesystem.remote.securedataserver.DefaultEncrypter
com.basis.server.LookAndFeel=default
com.basis.server.admin.1.defaultPort=2002
com.basis.server.admin.1.interface=0.0.0.0
com.basis.server.admin.1.start=true
com.basis.server.admin.1.useSSL=false
com.basis.server.admin.log=/usr2/basis/log/AdminServer.log
com.basis.server.allowPipe=true
com.basis.server.autorun.config=/usr2/bbx/config/config.bbx
com.basis.server.autorun.user=root
com.basis.server.autorun.workingDirectory=/usr2/bbx/
com.basis.server.configDirectory=/usr2/bbx/config
com.basis.server.exclusiveAccess=true
com.basis.server.filesystem.1.defaultPort=2000
com.basis.server.filesystem.1.defaultTimeout=2000
com.basis.server.filesystem.1.interface=0.0.0.0
com.basis.server.filesystem.1.prefixes=
com.basis.server.filesystem.1.start=true
com.basis.server.filesystem.1.useSSL=true
com.basis.server.filesystem.log=/usr2/basis/log/FilesystemServer.log
com.basis.server.memStatFrequence=15
com.basis.server.nio.override=false
com.basis.server.passwordAuth=false
com.basis.server.pro5ds.1.64bitMKeyed=false
com.basis.server.pro5ds.1.advisoryLocking=true
com.basis.server.pro5ds.1.defaultPort=2100
com.basis.server.pro5ds.1.defaultTimeout=5
com.basis.server.pro5ds.1.interface=0.0.0.0
com.basis.server.pro5ds.1.maskMKeyedFID=false
com.basis.server.pro5ds.1.prefixes=
com.basis.server.pro5ds.1.scanAllRoots=false
com.basis.server.pro5ds.1.start=false
com.basis.server.pro5ds.1.tagged=false
com.basis.server.pro5ds.1.umask=0000
com.basis.server.pro5ds.1.useSSL=true
com.basis.server.pro5ds.log=/usr2/basis/log/Pro5DSServer.log
com.basis.server.programCacheFile=/usr2/basis/cfg/BBjCache.txt
com.basis.server.programCacheSize=300
com.basis.server.resourceCacheFile=/usr2/basis//cfg/BBjResourceCache.txt
com.basis.server.skipProgramCacheFile=true
com.basis.server.sqlengine.1.debugLevel=2
com.basis.server.sqlengine.1.defaultPort=2001
com.basis.server.sqlengine.1.interface=0.0.0.0
com.basis.server.sqlengine.1.start=true
com.basis.server.sqlengine.1.useSSL=true
com.basis.server.sqlengine.log=/usr2/basis/log/SQLServer.log
com.basis.server.status.defaultPort=11057
com.basis.server.stdErr.keepLogs=7
com.basis.server.stdErr.sizeM=1
com.basis.server.stdErr=/usr2/basis/log/BBjServices.err
com.basis.server.stdOut.keepLogs=7
com.basis.server.stdOut.sizeM=1
com.basis.server.stdOut=/usr2/basis/log/BBjServices.out
com.basis.server.threadPoolSize=-1
com.basis.server.workingDirectory=/usr2/bbx/
com.basis.sql.logLevel=0
com.basis.user.useFork=true
default-config=/usr2/bbx/config/config.bbx
default-user=root
default-working-dir=/usr2/basis/bin
sun.arch.data.model=32
EOF
	close(BBJPROP);
	#Done creating BBj.properties


	# Basis License Manager.
	showinfo("Installing Basis License Manager...");
	if(! -f "/tmp/$BLM") {
		system("wget --proxy=off --cache=off -O /tmp/$BLM http://$TFSERVER/ks/$BLM");
		if(! -f "/tmp/$BLM") {
			showerror("Could not download file http://$TFSERVER/ks/$BBJ");
		}
	}
	if(-f "/tmp/$BLM") {
		$bbj_nozip = $BLM;
		$bbj_nozip =~ s/\.gz//g; # blah.jar.gz -> blah.jar
		system("gzip -dc /tmp/$BLM > /tmp/$bbj_nozip");
		system("java -jar /tmp/$bbj_nozip");
	}
	# Basis Admin to setup BBj in general (May need to manually do this)
	showinfo("Running Basis Admin Menu...");
	system("/usr2/basis/bin/admin");

	return(0);
}


sub install_rtiv12_packages
{


	showinfo("Installing RTI v12 Software Dependencies...");
	showinfo("Using Teleflora Package Server \"$TFSERVER\"");


	remount_partition("/teleflora", "/usr2");
	if(! -d "/usr2/bbx/bin") {
		# This step needed to ensure update_ostools succeeds.
		system("mkdir -p /usr2/bbx/bin");
	}
	system("grep \"BOOTPROTO=dhcp\" /etc/sysconfig/network-scripts/ifcfg-eth0 > /dev/null 2> /dev/null");
	if($? == 0) {
		configure_ip_addr("192.168.1.21");
	}

	create_default_users("rti");


	showinfo("Installing Additional Packages...");
	system("yum groupinstall -y mail-server");
	system("yum install -y fetchmail");
	system("yum install -y uucp");
	system("yum install -y ksh");


	# Samba
	system("grep delivery /etc/samba/smb.conf > /dev/null 2> /dev/null");
	if($? != 0) {
		modify_samba("rti");
	}

	#system("/usr2/bbx/bin/rtiuser.pl --add rti");
}

sub install_daisyv8_packages
{
	my $dev = "";

	showinfo("Installing Daisy v8 Software Dependencies...");
	showinfo("Using Teleflora Package Server \"$TFSERVER\"");

	remount_partition("/teleflora", "/d");

	unless ( $KEEPDHCP ) {
		my $eth_config_file = '/etc/sysconfig/network-scripts/ifcfg-eth0';
		system("grep \"BOOTPROTO=dhcp\" $eth_config_file > /dev/null 2> /dev/null");
		if($? == 0) {
			configure_ip_addr("192.168.1.21");
		}
	}

	# Create a "/mnt/cdrom" item inside of /etc/fstab.
	system("grep \"\/mnt\/cdrom\" /etc/fstab > /dev/null 2> /dev/null");
	if ($? != 0) {
		open(FSTAB, ">> /etc/fstab");
		print(FSTAB "/dev/scd0\t\t/mnt/cdrom\tiso9660\tro,exec\t0 0\n");
		close(FSTAB);
	}

	unless (-d "/mnt/cdrom") {
		system("mkdir /mnt/cdrom");
	}

	unless (-d "/mnt/usb") {
		system("mkdir /mnt/usb");
	}

	# Samba
	system("grep \"/d/daisy/export\" /etc/samba/smb.conf > /dev/null 2> /dev/null");
	if($? != 0) {
		modify_samba("daisy");
	}

	#
	# For daisy systems, since the following function sets the samba password
	# for the daisy account, samba must already be running.
	#
	create_default_users("daisy");
}



sub create_default_users
{
	my $pos = $_[0];
	my $salt = "";
	my $password = "";

	if("$pos" eq "rti") {

		system("/usr/sbin/groupadd rti");
		system("/usr/sbin/groupadd rtiadmins");


		# RTI 'tfsupport' user
		system("grep \"^tfsupport:\" /etc/passwd > /dev/null 2> /dev/null");
		if($? != 0) {
			system("/usr/sbin/useradd -g rti -G rti,rtiadmins -s /bin/bash tfsupport");
			print("\n");
			print("\n");
			print("\n");
			print(" Set 'tfsupport' User Password...\n");
			system("passwd tfsupport");
		}


		# RTI 'rti' user.
		system("grep \"^rti:\" /etc/passwd > /dev/null 2> /dev/null");
		if($? != 0) {
			$salt = join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64];
			$password = crypt("rti", $salt);
			system("/usr/sbin/useradd -p \"$password\" -g rti -s /bin/bash rti");
		}

		# RTI 'odbc' Samba user
		system("grep \"^odbc:\" /etc/passwd > /dev/null 2> /dev/null");
		if($? != 0) {
			system("/usr/sbin/useradd -g rti -s /sbin/nologin odbc");
		}

		system("grep \"^odbc:\" /etc/samba/smbpasswd > /dev/null 2> /dev/null");
		if($? != 0) {
			showinfo("Adding 'odbc' user to samba...");
			open(PIPE, "| smbpasswd -s -a odbc");
			print(PIPE "odbc99\n");
			print(PIPE "odbc99\n");
			close(PIPE);
		}

		# RTI 'deliver' samba user.
		system("grep \"^delivery:\" /etc/passwd > /dev/null 2> /dev/null");
		if($? != 0) {
			system("/usr/sbin/useradd -g rti -s /sbin/nologin delivery");
		}
		
		system("grep \"^delivery:\" /etc/samba/smbpasswd > /dev/null 2> /dev/null");
		if($? != 0) {
			showinfo("Adding 'delivery' user to samba...");
			open(PIPE, "| smbpasswd -s -a delivery");
			print(PIPE "delivery\n");
			print(PIPE "delivery\n");
			close(PIPE);
		}
	}


	if("$pos" eq "daisy") {

		system("/usr/sbin/groupadd daisy");
		system("/usr/sbin/groupadd dsyadmins");


		# Daisy 'tfsupport' user.
		system("grep \"^tfsupport:\" /etc/passwd > /dev/null 2> /dev/null");
		if($? != 0) {
			system("/usr/sbin/useradd -g daisy -G daisy,dsyadmins -s /bin/bash tfsupport");
			print("\n");
			print("\n");
			print("\n");
			print(" Set 'tfsupport' User System Password...\n");
			system("passwd tfsupport");
		}


		# Daisy 'daisy' user.
		system("grep \"^daisy:\" /etc/passwd > /dev/null 2> /dev/null");
		if($? != 0) {
			system("/usr/sbin/useradd -g daisy -s /bin/bash daisy");
			print("\n");
			print("\n");
			print("\n");
			print(" Set 'daisy' User System Password...\n");
			system("passwd daisy");

			print("\n");
			print("\n");
			print("\n");
			print(" Set 'daisy' User Samba Password...\n");
			system("smbpasswd -a daisy");
		}

	}
}

sub install_apcupsd_conf
{
	#
	# Our default config file will indicate the use of USB based interfaces.
	# Check to see if the conf file has already been customized... if so,
	# nothing to do.
	#
	system("grep updateos /etc/apcupsd/apcupsd.conf > /dev/null 2> /dev/null");
	if ($? == 0) {
		return;
	}

	my $ups_type = "usb";
	if ($UPS_SERIAL) {
		$ups_type = "serial";
	} else {
		$ups_type = identify_ups_hardware();
	}

	# save a copy of the original conf file
	if (-f '/etc/apcupsd/apcupsd.conf') {
		system("cp /etc/apcupsd/apcupsd.conf /etc/apcupsd/apcupsd.conf.orig");
	}

	print("Customizing config file for APC UPS Software...\n");

	open(FILE, "> /etc/apcupsd/apcupsd.conf");

	#
	# The first line of the file must be in a special format or the
	# apcupsd binary will complain.
	#
	print(FILE "## apcupsd.conf v1.1 ##\n");

	print(FILE "#\n");
	print(FILE "# APC UPS Config File\n");
	print(FILE "# Generated by $PROGNAME $CVS_REVISION $TIMESTAMP\n");


	if ($ups_type eq "usb") {
		print(FILE "# USB Based Interface\n");
		print(FILE "UPSCABLE usb\n");
		print(FILE "UPSTYPE usb\n");
		print(FILE "DEVICE \n");

	} else {
		print(FILE "# Serial Based Interface\n");
		print(FILE "UPSCABLE smart\n");
		print(FILE "UPSTYPE smartups\n");
		print(FILE "DEVICE $UPS_SERIAL_PORT\n");
	}

	print(FILE << "xxxEOFxxx");

UPSNAME RTIUPS
LOCKFILE /var/lock
SCRIPTDIR /etc/apcupsd
PWRFAILDIR /etc/apcupsd
NOLOGINDIR /etc
ONBATTERYDELAY 20
BATTERYLEVEL 10
MINUTES 10
TIMEOUT 0
ANNOY 300
ANNOYDELAY 60
NOLOGON disable
KILLDELAY 0

NETSERVER on
NISIP 127.0.0.1
NISPORT 3551
EVENTSFILE /var/log/apcupsd.events
EVENTSFILEMAX 10

UPSCLASS standalone
UPSMODE disable
STATTIME 0
STATFILE /var/log/apcupsd.status
LOGSTATS off
DATATIME 0


xxxEOFxxx
	close(FILE);

	system("chown root:root /etc/apcupsd/apcupsd.conf");
	system("chmod a+r /etc/apcupsd/apcupsd.conf");
}


sub install_apcupsd_battery_script
{
	print("Generating battery script for APC UPS Software...\n");

	# This script is run when we flip to running on the battery.
	open(FILE, "> /etc/apcupsd/onbattery");
	print(FILE "#\n");
	print(FILE  "# APC UPS Config File\n");
	print(FILE  "# Generated by $PROGNAME $CVS_REVISION $TIMESTAMP\n");
	print(FILE << "xxxEOFxxx");
#!/usr/bin/perl
#
# Script to inform Teleflora POS users about being on battery backup (ie, power is out.)
#
use strict;
use warnings;

open(WALL, "| wall");
print(WALL "\n");
print(WALL "\n");
print(WALL "!!!!!!!!!!!!!!!!!!!!!!!\n");
print(WALL "!!!!! POWER OUTAGE !!!!\n");
print(WALL "!!!!! Your Teleflora Server is running on Battery Backup.\n");
print(WALL "!!!!! Please make sure to finish and save any tasks.\n");
print(WALL "!!!!! DO NOT begin critical operations (such as credit cards) until power is restored.\n");
print(WALL "!!!!! Take measures to shut down your server now; before batteries are drained.\n");
print(WALL "!!!!!!!!!!!!!!!!!!!!!!!\n");
print(WALL "\n");
print(WALL "\n");
print(WALL "Press Control-L to refresh the screen.\n");
print(WALL "\n");
close(WALL);

# Magic return value needed by apccontrol.
exit(99);
xxxEOFxxx
	close(FILE);

	system("chown root:root /etc/apcupsd/onbattery");
	system("chmod 555 /etc/apcupsd/onbattery");
}


#
# Install software which listens for UPS notifications (power off, power on.)
# Un-install any previous UPS software (most notably, powerchute under RTI.
#
sub install_apcupsd
{
	#
	# If the rpm is already installed, just deal with config files.
	#
	system("rpm -qa | grep apcupsd > /dev/null 2> /dev/null");
	if($? == 0) {
		showinfo("APC UPS Software Already Installed...");
		install_apcupsd_conf();
		install_apcupsd_battery_script();
		return(0);
	}

	showinfo("Installing APC UPS Software...");

	identify_hardware();

	system("rm -f /tmp/apcupsd.rpm");
	if("$ARCH" eq "x64") {
		# RTI x64 systems are (today) always RHEL5.
		system("cd /tmp && wget -O /tmp/apcupsd.rpm 'http://downloads.sourceforge.net/project/apcupsd/rpms%20-%20Stable/3.14.8/apcupsd-3.14.8-1.el5.x86_64.rpm?use_mirror=surfnet&81449690'");
		system("yum localinstall --nogpgcheck -y /tmp/apcupsd.rpm");
	} else {

		if("$OS" eq "RHEL4") {
			# RTI 1800's run RHEL4
			system("wget -O /tmp/apcupsd.rpm 'http://downloads.sourceforge.net/project/apcupsd/rpms%20-%20Stable/3.14.8/apcupsd-3.14.8-1.el4.i386.rpm?use_mirror=superb-sea2&88360520'");
			system("rpm -ivh /tmp/apcupsd.rpm");

		} elsif ( ("$OS" eq "RHWS5") || ("$OS" eq "RHEL5") ) {
			# Daisy servers run RHEL5 32 bit.
			system("rm -f /tmp/apcupsd.rpm");
			system("cd /tmp && wget -O /tmp/apcupsd.rpm 'http://downloads.sourceforge.net/project/apcupsd/rpms%20-%20Stable/3.14.8/apcupsd-3.14.8-1.el5.i386.rpm?use_mirror=surfnet&68147522'");
			system("yum localinstall --nogpgcheck -y /tmp/apcupsd.rpm");

		} else {
			showerror("OS \"$OS\" not supported for APC UPS Software.");
			return(5);
		}
	}
	system("rm -f /tmp/apcupsd.rpm");

	unless (-d '/etc/apcupsd') {
		showerror("the APC UPS config dir not found: /etc/apcupsd.");
		showerror("the APC UPS Software was not installed successfully.");
		return(6);
	}

	# Turn off older APC (Java based) UPS Monitor.
	# Note that the APC software did not use 'chkconfig' to install PBEAgent, thus,
	# we will explicitly 'rm' the file.
	if (-f '/etc/init.d/PBEAgent') {
		system("/etc/init.d/PBEAgent stop");
		system("chkconfig --level 3 PBEAgent off");
		system("rm -f /etc/init.d/PBEAgent");
	}

	install_apcupsd_conf();

	install_apcupsd_battery_script();

	system("/sbin/service apcupsd start");

	return(0);
}

sub identify_ups_hardware
{
	my $lsusb_cmd = '/sbin/lsusb';

	unless (-x $lsusb_cmd) {
		return("usb");
	}

	open(PIPE, "$lsusb_cmd |");
	while(<PIPE>) {
		if (/American Power Conversion/i || /Tripp Lite/i) {
			close(PIPE);
			return("usb");
		}
	}
	close(PIPE);

	return("serial");
}

sub identify_hardware
{

	$HARDWARE = "unknown";
	open(PIPE, "/usr/sbin/dmidecode |");
	while(<PIPE>) {
		if(/PowerEdge T300/) {
			$HARDWARE = "t300";
			return($HARDWARE);
		} elsif (/PowerEdge T310/) {
			$HARDWARE = "t310";
			return($HARDWARE);
		} elsif (/PowerEdge T410/) {
			$HARDWARE = "t410";
			return($HARDWARE);
		} elsif (/PowerEdge 1800/) {
			$HARDWARE = "1800";
			return($HARDWARE);
		} elsif (/PowerEdge 420/) {
			$HARDWARE = "420";
			return($HARDWARE);
		} elsif (/PowerEdge R910/) {
			$HARDWARE = "r910";
			return($HARDWARE);
		} elsif (/PowerEdge 2950/) {
			$HARDWARE = "2950";
			return($HARDWARE);
		} elsif (/Precision 380/) {
			$HARDWARE = "Precision380";
			return($HARDWARE);
		} elsif (/Precision 390/) {
			$HARDWARE = "Precision390";
			return($HARDWARE);
		} elsif (/Precision WorkStation T3400/i) {
			$HARDWARE = "t3400";
			return($HARDWARE);
		} elsif (/Precision WorkStation T3500/i) {
			$HARDWARE = "t3500";
			return($HARDWARE);
		}
	}
	close(PIPE);
	return($HARDWARE);
}



#
# By default, redhat will mount partitions based on a label name, even swap partitions.
# We are using 'dd' to "clone" disks from sda to sdb, which means, two disks will have a partition
# labeled the same thing.
# This patch modifies /etc/fstab to remove the "label based mounting" and instead, use 
# "hard coded device names".
#
sub remount_partition
{
	my $oldlabel = $_[0];
	my $newmountpoint = $_[1];
	my $oldmountpoint = "";
	my $device  = "";
	my $line = "";
	my @array = ();


	# LABEL=SWAP-sda2 was "swap" mounted to "/dev/sda2"
	if("$oldlabel" =~ /(SWAP)(-)(\S+)/) {
		$device = "/dev/$3";
		$oldmountpoint = "swap";

	# Which device is LABEL=/teleflora mounted to currently ?
	} else {

		open(PIPE, "mount -l |");
		while(<PIPE>) {
			# e2fs labels show up with [labelname]
			next until /\[$oldlabel\]/;

			@array = split(/\s+/);
			$device = $array[0];
			$oldmountpoint = $array[2];
			last;
		}
		close(PIPE);
	}

	if("$device" eq "") {
		return(0);
	}
	if("$oldmountpoint" eq "") {
		return(0);
	}


	# We did not find this label in /etc/fstab. We're done.
	system("grep \"LABEL=$oldlabel\" /etc/fstab > /dev/null 2> /dev/null");
	if($? != 0) {
		return(0);
	}


	# Create our new mountpoint.
	showinfo("Mounting \"$device-> $newmountpoint\" instead of \"LABEL=$oldlabel -> $oldmountpoint\"...");
	if("$newmountpoint" eq "swap") {
		system("swapoff $device");
	} elsif ("$newmountpoint" ne "/") {
		system("umount $oldmountpoint");
	}



	# Modify /etc/fstab
	open(OLD, "< /etc/fstab");
	open(NEW, "> /etc/fstab.$$");
	while(<OLD>) {
		if(/^(\s*)(LABEL)(\s*)(=)(\s*)($oldlabel)(\s+)/) {
			@array = split(/\s+/);
			print(NEW "$device\t$newmountpoint\t$array[2]\t$array[3]\t$array[4] $array[5]\n");
			next;
		}
		print(NEW);
	}
	close(OLD);
	close(NEW);
	system("mv /etc/fstab.$$ /etc/fstab");

	# In the case of our root partition, we also need to modify grub.conf
	if($oldlabel eq "/") {
		open(OLD, "< /boot/grub/grub.conf");
		open(NEW, "> /boot/grub/grub.conf.$$");
		while(<OLD>) {
			$line = $_;

			#root=LABEL=/ -> root=/dev/blah
			if(/(root=LABEL=)(\s*)($oldlabel)/) {
				$line =~ s/(root=LABEL=)(\s*)($oldlabel)/root=$device/g;
				print(NEW $line);
				next;
			}
			print(NEW);
		}
		close(OLD);
		close(NEW);
		system("mv /boot/grub/grub.conf.$$ /boot/grub/grub.conf");
	}



	# Make sure our mountpoint exists.
	if( ("$newmountpoint" ne "swap")
	&&  (! -d "$newmountpoint") ) {
		system("mkdir -p $newmountpoint");
	}

	# Re-mount the device.
	if("$newmountpoint" eq "swap") {
		system("swapon $device");
	} else {
		if("$newmountpoint" ne "/") {
			system("mount $newmountpoint");
		}
	}

	return(0);
}



sub reset_aide_database
{

	if(! -f "/usr/sbin/aide") {
		return(1);
	}

	showinfo("Resetting Intrusion Detection Rules...");

	if(-f "/var/lib/aide/aide.db.gz") {
                $PID = fork();
                if ($PID == 0) {
                        loginfo("Update Aide Databases.");
                        system("/usr/sbin/aide --init");
                        system("mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz");
                        exit(0);
                } else {
                        loginfo("Update Aide Database started as PID $PID at " . localtime() . "\n");
                }
                exit(0);
        }

	return(0);
}





#
# Unmount all filesystems except '/'
# Useful if we need to perform a "power button" shutdown, to ensure that most of our 
# filesystems don't come up in a 'dirty' state.
#
# Notes:
# We explicity do not run 'sync' as, I have experienced in the past, cases where 'sync' hung,
# I believe because the backup device could not sync, and, "sync" works on all devices.
# The filesystem caches are all sycned when the FS is unmounted.
# This function should be run as root.
#
sub hard_reboot
{
	my @array = ();
	my $mountpoint = "";
	my $device = "";
	my $pid = -1;
	my $childpid = -1;
	my $i = 0;


	showinfo("Performing reboot...");

	# Run the "regular" shutdown here. If that works as expected, we should never actually
	# finish this function, as, we will be killed off.
	$pid = fork();
	if($pid == 0) {
		exec("/sbin/shutdown -r now");
	}
	for($i = 0; $i < 120; $i++) {
		$childpid = waitpid($pid, WNOHANG);
		last if($childpid != 0);
		sleep(1);
	}
	if($childpid < 0) {
		showinfo("waitpid() on PID $pid returned $childpid.");
	}

	if($i >= 120) {
		showerror("We waited long enough (2 mins) for our shutdown to finish. Will manually reboot.");
		system("kill -TERM $pid");
	} else {
		showerror("the 'shutdown' sub process terminated in $i seconds, without terminating this process.");
		return(1);
	}

	# If we get this far, though "shutdown" ran, it never actually did anything.
	# We have seen this in the field in cases where sync() hangs (and hence, the 'shutdown' process 
	# also hangs.
	# At this point, we will manually unmount disks, kill off processes, and reboot the computer.
	# Note! Make sure *not* to run 'sync', as, that will almost certainly hang.
	showinfo("Server did not reboot normally. Will issue a 'hard' reboot...");
	sleep(5);

	# Bring down
	system("/sbin/service smb stop");
	system("/sbin/service sendmail stop");
	if (-f "/etc/init.d/rti") {
		system("/sbin/service rti stop");
	}
	if(-f "/etc/init.d/daisy") {
		system("/sbin/service daisy stop");
	}


	# If things are this un-healthy, then, we may have underlying disk issues.
	# If we simply reboot without the '/fsckoptions' file, then, chances are, the flower shop
	# owner will be presented with an ugly prompt saying 'fsck failed', and a '#' prompt.
	# By adding this particular file, according to /etc/rc.d/rc.sysinit, FSCK will use these
	# "force" and "dammit" options, thereby sparing the florist from having to type stuff in.
	open(FILE, "> /fsckoptions");
		print(FILE "-f -v -y");
	close(FILE);

	open(MOUNTS, "< /proc/mounts");
	while(<MOUNTS>) {
		chomp;
		next until(/ext[23]/);
		@array = split(/\s+/);
		$device = $array[0];
		$mountpoint = $array[1];
		next if(! $device);
		next if("$device" eq "");
		next if("$mountpoint" eq "");
		next if("$mountpoint" eq "/");
		next if("$mountpoint" eq "/proc");
		next if(! -b $device);

		# Look at all processes holding this filesystem open, and kill them.
		#[kachline@rtidev bin]$ sudo /usr/sbin/lsof /usr4
		#COMMAND  PID USER   FD   TYPE DEVICE SIZE   NODE NAME
		#bash    4283   jj  cwd    DIR  104,2 4096 961291 /usr4/jj/rev
		print("Killing Processes ($device)...\n");
		open(LSOF, "/usr/sbin/lsof $device |");
		while(<LSOF>) {
			chomp;
			@array = split(/\s+/);
			$pid = $array[1];
			next if(! $pid);
			next if("$pid" eq "PID");
			print("$_\n");
			system("kill -HUP $pid");
			system("kill -TERM  $pid");
			system("kill -INT $pid");
			system("kill -KILL $pid");
		}
		close(LSOF);

		# Unmount the filesystem
		print("Unmounting $mountpoint -> $device");
		system("umount $device");
		if($? != 0) {
			print("Forcing Unmount of $mountpoint -> $device");
			system("umount -f $device");
			if($? != 0) {
				print("Error: Could not unmount $mountpoint -> $device");
				print("Could not Unmount \"$device\".\n");
				print("Try re-running this script to kill off 'lsof' processes.\n");
			}
		}

	}
	close(MOUNTS);

	#
	# Try to do a standard reboot at this point, though we have seen
	# instances in the field where this does not work.
	#
	system("/sbin/reboot -n -f");

	#
	# This is the atom bomb for causing a reboot...
	#
	# For background on what the code below does, read this article:
	#	http://www.linuxjournal.com/content/rebooting-magic-way
	#
	system("echo 1 > /proc/sys/kernel/sysrq");
	system("echo b > /proc/sysrq-trigger");

	#
	# Should not reach this point... the system should have rebooted
	# before this.
	#

	return(2);
}



#
# Many of our original T300 servers came shipped with a swap partition in place, yet,
# a bug in /etc/fstab which would cause the swap partition to never "swapon".
# This routing fixes said bug.
#
sub swapon
{
	my @partitions = ();
	my @array = ();
	my $thisdisk = "";
	my $thispart = "";


	showinfo("Enabling Swap Space...");
	# only RTI systems
	if(-d "/d/daisy") {
		showinfo("This is a daisy system. Will not update swap space.");
		return (0);
	}


	# Are we root?
	if($UID != 0) {
		showerror("Must be root to run.");
		return(1);
	}


	# Which partitions are formatted for swap?
	foreach $thisdisk ("/dev/sda", "/dev/sdb") {
		open(FDISK, "/sbin/fdisk -l $thisdisk |");
		while(<FDISK>) {
			next until(/^\/dev\//);
			next unless(/(Linux)(\s+)(swap)/);
			@array = split(/\s+/);
			$thispart = $array[0];
			if(-b "$thispart") {
				push(@partitions, $thispart);
			}
		}
		close(FDISK);
	}


	# Did we find swap partitions?
	if($#partitions < 0) {
		showerror("No swap partitions were found! No changes made.");
		return(5);
	}


	# Modify /etc/fstab
	showinfo("Updating /etc/fstab...");
	open(OLD, "< /etc/fstab") or die("Could not open /etc/fstab for read");
	open(NEW, "> /etc/fstab.$$") or die("Could not open /etc/fstab.$$ for write");
	while(<OLD>) {
		next if(/(\s+)(swap)(\s+)/);
		print(NEW);
	}
	close(OLD);

	# Record our known swap partitions.
	foreach $thispart (sort(@partitions)) {
		print(NEW "$thispart\t\tswap\t\tswap\tdefaults\t\t0\t0\n");
	}
	close(NEW);

	if(-s "/etc/fstab.$$" <= 0) {
		# We probably didn't have permission to create this temp file.
		showerror("Our newly created fstab file does not exist. No changes made.");
		return(6);
	}
	system("mv /etc/fstab.$$ /etc/fstab");


	# Format each swap partition.
	foreach $thispart (sort(@partitions)) {
		showinfo("Enabling Swap Partition \"$thispart\" ...");
		system("/sbin/mkswap $thispart");
		system("/sbin/swapon $thispart");
	}
	close(NEW);

	# Enable our swap partitions.
	system("cat /proc/meminfo | grep Swap");

	showinfo("Swap Space Updated.");
	return(0);
}


#
# Remove files from /var/spool/cups/tmp
# Earlier versions of RTI would leave behind lots of zero byte files in 
# this directory.
#
sub cups_clean_tempfiles
{
	showinfo("Cleanup CUPS Temporary Files...");
	system("find /var/spool/cups/tmp -type f -size 0b -print | xargs rm -f");
	if(-d "/usr2/bbx/bbxtmp") {
		system("find /usr2/bbx/bbxtmp -type f -size 0b -print | xargs rm -f");
	}
	return(0);
}


#
# Edit the CUPS conf file.
#
sub cups_edit_conf
{
	my $conf_file = '/etc/cups/cupsd.conf';
	my $new_conf_file = "$conf_file-$TIMESTAMP";

	showinfo("Editing CUPS Configuration File...");

	unless (-f "$conf_file") {
		showerror("$conf_file not found");
		return(1);
	}

	unless (open(OLD, "< $conf_file")) {
		showerror("Could not open $conf_file for read");
		return(2);
	}

	unless (open(NEW, "> $new_conf_file")) {
		showerror("Could not open $new_conf_file for write");
		close(OLD);
		return(3);
	}

	while(<OLD>) {

		next if (/^#updateos.pl#/);

		# CUPS has a default "max jobs" set to 500. For some of the
		# larger shops, this print queue size is too small.
		# Set the "Max Jobs" setting to a higher value.

		if ($CUPSCONF_MAXJOBS) {
			if(/^(\s*)(MaxJobs)(\s+)/) {
				print(NEW "#updateos.pl# $_");
				next;
			}
		}


		#
		# Don't put files into /var/spool/cups/tmp at all.
		# Thus eliminating the need for the "cleanfiles"
		# patch elsewhere in this script.
		#
		if ($CUPSCONF_DISABLETEMPFILES) {
			if (/^(\s*)(PreserveJobHistory)(\s+)/i) {
				print(NEW "#updateos.pl# $_");
				next;
			}
			if (/^(\s*)(PreserveJobFiles)(\s+)/i) {
				print(NEW "#updateos.pl# $_");
				next;
			}
		}

		if ($CUPSCONF_TIMEOUTS) {
			if (/^(\s*)(BrowseTimeout)(\s+)/i) {
				print(NEW "#updateos.pl# $_");
				next;
			}

			if (/^(\s*)(Timeout)(\s+)/i) {
				print(NEW "#updateos.pl# $_");
				next;
			}
		}

		if ($CUPSCONF_ERRORPOLICY) {
			if (/^(\s*)(ErrorPolicy)(\s+)/i) {
				print(NEW "#updateos.pl# $_");
				next;
			}
		}
		print(NEW);
	};

	close(OLD);

	loginfo("Adding rules to $conf_file");
	print(NEW "#updateos.pl# --- Start of additional lines ---\n");
	print(NEW "#updateos.pl# $PROGNAME $CVS_REVISION $TIMESTAMP\n");
	print(NEW "MaxJobs 10000\n");
	print(NEW "PreserveJobHistory No\n");
	print(NEW "PreserveJobFiles No\n");
	print(NEW "BrowseTimeout 0\n");
	print(NEW "Timeout 0\n");

	determine_os();
	if ($OS ne "FC3") {
		print(NEW "ErrorPolicy retry-job\n");
	}
	print(NEW "#updateos.pl# --- End of additional lines ---\n");

	close(NEW);

	# If we created a new conf file that is zero sized, that is bad.
	if (-z $new_conf_file) {
		showerror("Copy of $conf_file is a zero size file");
		system("rm $new_conf_file");
		return(4);
	}

	# Assume conf file was successfully transformed...
	# so replace the old one with the new.

	system("chmod --reference=$conf_file $new_conf_file");
	system("chown --reference=$conf_file $new_conf_file");
	system("cp $new_conf_file $conf_file");

	system("/sbin/service cups start");

	return(0);
}


#
# Remove all print jobs from all print queues.
#
sub purge_printjobs
{
	showinfo("Purging CUPS Print Jobs...");
	system("/sbin/service cups stop");
	system("find /var/spool/cups -type f -print | xargs rm -f");
	system("/sbin/service cups start");
	return(0);
}




sub determine_os
{
	$OS = "";

	# We could also use /usr/bin/lsb-release
	open(FILE, "< /etc/redhat-release");
	while(<FILE>) {

		# Fedora Core 3
		if(/(Fedora)(\s+)(Core)(\s+)(release)(\s+)(3)/) {
			$OS = "FC3";
			last;
		}

		# Fedora Core 4
		if(/(Fedora)(\s+)(Core)(\s+)(release)(\s+)(4)/) {
			$OS = "FC4";
			last;
		}

		# Fedora Core 5
		if(/(Fedora)(\s+)(Core)(\s+)(release)(\s+)(5)/) {
			$OS = "FC5";
			last;
		}

		# Redhat Enterprise Linux Client Workstation 5
		if( /(Client release)(\s+)(5)/ ) {
			$OS = "RHWS5";
			last;
		}

		# ES 5
		# Redhat Enterprise Linux Server 5
		if( (/(release)(\s+)(5)/)
		||  (/(CentOS)([[:print:]]+)(\s)(5)/) ) {
			$OS = "RHEL5";
			last;
		}

		# EL 4
		# Redhat Enterprise Linux Server 4
		if( (/(release)(\s+)(4)/) 
		||  (/(CentOS)([[:print:]]+)(\s)(4)/) ) {
			$OS = "RHEL4";
			last;
		}

		# Redhat 7.2
		if(/(release)(\s+)(7\.2)/) {
			$OS = "RH72";
			last;
		}
	}
	close(FILE);

	#
	# Allow a last minute switcheroo.
	#
	if ($ALTOS) {
	    $OS = $ALTOS;
	}

	return($OS);
}


#
# Which processor architecture are we running on?
#
sub processor_arch
{
	$ARCH = "";

	# rti can be either 32 bit or 64 bit
	if ($POSDIR eq '/usr2/bbx') {
		$ARCH = get_sys_info();

	# daisy can be only 32 bit
	} elsif ($POSDIR eq '/d/daisy') {
		$ARCH = 'x86';

	# RH72 can not report architecture
	} elsif ($POSDIR eq "") {
		if ($OS eq 'RH72') {
			$ARCH = 'x86';
		} else {
			$ARCH = get_sys_info();
		}
	}

	if ($ARCH eq "") {
		showerror("Can't determine processor architecture - assuming \"x86\"");
		$ARCH = "x86";
	}

	return($ARCH);
}

sub report_rhn_system_id
{
	my $rhn_system_id = get_rhn_system_id();

	if ($rhn_system_id eq "") {
		$rhn_system_id = "unregistered";
	}
	print("Redhat Network System ID: $rhn_system_id\n");
	return(0);
}

sub get_rhn_system_id
{
	my $rhn_system_id = "";
	my $rhn_system_id_file = '/etc/sysconfig/rhn/systemid';

	#
	# If the rhn system id file does not exist, then the system is
	# not registered.
	#
	unless (-f $rhn_system_id_file) {
		return($rhn_system_id);
	}

	open(FILE, "< $rhn_system_id_file");
	while (<FILE>) {
		if (/^<name>system_id/) {
			my $next_line = <FILE>;
			if ($next_line =~ /^<value><string>(.+)<\/string><\/value>/) {
				$rhn_system_id = $1;
				last;
			}
		}
	}
	close(FILE);

	return($rhn_system_id);
}


sub get_sys_info
{
	my $arch = "";

	return("x86") if ($OS eq 'RH72');

	open(PIPE, "uname -i |");
	while(<PIPE>) {
		if(/i.86/) {
			$arch = "x86";
		}
		if(/x86_64/) {
			$arch = "x64";
		}
	}
	close(PIPE);

	return($arch);
}


#
# Gather some evidence if we believe there was a compromise or need performance
# statistics.
#
sub forensics
{
	my $pid = "";
	my @array = ();


	unlink("/tmp/system-info.$$");

	system("/bin/echo '----- Basic Information -----' | tee --append /tmp/system-info.$$");
	system("date >> /tmp/system-info.$$");
	system("hostname >> /tmp/system-info.$$");


	system("/bin/echo '----- Network Information -----' | tee --append /tmp/system-info.$$");
	system("/sbin/ifconfig >> /tmp/system-info.$$");
	system("/bin/netstat -plan >> /tmp/system-info.$$");
	system("/sbin/route -n >> /tmp/system-info.$$");

	#
	# Run nmap discovery on all networks which we have a (known) route to.
	#
	open(PIPE, "/sbin/route -n |");
	while(<PIPE>) {
		if(/^\d/) {
			@array = split(/(\s+)/);
			next if("$array[0]" eq "0.0.0.0");
			next if("$array[0]" eq "127.0.0.0");
			next if("$array[0]" !~ /^\d/);
			system("/bin/echo '----- nmap $array[0] -----' | tee --append /tmp/system-info.$$");
			system("nmap -v -n -sS -O $array[0]/24 >> /tmp/system-info.$$");
		}
	}
	close(PIPE);


	system("/bin/echo '----- Processes (ps wwaux) -----' | tee --append /tmp/system-info.$$");
	system("ps wwaux >> /tmp/system-info.$$");

	# We may not be able to trust 'ps' results.
	system("/bin/echo '----- Processes (/proc) -----' | tee --append /tmp/system-info.$$");
	open(PROCS, "find /proc -type d -print |");
	while(<PROCS>) {
		chomp;
		next until (/\d+/);
		$pid = $_;
		print("$pid: ");
		system("/bin/echo \"/proc/$pid/cmdline\" >> /tmp/system-info.$$");
		system("cat /proc/$pid/cmdline >> /tmp/system-info.$$");
	}
	close(PROCS);


	system("/bin/echo '----- System Performance -----' | tee --append /tmp/system-info.$$");
	system("cat /proc/meminfo >> /tmp/system-info.$$");
	system("vmstat 2 5 >> /tmp/system-info.$$");
	system("iostat -x 2 5 >> /tmp/system-info.$$");
	system("/usr/sbin/dmidecode >> /tmp/system-info.$$");


	system("/bin/echo '----- OS Information -----' | tee --append /tmp/system-info.$$");
	system("uname -a >> /tmp/system-info.$$");
	system("cat /proc/redhat-release >> /tmp/system-info.$$");
	system("rpm --list >> /tmp/system-info.$$");
	system("rpm --verify >> /tmp/system-info.$$");
	system("dmesg >> /tmp/system-info.$$");
	if(-f "/usr/bin/yum") {
		system("yum checkupdate >> /tmp/system-info.$$");
	}



	system("/bin/echo '----- User Information -----' | tee --append /tmp/system-info.$$");
	system("w >> /tmp/system-info.$$");
	system("last >> /tmp/system-info.$$");
	system("/usr2/bbx/bin/rtiuser.pl --list >> /tmp/system-info.$$");

	system("/bin/echo '----- PCI 2.2.2 -----' | tee --append /tmp/system-info.$$");
	system("/sbin/chkconfig --list | grep ':on' >> /tmp/system-info.$$");

	system("/bin/echo '----- PCI 2.2.3 -----' | tee --append /tmp/system-info.$$");
	system("/sbin/chkconfig --list | grep ':on' >> /tmp/system-info.$$");



	# Create our resultant tarfile.
	unlink("/tmp/system-info.$$.tar");
	system("cd /tmp && tar --append -vf /tmp/system-info.$$.tar system-info.$$");
	system("cd / && tar --append -vf /tmp/system-info.$$.tar /etc");
	system("cd /home && find . -type f -iname .bash_history -exec tar --append -vf /tmp/system-info.$$.tar \\{\\} \\;");
	system("cd / && find /root -type f -iname .bash_history -exec tar --append -vf /tmp/system-info.$$.tar \\{\\} \\;");
	system("cd / && tar --append -vf /tmp/system-info.$$.tar root");
	system("cd / && tar --append -vf /tmp/system-info.$$.tar var/log");
	if(-d "/usr2/bbx") {
		system("cd / && tar --append -vf /tmp/system-info.$$.tar usr2/bbx/log");
		system("cd / && tar --append -vf /tmp/system-info.$$.tar usr2/bbx/config");
	}
	if(-d "/d/daisy") {
		system("cd / && tar --append -vf /tmp/system-info.$$.tar d/daisy/log");
	}

	system("gzip -v9 /tmp/system-info.$$.tar");
	system("ls -la /tmp/system-info.$$.tar.gz");


	return(0);
}



sub showinfo
{
	my $message = $_[0];
	print("$message\n");
	return(loginfo($message));
}

sub loginfo
{
	my $message = $_[0];
	return(logit($message, 'I'));
}

sub showerror
{
	my $message = $_[0];
	print("Error: $message\n");
	return(logerror($message));	
}

sub logerror
{
	my $message = $_[0];
	return(logit($message, 'E'));
}

sub logit
{
	my $message = $_[0];
	my $type = $_[1];
	my $logtime = strftime("%Y-%m-%d %H:%M:%S", localtime());

	chomp($message);

	# where is the logfile?
	if ($LOGFILE_PATH eq "") {
		if ( ($POSDIR ne "") && (-d "$POSDIR/log") ) {
			$LOGFILE_PATH = "$POSDIR/log/RTI-Patches.log";
		} else {
			$LOGFILE_PATH = "/tmp/RTI-Patches.log";
		}
	}

	open LOGFILE, ">> $LOGFILE_PATH";
		print LOGFILE "$logtime ($PROGNAME-$$) <$type> $message\r\n";
	close LOGFILE;

	return "";
}

