#!/usr/bin/perl
#
# $Revision: 1.2 $
# Script which creates various "custom inventory" scripts for
# RTI Altiris agent.
#
# Note that this script has been written in a way that it is usasble under Daisy as well, thus
# making changes in one POS easier to 'port to' the other.
#
# This file should be located under:
# /opt/altiris/notification/nsagent/var/packages/{*
# This file is automagically downloaded by the Altiris client as a package. The package also 
# manages how often the script is run.
#
use strict;
use warnings;
use File::Basename;
use File::stat;
use Getopt::Long;
use POSIX;


my $version = 0;
my $versions = 0;
my $configs = 0;
my $checkin = 0;
my $dmesg = 0;
my $rti = 0;
my $daisy = 0;
my $errors = 0;
my $sysinfo = 0;
my $updates = 0;
my $filelist = "";
my $install = 0;



my $ALTIRIS_SERVER = "https://altiris.teleflora.com";
my $ALTIRIS_DIR = "/opt/altiris";
my $CUSTOMINV_DIR= "$ALTIRIS_DIR/notification/nsagent/var/packages/{B89D89CA-DF94-4FC6-8DE4-D2EB4BB50984}";


#
# Changes to reflect Daisy or RTI
#
my $POS = "";
my $POSDIR = ""; # Root directory for our POS.
if($POS eq "DAISY") {
	$POSDIR = "/d/daisy";
} else {
	$POSDIR = "/usr2/bbx";
}



GetOptions(
	"version" => \$version,
	"versions" => \$versions,
	"configs" => \$configs,
	"checkin" => \$checkin,
	"rti" => \$rti,
	"daisy" => \$daisy,
	"dmesg" => \$dmesg,
	"errors" => \$errors,
	"sysinfo" => \$sysinfo,
	"install" => \$install,
	"updates" => \$updates,
);





# Unloess --daisy is specified, assume --rti
if($daisy != 0) {
	$POS = "DAISY";
} elsif ($rti != 0) {
	$POS = "RTI";

# We have to guess at which POS we are looking at.
} else {


	if(-d "/d/daisy") {
		$POS = "DAISY";
	} else {
		$POS = "RTI";
	}
}





if($version != 0) {
	print "$0 " . '$Revision: 1.2 $' . "\n";



} elsif($versions != 0) {
	if($POS eq "RTI") {
		custominv_rti_versions();
	}

} elsif($configs != 0) {
	if($POS eq "RTI") {
		custominv_rti_configs();
	}

} elsif($dmesg != 0) {
	custominv_dmesg();

} elsif($sysinfo != 0) {
	custominv_sysinfo();


} elsif($errors != 0) {
	if($POS eq "RTI") {
		custominv_rti_logerrors();
	}

} elsif($checkin != 0) {
	checkin();

} elsif($updates != 0) {
	get_updates();

} elsif ($install != 0) {
	install_agent();

} else {

	usage();
}




exit 0;


sub usage
{
	print "\n";
	print "Usage:\n";
	print "$0 " . '$Revision: 1.2 $' . "\n";
	print "$0 --checkin\tSee if Altiris is alive, sign into server.\n";
	print "$0 --install\tInstall Altiris Client.\n";
	print "$0 --version\tPrint version of this script.\n";
	print "\n";
	print "Custom Inventories (rarely needed to run these manually).\n";
	print "$0 --configs\tAll RTI Configurations\n";
	print "$0 --dmesg\tKernel Messages\n";
	print "$0 --errors\tTop Erorrs to look at.\n";
	print "$0 --sysinfo\tPrint System Summary Information\n";
	print "$0 --versions\tPrint various file versions.\n";
}



