#!/usr/bin/perl
use URI::Escape;
#Created/Modified by
#BT 9/24/11 Initial code for all inclusive msr check
#CPU type codes
my $CPU_PPC = 18;
my $CPU_INTEL = 7;
#bools
my $TRUE = 1;
my $FALSE = 0;
my $serialNumCmd = 'grep "Serial Number (system)"'; #not valid on 10.4
#determines if the OS is lion or higher
my $lion = $FALSE;
#vals
my %sysvals = ();
########################################
# Perl trim function to remove whitespace from the start and end of the string
#source: http://www.somacon.com/p114.php
sub trim($)
{
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
########################################
#CPU Blacklist
#Designed so that future processors can be accommodated, regardless of speed
##############
#All Motorola (not going to check for this since likelihood of this actually coming up is nil, last processor was from '95)
#All PowerPC
#All Intel Core Solo
#Intel Core Duo if < 1.83 GHz
#pass otherwise
sub checkCPU
{
#blacklisted cpu names
my $bl_coreSolo = "Intel Core Solo";
my $bl_coreDuo = "Intel Core Duo"; #only blacklisting if under 1.83 GHz
#required CPU Freq
my $req_freqcoreduo = 1.83 * 1000 * 1000 * 1000; #1.83 GHz converted to Hz
#get cpu type
my $cputype = trim(`sysctl -n hw.cputype`);
#get cpu speed
my $cpufreq = trim(`sysctl -n hw.cpufrequency_max`);
$sysvals{'cpu_speed'} = int($cpufreq / (1000 * 1000)); #convert to MHz from Hz
#get cpu name
my $cpuname = trim(`system_profiler -detailLevel mini | grep "Processor Name:" | cut -d : -f 2-9`);
$sysvals{'cpu_name'} = $cpuname;
#other values we'd like to collect
$sysvals{'cpu_cores'} = trim(`sysctl -n hw.activecpu`); #compatible with 10.3.9 mac mini
#cpuResult
my $cpuFail = $FALSE;
#blacklist all PowerPCs
if($cputype == $CPU_PPC)
{
$cpuFail = $TRUE;
}
elsif($cputype == $CPU_INTEL)
{
my $cmp = 999;
#blacklist core solos
if(($cmp = index($cpuname, $bl_coreSolo)) != -1)
{
print "Intel Core Solo failed: $cpuname, result=$cmp\n";
$cpuFail = $TRUE;
}
elsif(($cmp = index($cpuname, $bl_coreDuo)) != -1)
{
#blacklist all core duos that are below the speed requirement
if($cpufreq < $req_freqcoreduo)
{
print "Intel Core Duo: failed cpufreq < intel cpu : $cpuname, result=$cmp\n";
$cpuFail = $TRUE;
}
else
{
print "Intel Core Duo passed: $cpuname, result=$cmp\n";
}
}
else
{
print "CPU Passed: $cpuname\n";
}
}
return $cpuFail;
}
sub checkMem
{
my $memFail = $FALSE;
#mem requirement
my $req_mem = 1 * 1024 * 1024 * 1024; #1 GB, convert to bytes
#get memsize
my $memsize = trim(`sysctl -n hw.memsize`); #in bytes
$sysvals{'memory_amount'} = int($memsize / (1024 * 1024)); #convert to GB for easy reading in db
#other values to retrieve
#memory speed
$sysvals{'memory_speed'}=trim(`system_profiler SPMemoryDataType | grep "Speed:" | grep "Hz" | tail -n 1 | tr -cd 0-9`);
if($memsize < $req_mem)
{
print "memsize < req memsize : $memsize < $req_mem\n";
$memFail = $TRUE;
}
else
{
print "memsize passed : $memsize >= $req_mem\n";
}
return $memFail;
}
sub setLionFlag
{
my $major = $_[0];
my $minor = $_[1];
#lion flag is FALSE by default, so only need to check for true
if($major == 10)
{
if($minor >= 7)
{
$lion = $TRUE;
}
}
else
{
#default to silverlight 5 in other cases
$lion = $TRUE;
}
}
#need to see how OS X 10.0 is reported...might need to use looks_like_number
sub checkOSX
{
#required min OSX version
my $req_major = 10;
my $req_minor = 5;
my $req_bugfix = 0;
#get OSX version
my $major = trim(`sw_vers -productVersion | cut -d . -f 1`);
my $minor = trim(`sw_vers -productVersion | cut -d . -f 2`);
my $bugfix = trim(`sw_vers -productVersion | cut -d . -f 3`);
#get data for storage
$sysvals{'os'} = trim(`sw_vers -productName`);
$sysvals{'os_version'} = trim(`sw_vers -productVersion`);
#set the lion flag
setLionFlag($major, $minor);
my $osxFail = $FALSE;
if($major < $req_major)
{
$osxFail = $TRUE;
print "OSX Failed: Major $major.$minor.$bugfix < $req_major.$req_minor.$req_bugfix\n";
}
elsif ($major == $req_major) #skip if major > req_major
{
if($minor < $req_minor)
{
$osxFail = $TRUE;
print "OSX Failed: Minor $major.$minor.$bugfix < $req_major.$req_minor.$req_bugfix\n";
}
elsif ($minor == $req_minor) #skip if minor > req_minor
{
if($bugfix < $req_bugfix)
{
$osxFail = $TRUE;
print "OSX Failed: Bugfix $major.$minor.$bugfix < $req_major.$req_minor.$req_bugfix\n";
}
else #else bugfix >= req_bugfix
{
print "OSX Passed: $major.$minor.$bugfix >= $req_major.$req_minor.$req_bugfix\n";
}
}
}
return $osxFail;
}
#need to see how OS X 10.0 is reported...might need to use looks_like_number
sub checkSilverlight
{
print "Checking Silverlight...\n";
#required min Silverlight version
my $req_major = 4;
my $req_minor = 0;
my $req_bugfix = 60310;
if($lion)
{
$req_major = 5;
$req_minor = 0;
$req_bugfix = 0;
}
#get silverlight version
#read file located at /Library/Internet Plug-Ins/Silverlight.plugin/Contents/Info.plist
open FILE, "/Library/Application Support/Microsoft/Silverlight/version.txt" or return $TRUE;
my @filelines = <FILE>;
close FILE;
my @verparts = split(/\./, $filelines[0]);
#not sure if that produces a permission denied error
my $major = $verparts[0];
my $minor = $verparts[1];
my $bugfix = $verparts[2];
#get data for storage
$sysvals{'silverlight_version'} = trim($filelines[0]);
my $slFail = $FALSE;
if($major < $req_major)
{
$slFail = $TRUE;
print "Silverlight Failed: Major $major.$minor.$bugfix < $req_major.$req_minor.$req_bugfix\n";
}
elsif ($major == $req_major) #skip if major > req_major
{
if($minor < $req_minor)
{
$slFail = $TRUE;
print "Silverlight Failed: Minor $major.$minor.$bugfix < $req_major.$req_minor.$req_bugfix\n";
}
elsif ($minor == $req_minor) #skip if minor > req_minor
{
if($bugfix < $req_bugfix)
{
$slFail = $TRUE;
print "Silverlight Failed: Bugfix $major.$minor.$bugfix < $req_major.$req_minor.$req_bugfix\n";
}
#else #else bugfix >= req_bugfix
#{
# print "Silverlight Passed: $major.$minor.$bugfix >= $req_major.$req_minor.$req_bugfix\n";
#}
}
}
if($slFail == $FALSE){
print "Silverlight Passed: $major.$minor.$bugfix >= $req_major.$req_minor.$req_bugfix\n";
}
return $slFail;
}
sub checkFreeDisk
{
#recommended free disk
my $req_disk = 30 * 1024 * 1024; #25 Megabytes, in bytes
#get free disk
my $freedisk = `df -b / | tail -n 1 | tr -s "[:space:]" | cut -d ' ' -f 4` * 512; #mult by 512 bc the shell command returns number of 512-byte blocks
$sysvals{'hard_drive_free'} = int($freedisk / (1024 * 1024)); #convert to megabytes from bytes
#other info to store
$sysvals{'hard_drive_total'} = (`df -b / | tail -n 1 | tr -s "[:space:]" | cut -d ' ' -f 3` * 512) + $freedisk;
$sysvals{'hard_drive_total'} = int($sysvals{'hard_drive_total'} / (1024 * 1024)); #convert to megabytes from bytes
my $diskFail = $FALSE;
if($freedisk < $req_disk)
{
print "Free Disk fail: $freedisk < $req_disk\n";
$diskFail = $TRUE;
}
else
{
print "Free Disk pass: $freedisk >= $req_disk\n";
}
return $diskFail;
}
sub checkWiFi
{
my $wifiFail = $FALSE;
$sysvals{'network_secure'}="U"; #Unknown
#wifi fail conditions
my @fail = ("link auth: none", "Security: none", "link auth: unknown");
#need to merge fail with bypass
#where airport does not exist, invoking the airport command returns:
#WirelessAttach: getInterfaceWithName failed
#tested on mac mini, OS X 10.3.9
my @bypassfail = ("failed", "linkStatus: Disabled", "BSSID: 0:0:0:0:0:0");
#get airport status
#using --getinfo instead of -I for legacy support
my $airportdata = `/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport --getinfo`;
#check wifi authentication enabled
my $stage1fail = $FALSE;
for($i = 0; $i < scalar(@fail); $i++)
{
my $cmp = 999;
if(($cmp = index($airportdata, $fail[$i])) != -1)
{
$stage1fail = $TRUE;
print "WiFi Stage 1 Fail: $fail[$i] : index=$cmp\n$airportdata\n";
}
}
#this accounts for the case where airport is off (returns "AirPort: Off")
#also should allow it to pass if it returns unrecognized text.
if($stage1fail)
{
my $stage2bypass = $FALSE;
for($i = 0; $i < scalar(@bypassfail); $i++)
{
my $cmp = 999;
if(($cmp = index($airportdata, $bypassfail[$i])) != -1)
{
$stage2bypass = $TRUE;
print "WiFi Stage 2 BypassFail: $bypassfail[$i] : index=$cmp\n$airportdata\n";
}
}
if(!$stage2bypass)
{
$wifiFail = $TRUE;
$sysvals{'network_secure'}="N";
}
else
{
print "WiFi passed\n";
$sysvals{'network_secure'}="Y";
}
}
else
{
print "WiFi passed\n";
}
return $wifiFail;
}
sub checkWiFiTwo
{
# conditions where wifi isn't valid include:
# airport doesn't exist
# airport is off
# airport is on but not connected
my $wifiFail = $FALSE;
$sysvals{'network_secure'}="U"; #Unknown
#wifi fail conditions
my @fail = ("link auth: none", "Security: none", "link auth: unknown");
#need to merge fail with bypass
#where airport does not exist, invoking the airport command returns:
#WirelessAttach: getInterfaceWithName failed
#tested on mac mini, OS X 10.3.9
my @bypass = ("failed", "linkStatus: Disabled", "BSSID: 0:0:0:0:0:0", "AirPort: Off");
#get airport status
#using --getinfo instead of -I for legacy support
my $airportdata = trim(`/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport --getinfo`);
#check wifi authentication enabled
my $stage1bypass = $FALSE;
for($i = 0; $i < scalar(@bypass); $i++)
{
my $cmp = 999;
if(($cmp = index($airportdata, $bypass[$i])) != -1)
{
$stage1bypass = $TRUE;
print "WiFi Stage 1 Bypass: $bypass[$i] : index=$cmp\n$airportdata\n";
last;
}
}
#if it didn't bypass then we are alive and connected
#also should allow it to pass if we have unrecognized text.
if(!$stage1bypass)
{
my $stage2fail = $FALSE;
for($i = 0; $i < scalar(@fail); $i++)
{
my $cmp = 999;
if(($cmp = index($airportdata, $fail[$i])) != -1)
{
$stage2fail = $TRUE;
print "WiFi Stage 2 Fail: $fail[$i] : index=$cmp\n$airportdata\n";
last;
}
}
if($stage2fail)
{
$wifiFail = $TRUE;
$sysvals{'network_secure'}="N";
}
else
{
print "WiFi passed\n";
$sysvals{'network_secure'}="Y";
}
}
else
{
print "WiFi passed\n";
}
return $wifiFail;
}
#source: http://stackoverflow.com/questions/1743406/user-properties-privileges-in-applescript
sub checkAdmin
{
my $ADMIN = 80;
my $permTxt = `id -G`;
my @perms = split(/ /, $permTxt);
print @perms;
my $adminFail = $TRUE;
for($i = 0; $i < scalar(@perms); $i++)
{
if($perms[$i] == $ADMIN)
{
print "User is Admin\n";
$adminFail = $FALSE;
$sysvals{'admin'}="Y";
}
}
if($adminFail)
{
print "User Not Admin\n";
$sysvals{'admin'}="N";
}
return $adminFail;
}
#checkExternal
sub checkExternal
{
print "FUNC: checking external\n";
my $extFail = $FALSE;
$numDisplays = trim(`system_profiler SPDisplaysDataType | grep -c "Resolution"`);
if($numDisplays >1 )
{
$extFail = $TRUE;
print "FUNC: external detected\n";
}
return $extFail;
}
sub checkLaptop
{
print "FUNC: checking laptop\n";
my $laptopFail = $FALSE;
$numLaptop = trim(`system_profiler SPDisplaysDataType | grep -c "LCD:"`);
$numIMac = trim(`system_profiler SPDisplaysDataType | grep -c "iMac:"`);
if(($numLaptop == 0) && ($numIMac == 0))
{
$laptopFail = $TRUE;
print "FUNC: not laptop or iMac\n";
}
return $laptopFail;
}
#send to db
sub dbstore
{
$url = "http://optimumapp.iptv.optimum.net/iotvlogger.jsp?type=msr_mac";
$i = 0;
while ( my ($key, $value) = each(%sysvals) ) {
$url .= "&$key=".uri_escape($value);
}
print "$url\n";
$result = `curl -Sv "$url"`;
print $result;
}
sub getOtherInfo
{
#get additional info that was not already retrieved and used for the msr
#mac addresses
#osx serial
$cmd = 'system_profiler SPHardwareDataType | '.$serialNumCmd.' | cut -d : -f 2';
$sysvals{'osx_serial'}= trim(`$cmd`);
#gpu
$sysvals{'gpu_name'}= trim(`system_profiler SPDisplaysDataType | grep "Chipset Model:" | cut -d : -f 2`);
#gpu_ram
$sysvals{'gpu_ram'}=trim(`system_profiler SPDisplaysDataType | grep "VRAM" | cut -d : -f 2 | tr -cd 0-9`);
}
sub exitWarn
{
$sysvals{'result'}="W";
my $warnOffset = 32;
$sysvals{'resultCode'}=$_[0];
dbstore();
exit ($_[0] + $warnOffset);
}
sub exitFail
{
$sysvals{'result'}="F";
my $failOffset = 96;#for utest 32;
$sysvals{'resultCode'}=$_[0];
#print"exitfail $_[0] offsetresult is ($_[0]+$failOffset)\n";
dbstore();
exit ($_[0] + $failOffset);
}
sub exitSuccess
{
$sysvals{'result'}="P";
dbstore();
exit 0;
}
#retrieve info
$sysvals{'app_version'} = "1.56";
#high priority checks
$cpu = checkCPU();
$mem = checkMem();
$osx = checkOSX();
#ensure that silverlight check is done AFTER OSX check due to Lion check
$slversion = checkSilverlight();
#misc check warnings
$disk = checkFreeDisk();
$wifi = checkWiFiTwo();
$admin = checkAdmin();
$laptop = checkLaptop();
$external = checkExternal();
getOtherInfo();
#return custom error codes for each class of failure
#order is important here
#no longer returning all of these error codes
if($cpu && $mem && $osx){
print "RESULT: CPU, Mem and OSX Fail\n";
exitFail(16);
}
if($cpu && $mem){
print "RESULT: CPU and Mem Fail\n";
exitFail(17);
}
if($cpu && $osx){
print "RESULT: CPU and OSX Fail\n";
exitFail(18);
}
if($mem && $osx){
print "RESULT: Mem and OSX Fail\n";
exitFail(19);
}
if($cpu){
print "RESULT: CPU Fail\n";
exitFail(20);
}
if($mem){
print "RESULT: Mem Fail\n";
exitFail(21);
}
if($osx){
print "RESULT: OSX Fail\n";
exitFail(22);
}
if($laptop)
{
print "RESULT: not laptop\n";
exitFail(28);
}
if($external)
{
print "RESULT: external detected\n";
exitFail(27);
}
#if($disk && $wifi){
# print "RESULT: Disk and Wifi Fail\n";
# exitWarn(23); #warning only
#}
#if($disk){
# print "RESULT: Disk Fail\n";
# exitWarn(24); #warning only
#}
#if($wifi){
# print "RESULT: Wifi Fail\n";
# exitWarn(25); #warning only
#}
if($slversion){
print "RESULT: Silverlight Version Fail\n";
my $sldl = $ARGV[0]."/Contents/Resources/sldl.sh";
my $response = `"$sldl"`; #need to place quotes to account for spaces in path
if(index($response, "Yes") != -1)
{
`open http://go2.microsoft.com/fwlink/?LinkID=149156`;
}
exitFail(29); #warning only
}
if($admin){
print "RESULT: Admin Fail\n";
exitWarn(26); #warning only
}
#otherwise successful
exitSuccess();