#
# Send custom inventory, receive packages.
#
sub checkin
{

	# Send Custom Inventory.
	if(! -d "$CUSTOMINV_DIR") {
		print "Error: Could not find Custom Inventory Directory '$CUSTOMINV_DIR'\n";
		print "Perhaps installation did not complete fully?\n";
	} else {

		#
		# This is the script which 'aex-runinvnow' looks for when executed.
		#  We are dynamically creating this with the intent that we need only update this script 
		# in order to have an 'up-to-date' version of everything else altiris.
		#
		open SCRIPT, "> $CUSTOMINV_DIR/aex-invagent-custom" or die "Could not open custom inventory script. $!";
		print SCRIPT "#!/bin/bash\n";
		print SCRIPT "#\n";
		print SCRIPT "# This script automatically created from @ARGV\n";
		print SCRIPT "#\n";
		print SCRIPT "\n";
		print SCRIPT "$CUSTOMINV_DIR/aex-invagent-generic \"$ENV{'PWD'}/" . basename($0) . " --configs\"\n";
		print SCRIPT "$CUSTOMINV_DIR/aex-invagent-generic \"$ENV{'PWD'}/" . basename($0) . " --dmesg\"\n";
		print SCRIPT "$CUSTOMINV_DIR/aex-invagent-generic \"$ENV{'PWD'}/" . basename($0) . " --errors\"\n";
		print SCRIPT "$CUSTOMINV_DIR/aex-invagent-generic \"$ENV{'PWD'}/" . basename($0) . " --sysinfo\"\n";
		print SCRIPT "$CUSTOMINV_DIR/aex-invagent-generic \"$ENV{'PWD'}/" . basename($0) . " --versions\"\n";
		close SCRIPT;
		system "chown root $CUSTOMINV_DIR/aex-invagent-custom";
		system "chmod 755 $CUSTOMINV_DIR/aex-invagent-custom";

		system "cd $CUSTOMINV_DIR && ./aex-runinvnow";
	}

}


#
# Invoke user interface for running packages.
#
sub get_updates
{
	system "$ALTIRIS_DIR/notification/nsagent/bin/aex-swdapm";
}




#
# Install the Altiris Client software.
#
sub install_agent
{
	my $string= "";
	my $datestamp = strftime("%Y%m%d%H%M%S", localtime());


	# Install the agent.
	system "curl $ALTIRIS_SERVER/Altiris/NS/NSCap/Bin/Unix/Agent/Linux/x86/aex-bootstrap.gz | gzip -dc > /tmp/aex-bootstrap";
	if(-z "/tmp/aex-bootstrap") {
		print "Error: Could not download Altiris Install program.\n";
		return (-3);
	}

	system "chown root /tmp/aex-bootstrap";
	system "chmod 544 /tmp/aex-bootstrap";
	system "rm -f .aex-agent-install-config.xml /tmp/.aex-agent-install-config.xml"; # Stale config files



	# It is somewhat possible that a tech may have "rm -rf'ed" the altiris
	# directory. Yet, the altiris install script only looks to see if an RPM has
	# been installed.
	# Thus, we really need to uninstall the RPM, prior to running the install process 
	# again.
	open PIPE, "rpm -qa | grep aex-nsclt |";
	while(<PIPE>) {
		chomp;
		$string= $_;
		last;
	} 
	close PIPE;
	if($string ne "") {
		system "rpm -e $string";
	}

	# Actually run the 'aex-bootstrap' program here.
	system "/tmp/aex-bootstrap $ALTIRIS_SERVER";
	if($? != 0) {
		print "Error: Though aex-bootstrap could be downloaded, an error\n";
		print "\toccurred while installing the Altiris client.\n";
		system "killall aex-bootstrap";
		return (-3);
	}



	# Send Basic Inventory.
	# Note that this may take some time on a "first load", as, we are fetching a new Guid from the server.
	sleep(10);
	if(-f "$ALTIRIS_DIR/notification/nsagent/bin/aex-helper") {
		system "$ALTIRIS_DIR/notification/nsagent/bin/aex-helper agent --send-basic-inventory";
		system "$ALTIRIS_DIR/notification/nsagent/bin/aex-helper agent --refresh-policies";
	}


	return(0);
}




sub custominv_dmesg
{
	my $timestamp  = strftime("%Y-%m-%d %H:%M:%S", localtime());
	my $line = "";

	# Headers
	print "AeX_CI_Teleflora_" . $POS . "_dmesg\n";
	print "Delimiters = \",\"\n";
	print "string19 string128\n";
	print "Timestamp Message\n";


	open PIPE, "dmesg |";
	while(<PIPE>) {
		chomp;
		$line = $_;
		$line =~ s/,/_/g;
		print "$timestamp,$line\n";
	}
	close PIPE;

}


# /var/log/secure
sub custominv_secure
{
	my $line = "";
	my $month = "";
	my $day = "";
	my $year = strftime("%Y", localtime);
	my $timestamp = "";


	open FILE, "< /var/log/secure";
	while(<FILE>) {
		chomp;

		#
		# Aug 15 18:13:11 Stuff follows here.
		# Transformed to ...
		# 2007-08-15 18:13:11 Stuff follows here.
		#
		$line = $_;
		if(/^(\w+)(\s+)(\d+)(\s+)(\d\d:\d\d:\d\d)(\s+)([[:print:]]+)/) {
			$month = $1;
			$day = $3;
			$timestamp = $5;
			$line = $7;

			if($month eq "Jan") {
				$month = "01";
			} elsif ($month eq "Feb") {
				$month = "02";
			} elsif ($month eq "Mar") {
				$month = "03";
			} elsif ($month eq "Apr") {
				$month = "04";
			} elsif ($month eq "May") {
				$month = "05";
			} elsif ($month eq "Jun") {
				$month = "06";
			} elsif ($month eq "Jul") {
				$month = "07";
			} elsif ($month eq "Aug") {
				$month = "08";
			} elsif ($month eq "Sep") {
				$month = "09";
			} elsif ($month eq "Oct") {
				$month = "10";
			} elsif ($month eq "Nov") {
				$month = "11";
			} elsif ($month eq "Dec") {
				$month = "12";
			} else {
				$month = "01";
			}
			
		}
		$line =~ s/,/_/g;
		print "$year-$month-$day $timestamp,$line,/var/log/secure\n";
	}
	close FILE;

}


#
# Note that these field names are intentionally named similar to those in Dove POS
# to ease naming conventions on the server side.
#
sub custominv_sysinfo
{
	my @array = ();
	my $filename = "";
	my $filestat = "";
	my $string = "";
	my $shopcode = "Unknown";
	my $postype = "$POS";
	my $buildnum = "Unknown";
	my $installdate = "Unknown";
	my $installdir = "$POSDIR";
	my $edirectory = "Unknown";
	my $publicip = "Unknown";
	my $custominv_version = "Unknown";


	# Headers
	print "AeX_CI_Teleflora_" . $POS . "_SystemInformation\n";
	print "Delimiters = \",\"\n";
	print "string20 string10 string14 string20 string255 string10 string10 string20 string20\n";
	print "ShopCode POSType CurrentVersion CurrentInstallDate InstallDirectory InstallType TFEEdition PublicIP CustomInvVersion\n";



	# RTI specific findings.
	if($POS eq "RTI") {

		# Dove ID
		if(-f "$POSDIR/config/dove.ini") {
			open FILE, "< $POSDIR/config/dove.ini";
			while(<FILE>) {
				if(/(DOVE_USERNAME)(\s*)(=)(\s*)([[:print:]]+)/) {
					$shopcode = $5;
				}
			}
			close FILE;
		}


		# Build / CurrentVersion
		if(-f "$POSDIR/bbxd/RTI.ini") {
			$buildnum = "Unknown";
			open FILE, "< $POSDIR/bbxd/RTI.ini";
			while(<FILE>) {
				chomp;
				if(/(VERSION)(\s*)(=)(\s*)([[:print:]]+)/) {
					$buildnum = $5;
					last;
				}
			}
			close FILE;
		} else {
			$buildnum = "No .INI File";
		}


		# Install Date
		$installdate = "Unknown";
		$filename = `ls -tr /root/rti_install*.log | tail -1`;
		chomp($filename);
		open PIPE, "< $filename";
		while(<PIPE>) {
			if(/(Install Started )(\d+)(-)(\d+)(-)(\d+)/) {
				$installdate = $2 . $4 . $6;
			}
		}
		close PIPE;



		# Install Directory
		# RTI is technically 'installed' wherever our profile.d is pointing to.
		$installdir = "Unknown";
		open FILE, "< /etc/profile.d/rti.sh";
		while(<FILE>) {
			if(/(RTI_DIR)(\s*)(=)(\s*)([[:print:]]+)/) {
				$installdir = $5;
				last;
			}
		}
		close FILE;


		# eDirectory Version
		if(-f "$POSDIR/bbxd/ONOR01") {

			#
			# This from Scott Buckholtz.
			# Basically we read from bytes 60-65 for a string which looks like...
			# YY.MM
			# Where "MM" would be '08' (August), and YY would be '07' (2007).
			#
			open FILE, "< $POSDIR/bbxd/ONRO01";
			sysseek (FILE,60,0);
			sysread (FILE, $string,5);
			close FILE;

			# XX.YY
			@array = split (/\./, $string);
			if( (int($array[1]) == 2) 
			||  (int($array[1]) == 3)
			||  (int($array[1]) == 4) ) {
				$edirectory = "FMA" . (2000 + int($array[0]));

			} elsif( ( int($array[1]) == 5)
			||       ( int($array[1]) == 6)
			||       ( int($array[1]) == 7) ) {
				$edirectory = "MJJ" . (2000 + int($array[0]));

			} elsif( ( int($array[1]) == 8) 
			||       ( int($array[1]) == 9)
			||       ( int($array[1]) == 10) ) {
				$edirectory = "ASO" . (2000 + int($array[0]));

			} elsif( ( int($array[1]) == 11) 
			||       ( int($array[1]) == 12)
			||       ( int($array[1]) == 1) ) {
				$edirectory = "NDJ" . (2000 + int($array[0]));
			} else {
				$edirectory = $string;
			}
		}	



	} elsif ($POS eq "DAISY") {

		# Shop Code
		$shopcode = "Unknown";

		# Current Version / Build
		open PIPE, "$POSDIR/pos --version |";
		while(<PIPE>) {
			chomp;
			if (/(Build Number:)(\s*)([[:print:]]+)/) {
				$buildnum = $3;
				last;
			}
		}
		close PIPE;


		# Install date.
		# The best we have for daisy is the timestamp of the 'daisy' directory.
		$filestat = stat("$POSDIR");
		$installdate = strftime("%Y-%m-%d", localtime($filestat->ctime));


		# Install Directory.
		$installdir = $POSDIR;


		# In daisy, we usually put the eDirectory version in 'control.tel', which is a
		# cleartext file.
		open FILE, "< $POSDIR/control.dsy";
			$edirectory = <FILE>;
		close FILE;
		chomp($edirectory);

	}


	# POSType
	$postype = $POS;





	# Public IP Address
	$publicip = "Unknown";
	open PIPE, "curl --silent http://www.whatismyip.com |";
	while(<PIPE>) {
		chomp;
		$string = $_;
		if( $string =~ /((\d+){1,3}([[:punct:]])(\d+){1,3}([[:punct:]])(\d+){1,4}([[:punct:]])(\d+){1,3})/) {
			$publicip = $1;
			last;
		}
	}
	close PIPE;



	# Custom Inventory Version
	# Ie, version of this script.
	$string = '$Revision: 1.2 $';
	@array = split(/[[:space:]]/,$string);
	$custominv_version = $array[1];




	# Print our resultant record.
	# Note that Chad wants *one* row, with columns per data.
	# These columsns need to be at least consisten with those in Dove POS.
	chomp($shopcode);
	chomp($POS);
	chomp($buildnum);
	chomp($installdate);
	chomp($installdir);
	chomp($edirectory);
	chomp($publicip);
	print "$shopcode,$POS,$buildnum,$installdate,$installdir,Server,$edirectory,$publicip,$custominv_version\n";


}





#
# Modified version from RTI install script.
#
sub get_pro5_version
{
	my $pro5dir = "";
	my $pro5version = "Unknown";


	# Determine where pro5 executable lives.
	# look in profile.d for PRO5_DIR=blah
	open FILE, "< /etc/profile.d/pro5.sh";
	while(<FILE>) {
		chomp;
		if(/^(\s*)(PRO5_DIR)(\s*)(=)(\s*)([[:print:]]+)/) {
			$pro5dir = $6;
		}
	}
	close FILE;

	if(! -f "$pro5dir/pro5") {
		return "$pro5version";
	}




	# Make sure this is the right version of pro5
	open FILE, "> /tmp/pro5_rev.$$";
		print FILE "PRINT REV;BYE\n";
	close FILE;
	open PRO5, "$pro5dir/pro5 -c$POSDIR/config/config.bbx < /tmp/pro5_rev.$$ |";
	while(<PRO5>) {
		if( /^(REV)([[:space:]]+)(\d+\.\d+)/) {
			$pro5version = $3;
			last;
		}
	}
	close PRO5;
	unlink("/tmp/pro5_rev.$$");

	chomp($pro5version);
	return $pro5version;
}



#############################################
sub custominv_rti_versions
{
	my @array = ();
	my $build = "";
	my $thisfile = "";
	my $filelist = "";
	my $value = "";


	# Headers
	print "AeX_CI_Teleflora_RTI_Versions\n";
	print "Delimiters = \",\"\n";
	print "string40 string20\n";
	print "Program Version\n";



	# Get RTI Build
	$build = "Unknown";
	if(-f "$POSDIR/bbxd/RTI.ini") {
		open FILE, "< $POSDIR/bbxd/RTI.ini";
		while(<FILE>) {
			chomp;
			if(/(VERSION)(\s*)(=)(\s*)([[:print:]]+)/) {
				$build = $5;
				last;
			}
		}
		close FILE;
	} else {
		$build = "$POSDIR/config/RTI.ini file not found";
	}

	print "RTI Build,$build\n";




	# Get TCC Version
	$build = "Unknown";
	if(-e "$POSDIR/bin/tcc_linux") {
		open PIPE, "$POSDIR/bin/tcc_linux --version |";
		while(<PIPE>) {
			chomp;
			if(/(Version:)(\s*)([[:print:]]+)/) {
				$build = $3;
				last;
			}
		}
		close PIPE;
	}
	print "TCC,$build\n";



	# Pro-5 Version.
	$build = "Unknown";
	$build = get_pro5_version();
	print "Pro5Version,$build\n";




	# Various RTI scripts, executables and BBx files.
	$filelist = "";
	$filelist .= " " . "$POSDIR/bbxps/*";
	$filelist .= " " . "$POSDIR/bbxp/*";
	$filelist .= " " . "$POSDIR/bin/*";
	open PIPE, "find $filelist -type f -print 2> /dev/null |";
	while(<PIPE>) {
		chomp;
		$thisfile = $_;

		# Scan this particular (binary) file for the
		# fingerprint of "$Revision: 1.2 $"
		#
		open FILE, "< $thisfile";
		while(<FILE>) {
			if(/(Revision: \S+)/) {
				@array = split(/[[:space:]]/,$1);
				$value = $array[1];
				$thisfile =~ s/,/_/g;
				print "$thisfile,$value\n";
				last;
			}
		}
		close FILE;
	}
	close PIPE;
}




sub custominv_rti_configs
{
	my $filelist = "";
	my $thisfile = "";
	my $key = "";
	my $value = "";

	# Headers
	print "AeX_CI_Teleflora_RTI_Configurations\n";
	print "Delimiters = \",\"\n";
	print "string25 string100 string100\n";
	print "Key Value Filename\n";



	# .ini files.
	$filelist = "";
	$filelist .= " " . "$POSDIR/config/*.ini";
	$filelist .= " " . "$POSDIR/bbxd/*.ini";
	$filelist .= " " . "$POSDIR/config/config.bbx";
	$filelist .= " " . "/etc/profile.d/rti.sh";
	$filelist .= " " . "/etc/profile.d/pro5.sh";
	open PIPE, "find $filelist -type f -print 2> /dev/null | sort |";
	while(<PIPE>) {
		chomp;
		$thisfile = $_;

		# Scan this particular (binary) file for the
		# fingerprint of FOO=BAR
		#
		open FILE, "< $thisfile";
		while(<FILE>) {


			# KEY = VALUE
			if(/^(\s*)(\S+)(\s*)(=)(\s*)([[:print:]]+)$/) {
				$thisfile =~ s/,/_/g;
				$key = $2;
				if($key ne "") {
					$key =~ s/,/_/g;
				}
				$value = $6;
				chomp($value);
				if($value ne "") {
					$value =~ s/,/_/g;
				}
				print "$key,$value,$thisfile\n";


			# Config.bbx "alias" lines.
			# alias LP "|lp -dreport1 -s 2>/dev/null" "HPLASERJET Report Printer" CR,PTON=1B451B266C37481B266C36441B287330501B266C372E323743,SP=1B2873313048,CP=1B2873313748,CPCOLS=255,SPCOLS=255
			} elsif (/^(\s*)(alias)(\s*)(\w+)(\s*)([[:print:]]+)$/i) {
				$key = "alias $4";
				$value = $6;
				$value =~ s/,/_/g;
				chomp($value);
				print "$key,$value,$thisfile\n";
			}

		}
		close FILE;
	}
	close PIPE;



	# rtiBackgr
	# Which "daemon" processes are running?
	$thisfile = "$POSDIR/config/rtiBackgr";
	open FILE, "< $thisfile";
	while(<FILE>) {
		chomp;
		if(/^(\s*)(\w+)/) {
			$key = $2;
			$key =~ s/,/_/g;
			$value = "Enabled";
			print "$key, $value, $thisfile\n";
		}
	}
	close FILE;
}







sub custominv_rti_logerrors
{
	# Headers
	print "AeX_CI_Teleflora_RTI_Errors\n";
	print "Delimiters = \",\"\n";
	print "string20 string128 string100\n";
	print "Timestamp Message ErrorFile\n";


	# Look for errors in RTI logfiles.
	$filelist .= " " . "$POSDIR/log/*.log";
	custominv_rti_logfile($filelist);


	# Pick items out of /var/log/secure
	custominv_secure();





}






# 
# Log contents of a specific logfile.
# if "logtype" of "errors" is passed, then, only '<E>' log entries
# are returned, and those are returned in *descending* order (ie, most
# recent error on top.
#
sub custominv_rti_logfile
{
	my $filelist = $_[0];
	my $filestat = "";
	my $timestamp = "";
	my $datestamp = "";
	my $severity = "";
	my $message = "";
	my $thisfile = "";

	open PIPE, "find $filelist -type f -print 2> /dev/null |";
	while(<PIPE>) {
		chomp;
		$thisfile = $_;



		# Find the month/day/year for this file.
		$filestat = stat($thisfile);
		$datestamp = strftime("%Y-%m-%d", localtime($filestat->ctime));


		# Pick out errors in logfiles.
		open FILE, "< $thisfile";
		while(<FILE>) {
			chomp;


			# HH:MM:SS <E> blah
			if(/^(\d\d:\d\d:\d\d)([[:print:]]+)(<[A-Z]>)(\s*)([[:print:]]+)/) {
				$timestamp = $1;
				$severity = $3;
				$message = $5;
				if($message ne "") {
					$message =~ s/,/_/g;
				}

				next if ($severity !~ /<E>/i);
				print "$datestamp $timestamp,$message,$thisfile\n";


			# YYYY-MM-DD HH:MM:SS <E> blah
			} elsif(/^(\d\d\d\d-\d\d-\d\d\s+\d\d:\d\d:\d\d)([[:print:]]+)(<[A-Z]>)(\s*)([[:print:]]+)/) {
				$timestamp = $1;
				$severity = $3;
				$message = $5;
				if($message ne "") {
					$message =~ s/,/_/g;
				}

				next if ($severity !~ /<E>/i);
				print "$datestamp $timestamp,$message,$thisfile\n";

			}

		}
		close FILE;
	}
	close PIPE;
}
