| 1 | rodolico | 1 | #! /usr/bin/perl -w
 | 
        
           |  |  | 2 |   | 
        
           |  |  | 3 | # process_sysinfo.pl
 | 
        
           |  |  | 4 | # Author: R. W. Rodolico
 | 
        
           |  |  | 5 | # Part of sysinfo package. This application takes the output from sysinfo.pl as input, parsing
 | 
        
           |  |  | 6 | # it and populating a database (see sysinfo.sql) with the results.
 | 
        
           |  |  | 7 | # Application will bypass anything up to the line beginning with [sysinfo version], allowing
 | 
        
           |  |  | 8 | # the output of sysinfo.pl to be e-mailed to a central server, where this app will correctly parse
 | 
        
           |  |  | 9 | # it.
 | 
        
           |  |  | 10 | # Application also has limited sensing capabilities, and will respond to certain conditions with a
 | 
        
           |  |  | 11 | # message on STDOUT indicating conditions, such as disk usage above an alarm value, new Operating Systems
 | 
        
           |  |  | 12 | # installed, etc... The goal is to allow this program to be called by a cron job, and the result (if any)
 | 
        
           |  |  | 13 | # returned in the cron specified e-mail.
 | 
        
           |  |  | 14 | # OVERVIEW:
 | 
        
           |  |  | 15 | #    The input file contains two types of information, both beginning with a tag surrounded by square
 | 
        
           |  |  | 16 | #    brackets. The single line data has the value for that tag immediately following the tag, ie:
 | 
        
           |  |  | 17 | #       [tagname]value
 | 
        
           |  |  | 18 | #    Multiline data has a beginning tag, then data following on a line by line basis, until the next
 | 
        
           |  |  | 19 | #    tag (denoted by a tag name surrounded by square brackets) is reached. Every line between the first
 | 
        
           |  |  | 20 | #    and subsequent tag are considered data for the previous tag, ie:
 | 
        
           |  |  | 21 | #       [tagname1]
 | 
        
           |  |  | 22 | #       value 1
 | 
        
           |  |  | 23 | #       value 2
 | 
        
           |  |  | 24 | #       [tagname2]
 | 
        
           |  |  | 25 | #    thus, value 1, and value 2 are data for tagname1. Multiline data is stored in its own hash, and handled
 | 
        
           |  |  | 26 | #    by separate routines.
 | 
        
           |  |  | 27 | #    See bottom of this app for main routine; subroutines are in between here and the beginning of the main
 | 
        
           |  |  | 28 | #    code
 | 
        
           |  |  | 29 |   | 
        
           |  |  | 30 | # Required Libraries:
 | 
        
           |  |  | 31 | #      GenericSQL        - Home Grown MySQL access routine, included with package
 | 
        
           |  |  | 32 | #      GenericTemplates  - Home Grown routine, included with package
 | 
        
           |  |  | 33 | #      Logging           - Home Grown logging routine, included with package
 | 
        
           |  |  | 34 | #      Date (uses format and parse)
 | 
        
           |  |  | 35 |   | 
        
           |  |  | 36 | # Suggested Uses: See process_sysinfo.sh. This is an example that looks for all messages in a directory
 | 
        
           |  |  | 37 | #                 (in this case, a maildir directory), processes each e-mail, then moves the e-mail
 | 
        
           |  |  | 38 | #                 to the Processed folder. The advantage to this is that it can be called by a nightly
 | 
        
           |  |  | 39 | #                 cron job, with any warnings e-mailed back to the sysadmin
 | 
        
           |  |  | 40 |   | 
        
           |  |  | 41 | # version 0.10 20071103
 | 
        
           |  |  | 42 | #      Ready for distribution. Database fairly normalized.
 | 
        
           |  |  | 43 | # version 0.11 20071104
 | 
        
           |  |  | 44 | #      Bug fix, and set up for "uninstalled" software
 | 
        
           |  |  | 45 | # version 0.12 20071104
 | 
        
           |  |  | 46 | #      Adjusted so it will ignore blank package lines, and will handle directories_to_watch
 | 
        
           |  |  | 47 | # version 0.13 20071120
 | 
        
           |  |  | 48 | #      Fixed problem where a file that was NOT a valid sysinfo file would cause a run-away
 | 
        
           |  |  | 49 | # version 1.00 20071206
 | 
        
           |  |  | 50 | #  Modified for new database format
 | 
        
           |  |  | 51 | # version 1.01 20071208
 | 
        
           |  |  | 52 | # Modified for report_date to be a date/time stamp instead of just the date
 | 
        
           |  |  | 53 | # version 2.0.0b 20081208
 | 
        
           |  |  | 54 | # converted to read XML data. Also uses older style data, but converts it to standard hash to mimic xml
 | 
        
           |  |  | 55 | # Adds requirement for libxml-simple-perl
 | 
        
           |  |  | 56 | # version 2.0.1 20090416
 | 
        
           |  |  | 57 | # Bug fix
 | 
        
           |  |  | 58 |   | 
        
           |  |  | 59 |   | 
        
           |  |  | 60 | my $VERSION = '2.0.1';
 | 
        
           |  |  | 61 |   | 
        
           |  |  | 62 | # only required if reports are sent from process_sysinfo. Not the norm.
 | 
        
           |  |  | 63 | my $iMailResults;
 | 
        
           |  |  | 64 | my $mailTo;
 | 
        
           |  |  | 65 | my $mailCC;
 | 
        
           |  |  | 66 | my $mailBCC;
 | 
        
           |  |  | 67 | my $mailServer;
 | 
        
           |  |  | 68 | my $mailServerPort;
 | 
        
           |  |  | 69 | my $mailFrom;
 | 
        
           |  |  | 70 | my $SENDMAIL;
 | 
        
           |  |  | 71 | my $DiskUsageAlert = 90; # will generate a warning if any disk has more than this percent capacity used
 | 
        
           |  |  | 72 |   | 
        
           |  |  | 73 | # information for the database
 | 
        
           |  |  | 74 | #my $DSN = 'DBI:mysql:camp'; # and, set up the database access
 | 
        
           |  |  | 75 | #my $DB_USER = 'test';
 | 
        
           |  |  | 76 | #my $DB_PASS = 'test';
 | 
        
           |  |  | 77 |   | 
        
           |  |  | 78 | #my $LIBRARIES = '/home/www/common-cgi/'; # where the extra libraries are stored
 | 
        
           |  |  | 79 |   | 
        
           |  |  | 80 | # global variables (not configuration information)
 | 
        
           |  |  | 81 | my $dbh; # global variable for database handle
 | 
        
           |  |  | 82 | my @warnings; # variable to hold errors and warnings
 | 
        
           |  |  | 83 | my $FATAL = ''; # in case of a fatal error, this variable will hold the reason
 | 
        
           |  |  | 84 |   | 
        
           |  |  | 85 |   | 
        
           |  |  | 86 | # Globals that hold information after parsing by readAndParseInput
 | 
        
           |  |  | 87 | my $datafileVersion;# store the data file version here.
 | 
        
           |  |  | 88 | my $reportDate;      # global for the report date
 | 
        
           |  |  | 89 | my $clientID;
 | 
        
           |  |  | 90 | my $computerID;
 | 
        
           |  |  | 91 | my $clientName;
 | 
        
           |  |  | 92 | my $computerName;
 | 
        
           |  |  | 93 |   | 
        
           |  |  | 94 |   | 
        
           |  |  | 95 |   | 
        
           |  |  | 96 | #my %info;            # stores any single line tag/value pair
 | 
        
           |  |  | 97 | #my $ipAddresses;     # stores IP's for this machine
 | 
        
           |  |  | 98 | #my @diskInfo;        # stores the disk info
 | 
        
           |  |  | 99 | #my @packages;        # stores package info
 | 
        
           |  |  | 100 | #my @directoriesToWatch; # stores directories to watch
 | 
        
           |  |  | 101 | #my @pciInfo;        # stores pci info
 | 
        
           |  |  | 102 |   | 
        
           |  |  | 103 |   | 
        
           |  |  | 104 | # safe check for equality. Handles undefined
 | 
        
           |  |  | 105 | sub checkEquals {
 | 
        
           |  |  | 106 |    my ($first, $second) = @_;
 | 
        
           |  |  | 107 |    return ($first eq $second) if (defined $first) and (defined $second);
 | 
        
           |  |  | 108 |    return 1 if (! defined $first) and (! defined $second); # both undefined, so equal
 | 
        
           |  |  | 109 |    return 0;
 | 
        
           |  |  | 110 | }
 | 
        
           |  |  | 111 |   | 
        
           |  |  | 112 | # standard find and load configuration file
 | 
        
           |  |  | 113 | sub loadConfigurationFile {
 | 
        
           |  |  | 114 |    my $configuration_file = shift;
 | 
        
           |  |  | 115 |   | 
        
           |  |  | 116 |    use File::Basename;
 | 
        
           |  |  | 117 |    use Cwd qw(realpath);
 | 
        
           |  |  | 118 |   | 
        
           |  |  | 119 |    my $filename  = realpath($0); # get my real path
 | 
        
           |  |  | 120 |    my $directories;
 | 
        
           |  |  | 121 |    my $suffix;
 | 
        
           |  |  | 122 |    #print "$configuration_file\n";
 | 
        
           |  |  | 123 |    $configuration_file = $filename unless $configuration_file;
 | 
        
           |  |  | 124 |    #print "$configuration_file\n";
 | 
        
           |  |  | 125 |   | 
        
           |  |  | 126 |    if ( $configuration_file !~ m/\// ) { # no path information
 | 
        
           |  |  | 127 |       ($filename, $directories, $suffix) = fileparse($filename,qr/\.[^.]*/); # break filename apart
 | 
        
           |  |  | 128 |       #print "No Path Given\n";
 | 
        
           |  |  | 129 |    } else {
 | 
        
           |  |  | 130 |       ($filename, $directories, $suffix) = fileparse($configuration_file,qr/\.[^.]*/); # break filename apart
 | 
        
           |  |  | 131 |       $configuration_file = '';
 | 
        
           |  |  | 132 |       #print "Path included\n";
 | 
        
           |  |  | 133 |    }
 | 
        
           |  |  | 134 |    unless (-e $directories . ($configuration_file ? $configuration_file : $filename) . '.conf' ) {
 | 
        
           |  |  | 135 |       $lookingIn = $directories;
 | 
        
           |  |  | 136 |       while ($lookingIn) {
 | 
        
           |  |  | 137 |          $lookingIn =~ m/^(.*\/)[^\/]+\//;
 | 
        
           |  |  | 138 |          $lookingIn = $1;
 | 
        
           |  |  | 139 |          #print "$lookingIn\n";
 | 
        
           |  |  | 140 |          if (-e $lookingIn . ($configuration_file ? $configuration_file : $filename) . '.conf' ) {
 | 
        
           |  |  | 141 |             $directories = $lookingIn;
 | 
        
           |  |  | 142 |             $lookingIn = '';
 | 
        
           |  |  | 143 |          }
 | 
        
           |  |  | 144 |       }
 | 
        
           |  |  | 145 |    }
 | 
        
           |  |  | 146 |    $configuration_file = $directories . ($configuration_file ? $configuration_file : $filename) . '.conf'; # add the .conf
 | 
        
           |  |  | 147 | #   print "$configuration_file\n";
 | 
        
           |  |  | 148 | #   die;
 | 
        
           |  |  | 149 |    open CONFFILE, "<$configuration_file" or die "Can not open configuration file $configuration_file";
 | 
        
           |  |  | 150 |    my $confFileContents = join( '', <CONFFILE> );
 | 
        
           |  |  | 151 |    close CONFFILE;
 | 
        
           |  |  | 152 |    return $confFileContents;
 | 
        
           |  |  | 153 | }
 | 
        
           |  |  | 154 |   | 
        
           |  |  | 155 | # just a nice place to format any warnings/errors. Just prepend the client and computer name
 | 
        
           |  |  | 156 | sub createLogMessage {
 | 
        
           |  |  | 157 |    my $message = shift;
 | 
        
           |  |  | 158 |    $message = "$clientName - $computerName: " . $message;
 | 
        
           |  |  | 159 |    return $message;
 | 
        
           |  |  | 160 | }
 | 
        
           |  |  | 161 |   | 
        
           |  |  | 162 | # generic routine to send an e-mail
 | 
        
           |  |  | 163 | sub sendmessage {
 | 
        
           |  |  | 164 |    my ( $from, $to, $subject, $message, $cc, $bcc, $server, $port ) = @_;
 | 
        
           |  |  | 165 |   | 
        
           |  |  | 166 |    open SENDMAIL, "|$SENDMAIL" or die "Could not open sendmail";
 | 
        
           |  |  | 167 |    print SENDMAIL "From: $from\nTo: $to\nSubject: $subject\n";
 | 
        
           |  |  | 168 |    print SENDMAIL "cc: $cc\n" if $cc;
 | 
        
           |  |  | 169 |    print SENDMAIL "bcc: $bcc\n" if $bcc;
 | 
        
           |  |  | 170 |    print SENDMAIL "$message\n";
 | 
        
           |  |  | 171 |    print SENDMAIL ".\n";
 | 
        
           |  |  | 172 |    close SENDMAIL;
 | 
        
           |  |  | 173 | }
 | 
        
           |  |  | 174 |   | 
        
           |  |  | 175 | # simply used to get an attrib_id. If it does not exit, will create it
 | 
        
           |  |  | 176 |   | 
        
           |  |  | 177 | sub getAttributeID {
 | 
        
           |  |  | 178 |    my ($attributeName ) = @_;
 | 
        
           |  |  | 179 |    my $sql = qq/select attrib_id from attrib where name = $attributeName and removed_date is null/;
 | 
        
           |  |  | 180 |    my $result = &GenericSQL::getOneValue($dbh,$sql);
 | 
        
           |  |  | 181 |    unless ( $result ) {
 | 
        
           |  |  | 182 |       my $insertSQL = qq/insert into attrib (name,added_date) values ($attributeName,$reportDate)/;
 | 
        
           |  |  | 183 |       &GenericSQL::doSQL( $dbh,$insertSQL );
 | 
        
           |  |  | 184 |       $result = &GenericSQL::getOneValue($dbh,$sql);
 | 
        
           |  |  | 185 |       push @warnings, "Added a new attribute type [$attributeName]";
 | 
        
           |  |  | 186 |    }
 | 
        
           |  |  | 187 |    return $result;
 | 
        
           |  |  | 188 | }
 | 
        
           |  |  | 189 |   | 
        
           |  |  | 190 | sub fixDatabaseValue {
 | 
        
           |  |  | 191 |    # just return NULL if the parameter is invalid
 | 
        
           |  |  | 192 |    return 'NULL' unless defined $_[0];
 | 
        
           |  |  | 193 |   | 
        
           |  |  | 194 |    my ($value,$alwaysQuote) = @_;
 | 
        
           |  |  | 195 |    # remove leading and trailing blank spaces
 | 
        
           |  |  | 196 |    $value =~ s/^ +//gi;
 | 
        
           |  |  | 197 |    $value =~ s/ +$//gi;
 | 
        
           |  |  | 198 |    if ($alwaysQuote or ($value !~ m/^\d+$/)) { # Not a numeric value
 | 
        
           |  |  | 199 |       $value = &GenericSQL::fixStringValue($dbh, $value); # so get it ready for SQL (ie, put quotes around it, etc...
 | 
        
           |  |  | 200 |    }
 | 
        
           |  |  | 201 |    #$value = "'$value'" if $alwaysQuote && $value ;
 | 
        
           |  |  | 202 |    #print "AlwaysQuote [$alwaysQuote], value [$value]\n";
 | 
        
           |  |  | 203 |    return $value;
 | 
        
           |  |  | 204 | }
 | 
        
           |  |  | 205 |   | 
        
           |  |  | 206 | sub checkAndUpdateAttribute {
 | 
        
           |  |  | 207 |    my ($ID,$attribute,$value ) = @_;
 | 
        
           |  |  | 208 |    unless ($attribute && $value) {
 | 
        
           |  |  | 209 |       push @warnings, "Error: attempt to use null value for [$attribute], value [$value] for ID $ID in checkAndUPdateAttribute";
 | 
        
           |  |  | 210 |       return 0;
 | 
        
           |  |  | 211 |    }
 | 
        
           |  |  | 212 |    $value = &fixDatabaseValue($value, 1); # we want to always quote the value on this particular one
 | 
        
           |  |  | 213 |    #print "\tcheckAndUpdateAttribute:attribute/value = [$attribute][$value]\n";
 | 
        
           |  |  | 214 |    $attribute = &fixDatabaseValue( $attribute );
 | 
        
           |  |  | 215 |    my $attrib_id = &getAttributeID( $attribute, $reportDate );
 | 
        
           |  |  | 216 |    my $sql = qq/
 | 
        
           |  |  | 217 |       select device_attrib.value
 | 
        
           |  |  | 218 |       from device_attrib join attrib using (attrib_id)
 | 
        
           |  |  | 219 |       where device_attrib.device_id = $ID
 | 
        
           |  |  | 220 |             and device_attrib.removed_date is null
 | 
        
           |  |  | 221 |             and attrib.attrib_id = $attrib_id
 | 
        
           |  |  | 222 |       /;
 | 
        
           |  |  | 223 |    $result = &GenericSQL::getOneValue($dbh,$sql);
 | 
        
           |  |  | 224 |    $result = &fixDatabaseValue( $result, 1 ); # we must do this since we are comparing to $value which has had this done
 | 
        
           |  |  | 225 |    if ( $result ) { # got it, now see if it compares ok
 | 
        
           |  |  | 226 |       if ( $value ne $result ) { # nope, this has changed. Note, must use fixDatabaseValue for escapes already in $value
 | 
        
           |  |  | 227 |          # first, set the removed_date to now on the old part
 | 
        
           |  |  | 228 |          #die "[$reportDate][$ID][$attrib_id]\n";
 | 
        
           |  |  | 229 |          #print "\tresult = [$result], value = [$value]\n";
 | 
        
           |  |  | 230 |          $sql = qq/
 | 
        
           |  |  | 231 |             update device_attrib
 | 
        
           |  |  | 232 |             set removed_date = $reportDate
 | 
        
           |  |  | 233 |             where device_id = $ID
 | 
        
           |  |  | 234 |                   and attrib_id = $attrib_id
 | 
        
           |  |  | 235 |                   and removed_date is null
 | 
        
           |  |  | 236 |          /;
 | 
        
           |  |  | 237 |          &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 238 |          undef $result; # this will force the insert in the next block of code
 | 
        
           |  |  | 239 |       } # if $result ne $value
 | 
        
           |  |  | 240 |    } # if ($result)
 | 
        
           |  |  | 241 |    unless ( $result ) { # we have no valid entry for this attribute
 | 
        
           |  |  | 242 |       $sql = qq/
 | 
        
           |  |  | 243 |          insert into device_attrib(device_id,attrib_id,value,added_date)
 | 
        
           |  |  | 244 |             values ($ID,$attrib_id,$value,$reportDate)
 | 
        
           |  |  | 245 |          /;
 | 
        
           |  |  | 246 |       &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 247 |       return 1;
 | 
        
           |  |  | 248 |    }
 | 
        
           |  |  | 249 |    return 0;
 | 
        
           |  |  | 250 | }
 | 
        
           |  |  | 251 |   | 
        
           |  |  | 252 | # main subroutine that reads and parses the input
 | 
        
           |  |  | 253 | # it will place the appropriate values into the arrays/hashes
 | 
        
           |  |  | 254 | sub readAndParseInput {
 | 
        
           |  |  | 255 |    my @lines = <STDIN>; # suck all data lines into this array
 | 
        
           |  |  | 256 |    chomp @lines; # and remove eol chars
 | 
        
           |  |  | 257 |    while ( @lines && ( $lines[0] !~ m/^[\[\<]sysinfo/ ) ) { # skip any header lines that may exist
 | 
        
           |  |  | 258 |       shift @lines;
 | 
        
           |  |  | 259 |    }
 | 
        
           |  |  | 260 |    unless ( @lines ) {
 | 
        
           |  |  | 261 |       $FATAL = 'Invalid Report File';
 | 
        
           |  |  | 262 |       return;
 | 
        
           |  |  | 263 |    }
 | 
        
           |  |  | 264 |    if ( $lines[0] =~ m/<sysinfo([^>]*)>/ ) { # this is xml data
 | 
        
           |  |  | 265 |       $datafileVersion = $1;
 | 
        
           |  |  | 266 |       use XML::Simple; 
 | 
        
           |  |  | 267 |       my $output = XML::Simple->new();
 | 
        
           |  |  | 268 |       my $theXML = $output->XMLin(join( "\n",@lines));
 | 
        
           |  |  | 269 |       # XML::Simple is inconsistent in that the resulting hashes are different depending
 | 
        
           |  |  | 270 |       # on if they only have one instance of a block or multiples. This is ok most of the 
 | 
        
           |  |  | 271 |       # time, but for diskinfo, network, etc..., our code assumes the resulting hashes
 | 
        
           |  |  | 272 |       # will have a key into a hash reference, not simply a hash reference. The following 
 | 
        
           |  |  | 273 |       # kludge fixes that until I figure out the "right" way to do it.
 | 
        
           |  |  | 274 |       %toFix = ( 'diskinfo' => 'name', 'pci' => 'name' ); # , 'network'
 | 
        
           |  |  | 275 |       for $key ( keys %toFix ) { 
 | 
        
           |  |  | 276 |          #print "\n\nChecking $key\n";
 | 
        
           |  |  | 277 |          #print Data::Dumper->Dump([$$theXML{$key}],[$key]);
 | 
        
           |  |  | 278 |          my $test = $$theXML{$key};
 | 
        
           |  |  | 279 |          if ( defined $$test{ $toFix{$key}} ) { # This occurs if there is only one entry
 | 
        
           |  |  | 280 |             #print "We found a single entry hash\n";
 | 
        
           |  |  | 281 |             my $thisName = $$test{$toFix{$key}};
 | 
        
           |  |  | 282 |             delete $$test{$toFix{$key}};
 | 
        
           |  |  | 283 |             foreach $thisKey ( keys %$test ) {
 | 
        
           |  |  | 284 |                $$test{$thisName}{$thisKey} = $$test{$thisKey};
 | 
        
           |  |  | 285 |                delete $$test{$thisKey};
 | 
        
           |  |  | 286 |             }
 | 
        
           |  |  | 287 |          #print Data::Dumper->Dump([$$theXML{$key}],[$key]);
 | 
        
           |  |  | 288 |          }
 | 
        
           |  |  | 289 |       }
 | 
        
           |  |  | 290 |       # another problem, this time if the hostname is blank it the library sets it to an empty hash
 | 
        
           |  |  | 291 |       #print STDERR ref($$theXML{'system'}{'hostname'});
 | 
        
           |  |  | 292 |       # if the hostname is anything other than a pure scalar, just make it empty
 | 
        
           |  |  | 293 |       $$theXML{'system'}{'hostname'} = '' if ( ref($$theXML{'system'}{'hostname'}) );
 | 
        
           |  |  | 294 |       #print "\n\nAfter the check\n";
 | 
        
           |  |  | 295 |       #print Data::Dumper->Dump([$$theXML{'system'}],['system']);
 | 
        
           |  |  | 296 |       #die;
 | 
        
           |  |  | 297 |       return $theXML;
 | 
        
           |  |  | 298 |    } elsif ($lines[0] =~ m/\[sysinfo version\]/i) { # old style data file
 | 
        
           |  |  | 299 |       my %returnValue;
 | 
        
           |  |  | 300 |       my $linecount = 0; # just a pointer into the array
 | 
        
           |  |  | 301 |       # ok, we are in the actual data (this can be an e-mail)
 | 
        
           |  |  | 302 |       while ($linecount < @lines ) {
 | 
        
           |  |  | 303 |          if ($lines[$linecount++] =~ m/^\[([^\]]+)\](.*)$/ ) { # Assume single line entry, ie [tag]value
 | 
        
           |  |  | 304 |             $section = lc $1; # tag, section, whatever you want to call it. The thing inside the square brackets
 | 
        
           |  |  | 305 |             $value = $2; # this is what we are working with
 | 
        
           |  |  | 306 |             #$value = &fixDatabaseValue($2); # this is what we are working with
 | 
        
           |  |  | 307 |             # first, look for anything we want to place in global variables
 | 
        
           |  |  | 308 |             if ( $section eq 'sysinfo version' ) {
 | 
        
           |  |  | 309 |                $returnValue{'report'}{'version'} = $value;
 | 
        
           |  |  | 310 |                $datafileVersion = $value;
 | 
        
           |  |  | 311 |             } elsif ($section eq 'client name') {
 | 
        
           |  |  | 312 |                $returnValue{'report'}{'client'} = $value;
 | 
        
           |  |  | 313 |             } elsif ($section eq 'hostname' ) {
 | 
        
           |  |  | 314 |                $returnValue{'system'}{'hostname'} = $value;
 | 
        
           |  |  | 315 |             } elsif ($section eq 'report date') { # ok, so we put quotes around this and we don't want them
 | 
        
           |  |  | 316 |                $value =~ s/'//gi; # remove the quotes
 | 
        
           |  |  | 317 |                my $reportDate = substr($value,0,12); # and grab only the date, hours and minutes portion of the value
 | 
        
           |  |  | 318 |                $reportDate = substr($value,0,4) .'-' . substr($value,4,2) .'-' . substr($value,6,2) .' ' . substr($value,8,2) .':' . substr($value,10,2);
 | 
        
           |  |  | 319 |                $returnValue{'report'}{'date'} = $reportDate;
 | 
        
           |  |  | 320 |             } elsif ($section eq 'ip addresses' ) { # A machine can have multiple IP's
 | 
        
           |  |  | 321 |                @ipAddresses = split(' ', $value);
 | 
        
           |  |  | 322 |                my $counter = 0;
 | 
        
           |  |  | 323 |                while (my $ip = shift @ipAddresses) {
 | 
        
           |  |  | 324 |                   $returnValue{'network'}{$counter++}{'address'} = $ip;
 | 
        
           |  |  | 325 |                }
 | 
        
           |  |  | 326 |             # following are processing the multi-line tags. We just look through them and get the start and end
 | 
        
           |  |  | 327 |             # indicies of the section so they can be processed by the appropriate routines
 | 
        
           |  |  | 328 |             } elsif ($section eq 'disk info') {
 | 
        
           |  |  | 329 |                # disk info can be one or more line, so work until we find the next tag
 | 
        
           |  |  | 330 |                while ($linecount < @lines && $lines[$linecount] !~ m/^\[([^\]]+)\](.*)$/) {
 | 
        
           |  |  | 331 |                   my ( $device, $fstype, $size, $used, $mount ) = split( "\t",$lines[$linecount++] );
 | 
        
           |  |  | 332 |                   $returnValue{'diskinfo'}{$device}{'fstype'} = $fstype if $fstype;
 | 
        
           |  |  | 333 |                   $returnValue{'diskinfo'}{$device}{'size'} = $size if $size;
 | 
        
           |  |  | 334 |                   $returnValue{'diskinfo'}{$device}{'used'} = $used if $used;
 | 
        
           |  |  | 335 |                   $returnValue{'diskinfo'}{$device}{'mount'} = $mount if $mount;
 | 
        
           |  |  | 336 |                   #   push @diskInfo, $lines[$linecount++];
 | 
        
           |  |  | 337 |                }
 | 
        
           |  |  | 338 |             } elsif ($section eq 'packages installed') { # and, of course, software packages
 | 
        
           |  |  | 339 |                while ($linecount < @lines && $lines[$linecount] !~ m/^\[([^\]]+)\](.*)$/) {
 | 
        
           |  |  | 340 |                   if ( $lines[$linecount] =~ m/^\s*$/) {
 | 
        
           |  |  | 341 |                      $linecount++;
 | 
        
           |  |  | 342 |                      next;
 | 
        
           |  |  | 343 |                   }
 | 
        
           |  |  | 344 |                   my ($package, $version, $description) = split( "\t", $lines[$linecount++]);
 | 
        
           |  |  | 345 |                   $returnValue{'software'}{$package}{'version'} = $version;
 | 
        
           |  |  | 346 |                   $returnValue{'software'}{$package}{'description'} = $description;
 | 
        
           |  |  | 347 |                   #push @packages, $lines[$linecount++];
 | 
        
           |  |  | 348 |                }
 | 
        
           |  |  | 349 |             } elsif ($section eq 'pci info') { # this gives us some hardware info
 | 
        
           |  |  | 350 |                my $x = 0;
 | 
        
           |  |  | 351 |                while ($linecount < @lines && $lines[$linecount] !~ m/^\[([^\]]+)\](.*)$/) {
 | 
        
           |  |  | 352 |                   if ($lines[$linecount] =~ m/^\s*([0-9.:]+[\S])\s+(.*\S)\s*$/) { # we have a slot/name pair
 | 
        
           |  |  | 353 |                      $returnValue{'pci'}{$x}{'slot'} = $1;
 | 
        
           |  |  | 354 |                      $returnValue{'pci'}{$x}{'name'} = $2;
 | 
        
           |  |  | 355 |                   } else {
 | 
        
           |  |  | 356 |                      $returnValue{'pci'}{$x}{'slot'} = 'v1.x-unk';
 | 
        
           |  |  | 357 |                      $returnValue{'pci'}{$x}{'name'} = $lines[$linecount];
 | 
        
           |  |  | 358 |                   }
 | 
        
           |  |  | 359 |                   $x++;
 | 
        
           |  |  | 360 |                   $linecount++;
 | 
        
           |  |  | 361 |                }
 | 
        
           |  |  | 362 |             # we have a single line tag, so just store it in the right place
 | 
        
           |  |  | 363 |             } elsif ($value) {
 | 
        
           |  |  | 364 |                if ( $section eq 'client name' ) {
 | 
        
           |  |  | 365 |                   $returnValue{'report'}{'client'} = $value;
 | 
        
           |  |  | 366 |                } elsif ( $section eq 'distro_name' ) {
 | 
        
           |  |  | 367 |                   $returnValue{'operatingsystem'}{'distribution'} = $value;
 | 
        
           |  |  | 368 |                } elsif ( $section eq 'distro_description' ) {
 | 
        
           |  |  | 369 |                   $returnValue{'operatingsystem'}{'description'} = $value;
 | 
        
           |  |  | 370 |                } elsif ( $section eq 'distro_release' ) {
 | 
        
           |  |  | 371 |                   $returnValue{'operatingsystem'}{'release'} = $value;
 | 
        
           |  |  | 372 |                } elsif ( $section eq 'distro_codename' ) {
 | 
        
           |  |  | 373 |                   $returnValue{'operatingsystem'}{'codename'} = $value;
 | 
        
           |  |  | 374 |                } elsif ( $section eq 'hostname' ) {
 | 
        
           |  |  | 375 |                   $returnValue{'system'}{'hostname'} = $value;
 | 
        
           |  |  | 376 |                } elsif ( $section eq 'memory' ) {
 | 
        
           |  |  | 377 |                   $returnValue{'system'}{'memory'} = $value;
 | 
        
           |  |  | 378 |                } elsif ( $section eq 'num_cpu' ) {
 | 
        
           |  |  | 379 |                   $returnValue{'system'}{'num_cpu'} = $value;
 | 
        
           |  |  | 380 |                } elsif ( $section eq 'cpu_speed' ) {
 | 
        
           |  |  | 381 |                   $returnValue{'system'}{'cpu_speed'} = $value;
 | 
        
           |  |  | 382 |                } elsif ( $section eq 'cpu_type' ) {
 | 
        
           |  |  | 383 |                   $returnValue{'system'}{'cpu_type'} = $value;
 | 
        
           |  |  | 384 |                } elsif ( $section eq 'cpu_sub' ) {
 | 
        
           |  |  | 385 |                   $returnValue{'system'}{'cpu_sub'} = $value;
 | 
        
           |  |  | 386 |                } elsif ( $section eq 'os_name' ) {
 | 
        
           |  |  | 387 |                   $returnValue{'operatingsystem'}{'os_name'} = $value;
 | 
        
           |  |  | 388 |                } elsif ( $section eq 'os_version' ) {
 | 
        
           |  |  | 389 |                   $returnValue{'operatingsystem'}{'os_version'} = $value;
 | 
        
           |  |  | 390 |                } elsif ( $section eq 'kernel' ) {
 | 
        
           |  |  | 391 |                   $returnValue{'operatingsystem'}{'kernel'} = $value;
 | 
        
           |  |  | 392 |                } elsif ( $section eq 'boot' ) {
 | 
        
           |  |  | 393 |                   $returnValue{'system'}{'last_boot'} = $value;
 | 
        
           |  |  | 394 |                } elsif ( $section eq 'uptime' ) {
 | 
        
           |  |  | 395 |                   $returnValue{'system'}{'uptime'} = $value;
 | 
        
           |  |  | 396 |                }
 | 
        
           |  |  | 397 |                #$info{$section} = $value;
 | 
        
           |  |  | 398 |             } else { # we should never get here, a single line with no value is BAD
 | 
        
           |  |  | 399 |                push @warnings, &createLogMessage( "Unknown line '$lines[$linecount-1]'" ) . "\n";
 | 
        
           |  |  | 400 |             }
 | 
        
           |  |  | 401 |          } else { # this is also an error, no [tagname]. Maybe a space inserted?
 | 
        
           |  |  | 402 |             push @warnings, &createLogMessage( "unknown line '$lines[$linecount-1]'" ) . "\n";
 | 
        
           |  |  | 403 |          }
 | 
        
           |  |  | 404 |       } # while
 | 
        
           |  |  | 405 |       return \%returnValue;
 | 
        
           |  |  | 406 |    }
 | 
        
           |  |  | 407 | }
 | 
        
           |  |  | 408 |   | 
        
           |  |  | 409 | # tries to figure out the client. If the client does not exist, will create a null record
 | 
        
           |  |  | 410 | # for them. Stores result in $client_id (reading $clientName)
 | 
        
           |  |  | 411 | sub getClientID {
 | 
        
           |  |  | 412 |    # let's see if the client exists
 | 
        
           |  |  | 413 |    $client = &fixDatabaseValue($clientName);
 | 
        
           |  |  | 414 |    $sql = qq/select client_id from client where name = $client and removed_date is null/;
 | 
        
           |  |  | 415 |    my $client_id = &GenericSQL::getOneValue( $dbh, $sql );
 | 
        
           |  |  | 416 |    unless ($client_id) { # no entry, check the alias table
 | 
        
           |  |  | 417 |       $sql = qq/select client_id from client_alias where alias=$client and removed_date is null/;
 | 
        
           |  |  | 418 |       $client_id = &GenericSQL::getOneValue( $dbh, $sql );
 | 
        
           |  |  | 419 |    }
 | 
        
           |  |  | 420 |    # the following has been changed to simply return a message
 | 
        
           |  |  | 421 |    unless ( $client_id ) { # nope, client does not exist, so add them
 | 
        
           |  |  | 422 |       $device = &fixDatabaseValue($computerName);
 | 
        
           |  |  | 423 |       $sql = qq/select report_date from unknown_entry where client_name = $client and device_name = $device/;
 | 
        
           |  |  | 424 |       #$report = &GenericSQL::getOneValue( $dbh, $sql );
 | 
        
           |  |  | 425 |       #print STDERR "Report Date $report\n";
 | 
        
           |  |  | 426 |       if ($report = &GenericSQL::getOneValue( $dbh, $sql )) {
 | 
        
           |  |  | 427 |          $FATAL = "New Client detected, but entry already made. You must update Camp before this can be processed";
 | 
        
           |  |  | 428 |       } else {
 | 
        
           |  |  | 429 |          $sql = qq/insert into unknown_entry(client_name,device_name,report_date) values ($client, $device, $reportDate)/;
 | 
        
           |  |  | 430 |          &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 431 |          $FATAL = "Warning, new client $client found with new device $device. You must update Camp before this report can be processed\n";
 | 
        
           |  |  | 432 |       }
 | 
        
           |  |  | 433 |    }
 | 
        
           |  |  | 434 |    return $client_id;
 | 
        
           |  |  | 435 | }
 | 
        
           |  |  | 436 |   | 
        
           |  |  | 437 | # get a device type id from the device table. Create it if it does not exist
 | 
        
           |  |  | 438 | sub getDeviceTypeID {
 | 
        
           |  |  | 439 |    my $typeDescription = &GenericSQL::fixStringValue( $dbh, shift );
 | 
        
           |  |  | 440 |    my $reportDate = shift;
 | 
        
           |  |  | 441 |    $sql = qq/select device_type_id from device_type where name = $typeDescription and removed_date is null/;
 | 
        
           |  |  | 442 |    my $id = &GenericSQL::getOneValue( $dbh, $sql );
 | 
        
           |  |  | 443 |    unless ($id) {
 | 
        
           |  |  | 444 |       my $sql_insert = qq/insert into device_type ( name,added_date ) values ($typeDescription, $reportDate) /;
 | 
        
           |  |  | 445 |       &GenericSQL::doSQL( $dbh, $sql_insert );
 | 
        
           |  |  | 446 |       $id = &GenericSQL::getOneValue( $dbh, $sql );
 | 
        
           |  |  | 447 |    }
 | 
        
           |  |  | 448 |    return $id;
 | 
        
           |  |  | 449 | }
 | 
        
           |  |  | 450 |   | 
        
           |  |  | 451 | # gets the computer ID. If the computerID does not exist, creates it.
 | 
        
           |  |  | 452 | # returns the id of the computer.
 | 
        
           |  |  | 453 | sub getComputerID {
 | 
        
           |  |  | 454 |    # ok, does this computer name exist (each computer name per site must be unique)
 | 
        
           |  |  | 455 |    $computer = &fixDatabaseValue($computerName);
 | 
        
           |  |  | 456 |    my $sql = qq/
 | 
        
           |  |  | 457 |       select device_id
 | 
        
           |  |  | 458 |       from device join site using (site_id)
 | 
        
           |  |  | 459 |       where site.client_id = $clientID
 | 
        
           |  |  | 460 |             and device.name = $computer
 | 
        
           |  |  | 461 |             and device.removed_date is null
 | 
        
           |  |  | 462 |          /;
 | 
        
           |  |  | 463 |    my $computer_id = &GenericSQL::getOneValue( $dbh, $sql ); # actually, result of query above
 | 
        
           |  |  | 464 |    unless ( $computer_id ) { # didn't find it. Let's see if it is in the alias table
 | 
        
           |  |  | 465 |       $sql = qq/select device_id from device_alias join device using (device_id) join site using (site_id) where device_alias.alias = $computer and site.client_id = $clientID/;
 | 
        
           |  |  | 466 |       $computer_id = &GenericSQL::getOneValue( $dbh, $sql );
 | 
        
           |  |  | 467 |    }
 | 
        
           |  |  | 468 |    # changed to just give a warning
 | 
        
           |  |  | 469 |    unless ( $computer_id ) { # nope, computer does not exist so create it
 | 
        
           |  |  | 470 |       $client = &fixDatabaseValue($clientName);
 | 
        
           |  |  | 471 |       $sql = qq/select report_date from unknown_entry where client_name = $client and device_name = $computer and processed_date is null/;
 | 
        
           |  |  | 472 |       #$report = &GenericSQL::getOneValue( $dbh, $sql );
 | 
        
           |  |  | 473 |       #print STDERR "Report Date $report\n";
 | 
        
           |  |  | 474 |       if ($report = &GenericSQL::getOneValue( $dbh, $sql )) {
 | 
        
           |  |  | 475 |          $FATAL = "New Device detected, but entry already made. You must update Camp before this can be processed";
 | 
        
           |  |  | 476 |       } else {
 | 
        
           |  |  | 477 |          $sql = qq/insert into unknown_entry(client_name,device_name,report_date) values ($client, $computer, $reportDate)/;
 | 
        
           |  |  | 478 |          &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 479 |          $FATAL = "Warning, new device $computer found associated with client $client. You must update Camp before this report can be processed\n";
 | 
        
           |  |  | 480 |       }
 | 
        
           |  |  | 481 |    }
 | 
        
           |  |  | 482 |    return $computer_id;
 | 
        
           |  |  | 483 | }
 | 
        
           |  |  | 484 |   | 
        
           |  |  | 485 | # checks for a duplicate report, ie one that has already been run.
 | 
        
           |  |  | 486 | # the only thing that always changes is disk space usage, so just look to see
 | 
        
           |  |  | 487 | # if this computer has a report already for this date/time
 | 
        
           |  |  | 488 | sub recordReport {
 | 
        
           |  |  | 489 |    my $sql = qq/select count(*) from sysinfo_report where device_id = $computerID and report_date = $reportDate/;
 | 
        
           |  |  | 490 |    if (&GenericSQL::getOneValue( $dbh, $sql ) > 0) {
 | 
        
           |  |  | 491 |       my $thisDevice = &GenericSQL::getOneValue( $dbh, "select name from device where device_id = $computerID" );
 | 
        
           |  |  | 492 |       $FATAL = qq/Duplicate Report for $thisDevice (id $computerID) on $reportDate/;
 | 
        
           |  |  | 493 |       return;
 | 
        
           |  |  | 494 |    }
 | 
        
           |  |  | 495 |    $version = &fixDatabaseValue($datafileVersion);
 | 
        
           |  |  | 496 |    # if we made it this far, we are ok, so just add the report id
 | 
        
           |  |  | 497 |    $sql = qq/insert into sysinfo_report(device_id,version,report_date,added_date) values ($computerID,$version,$reportDate,now())/;
 | 
        
           |  |  | 498 |    &GenericSQL::doSQL($dbh,$sql);
 | 
        
           |  |  | 499 |    $sql = qq/select sysinfo_report_id from sysinfo_report where device_id = $computerID and report_date = $reportDate/;
 | 
        
           |  |  | 500 |    return &GenericSQL::getOneValue( $dbh, $sql );
 | 
        
           |  |  | 501 | }
 | 
        
           |  |  | 502 |   | 
        
           |  |  | 503 | # gets operating system ID. If it does not exist, creates it
 | 
        
           |  |  | 504 | sub getOSID {
 | 
        
           |  |  | 505 |    my ($osHash) = shift;
 | 
        
           |  |  | 506 |    my $os_id;
 | 
        
           |  |  | 507 |    my $osName = &fixDatabaseValue($$osHash{'os_name'});
 | 
        
           |  |  | 508 |    my $kernel = &fixDatabaseValue($$osHash{'kernel'});
 | 
        
           |  |  | 509 |    my $distro_name = &fixDatabaseValue($$osHash{'distribution'});
 | 
        
           |  |  | 510 |    my $release = &fixDatabaseValue($$osHash{'release'});
 | 
        
           |  |  | 511 |    my $version = &fixDatabaseValue($$osHash{'os_version'});
 | 
        
           |  |  | 512 |    my $description = &fixDatabaseValue($$osHash{'description'});
 | 
        
           |  |  | 513 |    my $codename = &fixDatabaseValue($$osHash{'codename'});
 | 
        
           |  |  | 514 |   | 
        
           |  |  | 515 |    $sql = qq/select operating_system_id from operating_system
 | 
        
           |  |  | 516 |             where name = $osName
 | 
        
           |  |  | 517 |                and kernel = $kernel
 | 
        
           |  |  | 518 |                and distro = $distro_name
 | 
        
           |  |  | 519 |                and distro_release = $release /;
 | 
        
           |  |  | 520 |    unless ( $os_id = &GenericSQL::getOneValue( $dbh, $sql ) ) {
 | 
        
           |  |  | 521 |       $sql = qq/insert into operating_system (name,version,kernel,distro,distro_description,distro_release,distro_codename, added_date) values
 | 
        
           |  |  | 522 |                ($osName,$version,$kernel,$distro_name,$description,$release,$codename, $reportDate)/;
 | 
        
           |  |  | 523 |       &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 524 |       $sql = qq/select operating_system_id from operating_system
 | 
        
           |  |  | 525 |             where name = $osName
 | 
        
           |  |  | 526 |                and kernel = $kernel
 | 
        
           |  |  | 527 |                and distro = $distro_name
 | 
        
           |  |  | 528 |                and distro_release = $release /;
 | 
        
           |  |  | 529 |       $os_id = &GenericSQL::getOneValue( $dbh, $sql );
 | 
        
           |  |  | 530 |    }
 | 
        
           |  |  | 531 |    return $os_id;
 | 
        
           |  |  | 532 | }
 | 
        
           |  |  | 533 |   | 
        
           |  |  | 534 |   | 
        
           |  |  | 535 | # simply verifies some attributes of the computer
 | 
        
           |  |  | 536 | sub updateComputerMakeup {
 | 
        
           |  |  | 537 |    my ($systemHash) = @_;
 | 
        
           |  |  | 538 |    #print "[$$systemHash{'memory'}]\n";
 | 
        
           |  |  | 539 |    &checkAndUpdateAttribute($computerID,'Memory',$$systemHash{'memory'});
 | 
        
           |  |  | 540 |    #print "[$$systemHash{'num_cpu'}]\n";
 | 
        
           |  |  | 541 |    &checkAndUpdateAttribute($computerID,'Number of CPUs',$$systemHash{'num_cpu'});
 | 
        
           |  |  | 542 |    #die;
 | 
        
           |  |  | 543 |    &checkAndUpdateAttribute($computerID,'CPU Type',$$systemHash{'cpu_type'});
 | 
        
           |  |  | 544 |    &checkAndUpdateAttribute($computerID,'CPU SubType',$$systemHash{'cpu_sub'});
 | 
        
           |  |  | 545 |    &checkAndUpdateAttribute($computerID,'CPU Speed',$$systemHash{'cpu_speed'});
 | 
        
           |  |  | 546 | }
 | 
        
           |  |  | 547 |   | 
        
           |  |  | 548 | sub updateOS {
 | 
        
           |  |  | 549 |    my ($osHash) = @_;
 | 
        
           |  |  | 550 |    # verify the operating system
 | 
        
           |  |  | 551 |    my $os_id = &getOSID($osHash, $reportDate);
 | 
        
           |  |  | 552 |    $sql = qq/select operating_system_id from device_operating_system where device_id = $computerID and removed_date is null/;
 | 
        
           |  |  | 553 |    $registeredOS = &GenericSQL::getOneValue( $dbh, $sql );
 | 
        
           |  |  | 554 |    unless ($registeredOS && $registeredOS eq $os_id ) {
 | 
        
           |  |  | 555 |       if ( $registeredOS ) { #we have the same computer, but a new OS???
 | 
        
           |  |  | 556 |          $sql = qq/update device_operating_system set removed_date = $reportDate where device_id = $computerID and removed_date is null/;
 | 
        
           |  |  | 557 |          &GenericSQL::doSQL( $dbh, $sql);
 | 
        
           |  |  | 558 |          push @warnings, &createLogMessage("Computer $computerName has a new OS" );
 | 
        
           |  |  | 559 |          $os_id = &getOSID($osHash, $reportDate);
 | 
        
           |  |  | 560 |       }
 | 
        
           |  |  | 561 |       $sql = qq/insert into device_operating_system( device_id,operating_system_id,added_date) values ($computerID,$os_id,$reportDate)/;
 | 
        
           |  |  | 562 |       &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 563 |    }
 | 
        
           |  |  | 564 | }
 | 
        
           |  |  | 565 |   | 
        
           |  |  | 566 | sub dateToMySQL {
 | 
        
           |  |  | 567 |    my $date = shift;
 | 
        
           |  |  | 568 |    # print "Date In $date\n";
 | 
        
           |  |  | 569 |    $date =~ s/'//g; # some of the older reports put quotes around this
 | 
        
           |  |  | 570 |    return &fixDatabaseValue($date) if $date =~ m/\d{4}[-\/]\d{2}[-\/]\d{2} \d{2}:\d{2}/;  # this is already in the correct format
 | 
        
           |  |  | 571 |   | 
        
           |  |  | 572 |    my ($ss,$mm,$hh,$day,$month,$year,$zone);
 | 
        
           |  |  | 573 |    unless  ( $date =~ m/^\d+$/ ) { # If it is not a unix time stamp
 | 
        
           |  |  | 574 |       $date = str2time($date); # try to parse it
 | 
        
           |  |  | 575 |    }
 | 
        
           |  |  | 576 |    return '' unless defined $date && $date; # bail if date is not defined or zero
 | 
        
           |  |  | 577 |    # standard processing of a date
 | 
        
           |  |  | 578 |    ($ss,$mm,$hh,$day,$month,$year,$zone) = localtime($date);
 | 
        
           |  |  | 579 |    $year += 1900;
 | 
        
           |  |  | 580 |    ++$month;
 | 
        
           |  |  | 581 |    # printf( "Answer Is: %4d-%02d-%02d %02d:%02d\n", $year,$month,$day,$hh,$mm);
 | 
        
           |  |  | 582 |    return &fixDatabaseValue(sprintf( '%4d-%02d-%02d %02d:%02d', $year,$month,$day,$hh,$mm));
 | 
        
           |  |  | 583 | }
 | 
        
           |  |  | 584 |   | 
        
           |  |  | 585 | # every time we get a report, we need to see if the computer was rebooted
 | 
        
           |  |  | 586 | # if last reboot date is not the same as what our report shows, we will
 | 
        
           |  |  | 587 | # remove the existing entry, then add a new one
 | 
        
           |  |  | 588 | sub updateBootTime {
 | 
        
           |  |  | 589 |    my ($systemHash) = @_;
 | 
        
           |  |  | 590 |    my $lastReboot;
 | 
        
           |  |  | 591 |    if ($$systemHash{'last_boot'}) {
 | 
        
           |  |  | 592 |       #print "Checking Boot Time\n";
 | 
        
           |  |  | 593 |       if ($lastReboot = &dateToMySQL($$systemHash{'last_boot'})) {
 | 
        
           |  |  | 594 |          my $sql = qq/select computer_uptime_id from computer_uptime where device_id = $computerID and last_reboot = $lastReboot/;
 | 
        
           |  |  | 595 |          unless ( &GenericSQL::getOneValue( $dbh, $sql ) ) {
 | 
        
           |  |  | 596 |             push @warnings, &createLogMessage("Computer was rebooted at $lastReboot");
 | 
        
           |  |  | 597 |             my $sql_insert = qq/update computer_uptime set removed_date = $reportDate where device_id = $computerID and removed_date is null/;
 | 
        
           |  |  | 598 |             &GenericSQL::doSQL( $dbh, $sql_insert );
 | 
        
           |  |  | 599 |             $sql_insert = qq/insert into computer_uptime (device_id,added_date,last_reboot) values ($computerID,$reportDate,$lastReboot)/;
 | 
        
           |  |  | 600 |             &GenericSQL::doSQL( $dbh, $sql_insert );
 | 
        
           |  |  | 601 |          }
 | 
        
           |  |  | 602 |       } else {
 | 
        
           |  |  | 603 |          push @warnings, &createLogMessage('Invalid reboot time [' . $$systemHash{'last_boot'} . ']');
 | 
        
           |  |  | 604 |       }
 | 
        
           |  |  | 605 |    } else {
 | 
        
           |  |  | 606 |       push @warnings, &createLogMessage('No Boot time given');
 | 
        
           |  |  | 607 |    }
 | 
        
           |  |  | 608 | }
 | 
        
           |  |  | 609 |   | 
        
           |  |  | 610 | # routine will check for all IP addresses reported and check against those recorded in the
 | 
        
           |  |  | 611 | # database. It will remove any no longer in the database, and add any new ones
 | 
        
           |  |  | 612 | sub doIPAddresses {
 | 
        
           |  |  | 613 |    my ( $networkHash ) = @_;
 | 
        
           |  |  | 614 |    # delete $$networkHash{'lo'}; # we don't process lo
 | 
        
           |  |  | 615 |    # first, remove any interfaces that no longer exist
 | 
        
           |  |  | 616 |    my $interfaces = join ',', (map { &fixDatabaseValue($_) } keys %$networkHash); # get a list of interfaces being passed in
 | 
        
           |  |  | 617 |    if ( $interfaces ) {
 | 
        
           |  |  | 618 |       my $sql = qq/update network set removed_date = $reportDate where device_id = $computerID and removed_date is null and interface not in ($interfaces)/;
 | 
        
           |  |  | 619 |       &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 620 |    }
 | 
        
           |  |  | 621 |    # let's get all remaining network information
 | 
        
           |  |  | 622 |    $sql = qq/select network_id,interface,address,netmask,ip6,ip6net,mac,mtu from network where device_id = $computerID and removed_date is null/;
 | 
        
           |  |  | 623 |    my $sth = &GenericSQL::startQuery( $dbh, $sql );
 | 
        
           |  |  | 624 |    while (my $thisRow = &GenericSQL::getNextRow($sth)) {
 | 
        
           |  |  | 625 |       if ( defined $$thisRow{'interface'} ) { # pre 2.0 versions did not have an interface object
 | 
        
           |  |  | 626 |          # long drawn out thing to check if they are the same
 | 
        
           |  |  | 627 |          if ( &checkEquals($$networkHash{$$thisRow{'interface'}}{'address'}, $$thisRow{'address'}) && 
 | 
        
           |  |  | 628 |               &checkEquals($$networkHash{$$thisRow{'interface'}}{'ip6address'}, $$thisRow{'ip6'}) &&
 | 
        
           |  |  | 629 |               &checkEquals($$networkHash{$$thisRow{'interface'}}{'ip6networkbits'}, $$thisRow{'ip6net'}) &&  
 | 
        
           |  |  | 630 |               &checkEquals($$networkHash{$$thisRow{'interface'}}{'mac'}, $$thisRow{'mac'}) &&
 | 
        
           |  |  | 631 |               &checkEquals($$networkHash{$$thisRow{'interface'}}{'mtu'}, $$thisRow{'mtu'}) && 
 | 
        
           |  |  | 632 |               &checkEquals($$networkHash{$$thisRow{'interface'}}{'netmask'}, $$thisRow{'netmask'}) ) {
 | 
        
           |  |  | 633 |             # they are the same, so just mark it off the list
 | 
        
           |  |  | 634 |             delete $$networkHash{$$thisRow{'interface'}};
 | 
        
           |  |  | 635 |          } else { # it has changed, so invalidate the current line in the database
 | 
        
           |  |  | 636 |             $sql = qq/update network set removed_date = $reportDate where network_id = $$thisRow{'network_id'}/;
 | 
        
           |  |  | 637 |             &GenericSQL::doSQL( $dbh, $sql ); 
 | 
        
           |  |  | 638 |          }
 | 
        
           |  |  | 639 |       } else { # the database is still using pre 2.0 values, so we must see if we need to upgrade this
 | 
        
           |  |  | 640 |          if ($datafileVersion =~ m/^2/) { # version 2.x, so we will need to update this record
 | 
        
           |  |  | 641 |             # in this case, we are going to just "remove" all current entries and reload them below.
 | 
        
           |  |  | 642 |             # this code will only be run once for each machine that needs to conver to the new format
 | 
        
           |  |  | 643 |             $sql = qq/update network set removed_date = $reportDate where removed_date is null and device_id = $computerID/;
 | 
        
           |  |  | 644 |             last;
 | 
        
           |  |  | 645 |          }
 | 
        
           |  |  | 646 |       }
 | 
        
           |  |  | 647 |    }
 | 
        
           |  |  | 648 |    # at this point, the only items left are either new or have changed, so just insert them.
 | 
        
           |  |  | 649 |    foreach my $device ( keys %$networkHash ) {
 | 
        
           |  |  | 650 |       $sql = qq/insert into network (device_id,added_date,interface,address,netmask,ip6,ip6net,mtu,mac) values /;
 | 
        
           |  |  | 651 |       $sql .= '( ' . join(',',
 | 
        
           |  |  | 652 |                            $computerID,
 | 
        
           |  |  | 653 |                            $reportDate,
 | 
        
           |  |  | 654 |                            &fixDatabaseValue($device),
 | 
        
           |  |  | 655 |                            &fixDatabaseValue($$networkHash{$device}{'address'}),
 | 
        
           |  |  | 656 |                            &fixDatabaseValue($$networkHash{$device}{'netmask'}),
 | 
        
           |  |  | 657 |                            &fixDatabaseValue($$networkHash{$device}{'ip6address'}),
 | 
        
           |  |  | 658 |                            &fixDatabaseValue($$networkHash{$device}{'ip6networkbits'}),
 | 
        
           |  |  | 659 |                            &fixDatabaseValue($$networkHash{$device}{'mtu'}),
 | 
        
           |  |  | 660 |                            &fixDatabaseValue($$networkHash{$device}{'mac'})
 | 
        
           |  |  | 661 |                            ) .
 | 
        
           |  |  | 662 |               ')';
 | 
        
           |  |  | 663 |       &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 664 |       push @warnings,&createLogMessage("Network Device $device was added/modified");
 | 
        
           |  |  | 665 |    }
 | 
        
           |  |  | 666 | } # sub doIPAddresses
 | 
        
           |  |  | 667 |   | 
        
           |  |  | 668 |   | 
        
           |  |  | 669 | sub processDisks {
 | 
        
           |  |  | 670 |    my ($diskHash) = @_;
 | 
        
           |  |  | 671 |    #print Data::Dumper->Dump([$diskHash],['$diskHash']);
 | 
        
           |  |  | 672 |    #print "Upon entry, we have " . (scalar keys %$diskHash) . " Items in hash\n";
 | 
        
           |  |  | 673 |    # first, see if there are any alerts
 | 
        
           |  |  | 674 |    foreach my $partition (keys %$diskHash) {
 | 
        
           |  |  | 675 |       if ($$diskHash{$partition}{'size'}) {
 | 
        
           |  |  | 676 |          my $usedPercent = sprintf('%4.2f', ($$diskHash{$partition}{'used'}/$$diskHash{$partition}{'size'}) * 100);
 | 
        
           |  |  | 677 |          push @warnings, &createLogMessage("Partition $partition at $usedPercent%% capacity") if $usedPercent > $DiskUsageAlert;
 | 
        
           |  |  | 678 |       }
 | 
        
           |  |  | 679 |    }
 | 
        
           |  |  | 680 |    # now, remove any that are no longer reported
 | 
        
           |  |  | 681 |    my $temp = join ',', (map { &fixDatabaseValue($_) } keys %$diskHash); # get a list of interfaces being passed in
 | 
        
           |  |  | 682 |    my $sql = qq/select disk_info_id from disk_info where removed_date is null and device_id = $computerID and disk_device not in ($temp)/;
 | 
        
           |  |  | 683 |    #print "\n$sql\n";
 | 
        
           |  |  | 684 | #   die;
 | 
        
           |  |  | 685 |    my @idsToDelete = &GenericSQL::getArrayOfValues( $dbh, $sql );
 | 
        
           |  |  | 686 | #   print '[' . join ('][', @idsToDelete) . "]\n";
 | 
        
           |  |  | 687 |    foreach my $id ( @idsToDelete ) {
 | 
        
           |  |  | 688 |       next unless $id;
 | 
        
           |  |  | 689 |       push @warnings,&createLogMessage("Disk Partition removed");
 | 
        
           |  |  | 690 |       $sql = qq/update disk_info set removed_date = $reportDate where removed_date is null and disk_info_id = $id/;
 | 
        
           |  |  | 691 |       &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 692 |       $sql = qq/update disk_space set removed_date = $reportDate where removed_date is null and disk_info_id = $id/;
 | 
        
           |  |  | 693 |       &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 694 |    }
 | 
        
           |  |  | 695 |    # now, we have a "clean" database
 | 
        
           |  |  | 696 |    # do a query to retrieve all disk entries for this device
 | 
        
           |  |  | 697 |   $sql = qq/select disk_info.disk_info_id,disk_space_id,disk_device,filesystem,mount_point,capacity 
 | 
        
           |  |  | 698 |             from disk_info join disk_space using (disk_info_id) 
 | 
        
           |  |  | 699 |             where disk_space.removed_date is null and disk_info.removed_date is null and device_id = $computerID/;
 | 
        
           |  |  | 700 |    my $sth = &GenericSQL::startQuery( $dbh, $sql );
 | 
        
           |  |  | 701 |    #print "Before we start processing, we have " . (scalar keys %$diskHash) . " Items in hash\n";
 | 
        
           |  |  | 702 |    while (my $thisDBRow = &GenericSQL::getNextRow($sth)) {
 | 
        
           |  |  | 703 |       my $thisHashRow = $$diskHash{$$thisDBRow{'disk_device'}} ; # just for convenience 
 | 
        
           |  |  | 704 |       # Always invalidate the disk space entry. We'll either add a new row, or it is changed too much
 | 
        
           |  |  | 705 |       $sql = "update disk_space set removed_date = $reportDate where removed_date is null and disk_info_id = " . $$thisDBRow{'disk_info_id'};
 | 
        
           |  |  | 706 |       &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 707 |       # we know this exists in both
 | 
        
           |  |  | 708 |       #print "\n\n" . $$thisDBRow{'disk_device'} . "\n";
 | 
        
           |  |  | 709 |       #print Data::Dumper->Dump([$thisDBRow],['thisRow']);
 | 
        
           |  |  | 710 |       #print Data::Dumper->Dump([$thisHashRow],['thisHashRow']);
 | 
        
           |  |  | 711 |       #print $$thisHashRow{'fstype'} . "\n";
 | 
        
           |  |  | 712 |       #print $$thisHashRow{'size'} . "\n";
 | 
        
           |  |  | 713 |       #print $$thisHashRow{'mount'} . "\n";
 | 
        
           |  |  | 714 |   | 
        
           |  |  | 715 |       # is it a partition, or a directory to watch. This is defined as a directory to watch does not contain a size,
 | 
        
           |  |  | 716 |       # mount point or file system type.
 | 
        
           |  |  | 717 |       my $diskPartition = (exists ($$thisHashRow{'fstype'}) && exists ($$thisHashRow{'size'}) && exists ($$thisHashRow{'mount'}) );
 | 
        
           |  |  | 718 |       # now, determine if we need to update the disk_info for some reason
 | 
        
           |  |  | 719 |       # this condition is based upon two types of entries
 | 
        
           |  |  | 720 |       # Type #1 (top) is a standard partition, so we see if fstype, mount and capacity are the same
 | 
        
           |  |  | 721 |       # type #2 (after ||) us a "directory to watch" (with no fstype, size or mount)
 | 
        
           |  |  | 722 |       if ( $diskPartition ) { # it is a partition, so check if something has changed in the entry
 | 
        
           |  |  | 723 |          #print "\n\nDevice: [" . $$thisDBRow{'disk_device'} . "] is a partition\n";
 | 
        
           |  |  | 724 |          #print "thisHashRow fstype [" . $$thisHashRow{'fstype'} . "]\n";
 | 
        
           |  |  | 725 |          #print "thisHashRow size  [" . $$thisHashRow{'size'} . "]\n";
 | 
        
           |  |  | 726 |          #print "thisHashRow mount  [" . $$thisHashRow{'mount'} . "]\n";
 | 
        
           |  |  | 727 |          #print "thisRow filesystem [" . 
 | 
        
           |  |  | 728 |          unless ( &checkEquals($$thisHashRow{'fstype'}, $$thisDBRow{'filesystem'}) and
 | 
        
           |  |  | 729 |                   &checkEquals($$thisHashRow{'mount'}, $$thisDBRow{'mount_point'}) and
 | 
        
           |  |  | 730 |                   &checkEquals($$thisHashRow{'size'}, $$thisDBRow{'capacity'}) ) {
 | 
        
           |  |  | 731 |             # yes, a change. If we just remove this entry, the add loop (below) will set it as a new device
 | 
        
           |  |  | 732 |             $sql = "update disk_info set removed_date = $reportDate where disk_info_id = " . $$thisDBRow{'disk_info_id'};
 | 
        
           |  |  | 733 |             &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 734 |             #print "$sql\n";
 | 
        
           |  |  | 735 |             next;
 | 
        
           |  |  | 736 |          }
 | 
        
           |  |  | 737 |       }
 | 
        
           |  |  | 738 |       $usedSpace = $$diskHash{$$thisDBRow{'disk_device'}}{'used'};
 | 
        
           |  |  | 739 |       #print "\tupdating entry, looking at disk has => $$thisDBRow{'disk_device'} with space $usedSpace\n";
 | 
        
           |  |  | 740 |       $sql = "insert into disk_space (disk_info_id,space_used,added_date) values ";
 | 
        
           |  |  | 741 |       $sql .= '(' . join (',', ($$thisDBRow{'disk_info_id'}, &fixDatabaseValue($usedSpace), $reportDate)) . ')';
 | 
        
           |  |  | 742 |       &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 743 |       # and delete the hash entry so we don't process it as a change
 | 
        
           |  |  | 744 |       delete $$diskHash{$$thisDBRow{'disk_device'}};
 | 
        
           |  |  | 745 |    }
 | 
        
           |  |  | 746 |    # at this point, all we have left are additions and changes
 | 
        
           |  |  | 747 |    foreach my $partition ( keys %$diskHash ) {
 | 
        
           |  |  | 748 |       $sql = 'insert into disk_info(device_id,added_date,disk_device,filesystem,mount_point,capacity) values ';
 | 
        
           |  |  | 749 |       $sql .= '(' . join( ',', ( $computerID,
 | 
        
           |  |  | 750 |                                  $reportDate, 
 | 
        
           |  |  | 751 |                                  &fixDatabaseValue($partition), 
 | 
        
           |  |  | 752 |                                  &fixDatabaseValue($$diskHash{$partition}{'fstype'}),
 | 
        
           |  |  | 753 |                                  &fixDatabaseValue($$diskHash{$partition}{'mount'}),
 | 
        
           |  |  | 754 |                                  &fixDatabaseValue($$diskHash{$partition}{'size'})
 | 
        
           |  |  | 755 |                                )
 | 
        
           |  |  | 756 |                         ) . ')';
 | 
        
           |  |  | 757 |       &GenericSQL::doSQL($dbh, $sql);
 | 
        
           |  |  | 758 |       $sql = "select disk_info_id from disk_info where removed_date is null and device_id = $computerID and disk_device = " . &fixDatabaseValue($partition);
 | 
        
           |  |  | 759 |       $temp = &GenericSQL::getOneValue( $dbh, $sql );
 | 
        
           |  |  | 760 |       $sql = 'insert into disk_space(disk_info_id,added_date,space_used) values (';
 | 
        
           |  |  | 761 |       $sql .= join( ',', ($temp, $reportDate, fixDatabaseValue($$diskHash{$partition}{'used'}))) . ')';
 | 
        
           |  |  | 762 |       &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 763 |    }
 | 
        
           |  |  | 764 | }
 | 
        
           |  |  | 765 |   | 
        
           |  |  | 766 | # routine to ensure the hardware returned as PCI hardware is in the attributes area
 | 
        
           |  |  | 767 | sub processPCI {
 | 
        
           |  |  | 768 |    my  ($pciHash) = @_;
 | 
        
           |  |  | 769 |    # print "Entering processPCI\n";
 | 
        
           |  |  | 770 |    #print Data::Dumper->Dump([$pciHash],[$key]);
 | 
        
           |  |  | 771 |    return unless $pciHash && keys %$pciHash;
 | 
        
           |  |  | 772 |   | 
        
           |  |  | 773 |    #my %attributeMappings = ('class' => 'Class', # v2 database has these items, but we want to have a pretty name
 | 
        
           |  |  | 774 |    #                         'device' => 'Device Name',
 | 
        
           |  |  | 775 |    #                         'sdevice' => 'Subsystem Device',
 | 
        
           |  |  | 776 |    #                         'svendor' => 'Subsystem Vendor',
 | 
        
           |  |  | 777 |    #                         'vendor' => 'Vendor',
 | 
        
           |  |  | 778 |    #                         'name'   => 'Name',
 | 
        
           |  |  | 779 |    #                         'slot' => 'Slot'
 | 
        
           |  |  | 780 |    #                        );
 | 
        
           |  |  | 781 |   | 
        
           |  |  | 782 |    # The two keys we'll check for uniquness are device.name and device_type with a key value of 'slot'. If these
 | 
        
           |  |  | 783 |    # are the same, we assume this is the same record
 | 
        
           |  |  | 784 |   | 
        
           |  |  | 785 |    # print Data::Dumper->Dump([$pciHash]);
 | 
        
           |  |  | 786 |   | 
        
           |  |  | 787 |    my $key;
 | 
        
           |  |  | 788 |    # normalize the data
 | 
        
           |  |  | 789 |    foreach $key ( keys %$pciHash ) {
 | 
        
           |  |  | 790 |       unless ( defined ($$pciHash{$key}{'slot'}) ) { # doesn't have a slot field
 | 
        
           |  |  | 791 |          my $slotField = '';
 | 
        
           |  |  | 792 |          my $test = $$pciHash{$key};
 | 
        
           |  |  | 793 |          foreach $subkey ( keys %$test) { # scan through all keys and see if there is something with a "slot looking" value in it
 | 
        
           |  |  | 794 |             $slotField = $key if $$test{$subkey} =~ m/^[0-9a-f:.]+$/;
 | 
        
           |  |  | 795 |          }
 | 
        
           |  |  | 796 |          if ( $slotField ) {
 | 
        
           |  |  | 797 |             $$pciHash{$key}{$subkey}{'slot'} = $$pciHash{$key}{$subkey}{$slotField};
 | 
        
           |  |  | 798 |          } else {
 | 
        
           |  |  | 799 |             $$pciHash{$key}{'slot'} = 'Unknown';
 | 
        
           |  |  | 800 |          }
 | 
        
           |  |  | 801 |       }
 | 
        
           |  |  | 802 |       # Each entry must have a name. Use 'device' if it doesn't exist
 | 
        
           |  |  | 803 |       $$pciHash{$key}{'name'} = $$pciHash{$key}{'device'} unless defined($$pciHash{$key}{'name'}) && $$pciHash{$key}{'name'};
 | 
        
           |  |  | 804 |       $$pciHash{$key}{'name'} = $$pciHash{$key}{'sdevice'} unless defined($$pciHash{$key}{'name'}) && $$pciHash{$key}{'name'};
 | 
        
           |  |  | 805 |       $$pciHash{$key}{'name'} =~ s/^ +//; 
 | 
        
           |  |  | 806 |       unless ( $$pciHash{$key}{'name'} ) {
 | 
        
           |  |  | 807 |          push @warnings, &createLogMessage("No name given for one or more PCI devices at normalize, Computer ID: [$computerID], Report Date: [$reportDate]");
 | 
        
           |  |  | 808 |          return;
 | 
        
           |  |  | 809 |       }
 | 
        
           |  |  | 810 |       # Following is what will actually be put in the device table, ie device.name
 | 
        
           |  |  | 811 |       $$pciHash{$key}{'keyFieldValue'} = $$pciHash{$key}{'slot'} . ' - ' . $$pciHash{$key}{'name'};
 | 
        
           |  |  | 812 |    }
 | 
        
           |  |  | 813 |    # at this point, we should have a slot and a name field in all pci devices
 | 
        
           |  |  | 814 |   | 
        
           |  |  | 815 |    # print Data::Dumper->Dump([$pciHash]);
 | 
        
           |  |  | 816 |    # die;
 | 
        
           |  |  | 817 |    # Get list of all PCI cards in database for this computer
 | 
        
           |  |  | 818 |    my @toDelete;
 | 
        
           |  |  | 819 |    $sql = qq/select device_id,
 | 
        
           |  |  | 820 |                      device.name name
 | 
        
           |  |  | 821 |                from device join device_type using (device_type_id) 
 | 
        
           |  |  | 822 |                where device_type.name = 'PCI Card' 
 | 
        
           |  |  | 823 |                      and device.removed_date is null
 | 
        
           |  |  | 824 |                      and device.part_of = $computerID/;
 | 
        
           |  |  | 825 |    my $sth = &GenericSQL::startQuery( $dbh, $sql );
 | 
        
           |  |  | 826 |    while (my $thisRow = &GenericSQL::getNextRow($sth)) { # for each row in the database
 | 
        
           |  |  | 827 |       my $deleteMe = $$thisRow{'device_id'}; # assume we will delete it
 | 
        
           |  |  | 828 |       foreach $key (keys %$pciHash ) { # look for it in the hash
 | 
        
           |  |  | 829 |          #print "Checking [$$pciHash{$key}{'name'}] eq [$$thisRow{'name'}]\n";
 | 
        
           |  |  | 830 |          #print "         [$$pciHash{$key}{'slot'}] eq [$$thisRow{'slot'}]\n\n";
 | 
        
           |  |  | 831 |          if (
 | 
        
           |  |  | 832 |                ($$pciHash{$key}{'keyFieldValue'} eq $$thisRow{'name'})
 | 
        
           |  |  | 833 |                &&
 | 
        
           |  |  | 834 |                ! defined ($$pciHash{$key}{'device_id'})               # this keeps us from ignoring a card when two are installed
 | 
        
           |  |  | 835 |             ) { # it is in the database and in pciHash
 | 
        
           |  |  | 836 |             $deleteMe = ''; # so let's keep it
 | 
        
           |  |  | 837 |             $$pciHash{$key}{'device_id'} = $$thisRow{'device_id'}; # and mark it as there
 | 
        
           |  |  | 838 |             #print "\tfound equality at $$thisRow{'device_id'}\n";
 | 
        
           |  |  | 839 |             last; # and exit the foreach loop
 | 
        
           |  |  | 840 |          }
 | 
        
           |  |  | 841 |       }
 | 
        
           |  |  | 842 |       push @toDelete, $deleteMe if $deleteMe; # if we did not find it, mark for deletion
 | 
        
           |  |  | 843 |    }
 | 
        
           |  |  | 844 |    # remove stale items from the database
 | 
        
           |  |  | 845 |    if (@toDelete) {
 | 
        
           |  |  | 846 |       my $toDelete = join ",", @toDelete; # this is a list of device_id's
 | 
        
           |  |  | 847 |       push @warnings, &createLogMessage( scalar(@toDelete) . " PCI Devices removed");
 | 
        
           |  |  | 848 |       # remove from the device_attrib table
 | 
        
           |  |  | 849 |       $sql = qq/update device_attrib set removed_date = $reportDate where device_id in ($toDelete)/;
 | 
        
           |  |  | 850 |       # print "$sql\n";
 | 
        
           |  |  | 851 |       &GenericSQL::doSQL($dbh, $sql);
 | 
        
           |  |  | 852 |       # and from the device table itself
 | 
        
           |  |  | 853 |       $sql = qq/update device set removed_date = $reportDate where device_id in ($toDelete)/;
 | 
        
           |  |  | 854 |       &GenericSQL::doSQL($dbh, $sql);
 | 
        
           |  |  | 855 |    }
 | 
        
           |  |  | 856 |    undef @toDelete; # don't need this anymore
 | 
        
           |  |  | 857 |   | 
        
           |  |  | 858 |    my $added = 0;
 | 
        
           |  |  | 859 |    my $updated = 0;
 | 
        
           |  |  | 860 |    # now, we have either inserts or updates
 | 
        
           |  |  | 861 |    foreach $key (keys %$pciHash) {
 | 
        
           |  |  | 862 |       unless ( $$pciHash{$key}{'device_id'} ) { # we did not find it in the database, so it is an insert
 | 
        
           |  |  | 863 |          my $thisKey = &fixDatabaseValue($$pciHash{$key}{'keyFieldValue'});
 | 
        
           |  |  | 864 |          $sql = qq/insert into device (site_id,device_type_id,name,part_of,added_date) 
 | 
        
           |  |  | 865 |                    select site_id,device_type.device_type_id, $thisKey, device_id, $reportDate
 | 
        
           |  |  | 866 |                    from device,device_type 
 | 
        
           |  |  | 867 |                    where device.device_id = $computerID 
 | 
        
           |  |  | 868 |                          and device_type.name = 'PCI Card'/;
 | 
        
           |  |  | 869 |          &GenericSQL::doSQL($dbh, $sql);
 | 
        
           |  |  | 870 |          # get the inserted key
 | 
        
           |  |  | 871 |          $$pciHash{$key}{'device_id'} = &GenericSQL::getOneValue($dbh, qq/select max(device_id) from device where part_of = $computerID and name = $thisKey and added_date = $reportDate/);
 | 
        
           |  |  | 872 |          $added++;
 | 
        
           |  |  | 873 |       } # unless
 | 
        
           |  |  | 874 |       my $thisEntry = $$pciHash{$key};
 | 
        
           |  |  | 875 |       $value = 0;
 | 
        
           |  |  | 876 |       foreach my $subkey ( keys %$thisEntry ) {
 | 
        
           |  |  | 877 | #         $test = $attributeMappings{$subkey} ? $attributeMappings{$subkey} : $subkey;
 | 
        
           |  |  | 878 |          # print "checking $subkey [$$thisEntry{$subkey}]\n";
 | 
        
           |  |  | 879 |          $value += &checkAndUpdateAttribute($$pciHash{$key}{'device_id'}, 
 | 
        
           |  |  | 880 |                                             $attributeMappings{$subkey} ? $attributeMappings{$subkey} : $subkey, 
 | 
        
           |  |  | 881 |                                             $$thisEntry{$subkey} ) 
 | 
        
           |  |  | 882 |                                             unless ($subkey eq 'device_id') or ($subkey eq 'keyFieldValue');
 | 
        
           |  |  | 883 |       }
 | 
        
           |  |  | 884 |       $updated++ if $value;
 | 
        
           |  |  | 885 |    }
 | 
        
           |  |  | 886 |    push @warnings, &createLogMessage("$added PCI Devices added") if $added;
 | 
        
           |  |  | 887 |    push @warnings, &createLogMessage("$updated PCI Devices modified") if $updated;
 | 
        
           |  |  | 888 | }
 | 
        
           |  |  | 889 |   | 
        
           |  |  | 890 |   | 
        
           |  |  | 891 | # figure out the software_id and software_version_id of a package. Adds the package/version if
 | 
        
           |  |  | 892 | # it doesn't exist in the database
 | 
        
           |  |  | 893 | sub getSoftwareID {
 | 
        
           |  |  | 894 |    my ( $packageName,$versionInfo,$description ) = @_;
 | 
        
           |  |  | 895 |    #print "In getSoftwareID, paramters are [$packageName][$versionInfo][$description]\n";
 | 
        
           |  |  | 896 |    #return;
 | 
        
           |  |  | 897 |    # escape and quote the values for SQL
 | 
        
           |  |  | 898 |    $packageName = &GenericSQL::fixStringValue($dbh, $packageName );
 | 
        
           |  |  | 899 |    $versionInfo = &GenericSQL::fixStringValue($dbh, $versionInfo );
 | 
        
           |  |  | 900 |    # does the package exist?
 | 
        
           |  |  | 901 |    my $sql = qq/select software_id from software where package_name = $packageName and removed_date is null/;
 | 
        
           |  |  | 902 |    my $result = &GenericSQL::getOneValue( $dbh, $sql );
 | 
        
           |  |  | 903 |    unless ( $result ) { # NO, package doesn't exist, so add it to the database
 | 
        
           |  |  | 904 |       $description = &GenericSQL::fixStringValue($dbh, $description );
 | 
        
           |  |  | 905 |       $sql = qq/insert into software (package_name,description, added_date) values ($packageName,$description, $reportDate)/;
 | 
        
           |  |  | 906 |       &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 907 |       $sql = qq/select software_id from software where package_name = $packageName and removed_date is null/;
 | 
        
           |  |  | 908 |       $result = &GenericSQL::getOneValue( $dbh, $sql );
 | 
        
           |  |  | 909 |    }
 | 
        
           |  |  | 910 |    # does this version number exist?
 | 
        
           |  |  | 911 |    $sql = qq/select software_version_id from software_version where version = $versionInfo and removed_date is null/;
 | 
        
           |  |  | 912 |    my $version = &GenericSQL::getOneValue( $dbh, $sql );
 | 
        
           |  |  | 913 |    unless ( $version ) { # nope, so add it
 | 
        
           |  |  | 914 |       $sql = qq/insert into software_version ( version,added_date ) values ($versionInfo,$reportDate)/;
 | 
        
           |  |  | 915 |       &GenericSQL::doSQL( $dbh, $sql );
 | 
        
           |  |  | 916 |       $sql = qq/select software_version_id from software_version where version = $versionInfo and removed_date is null/;
 | 
        
           |  |  | 917 |       $version = &GenericSQL::getOneValue( $dbh, $sql );
 | 
        
           |  |  | 918 |    }
 | 
        
           |  |  | 919 |    return ($result,$version);
 | 
        
           |  |  | 920 | }
 | 
        
           |  |  | 921 |   | 
        
           |  |  | 922 | # process each package. We will only add entries if a package has changed, either version number
 | 
        
           |  |  | 923 | # added, or deleted. Deleted packages are not handled well right now.
 | 
        
           |  |  | 924 | sub processPackages {
 | 
        
           |  |  | 925 |    my  ($softwareHash) = @_;
 | 
        
           |  |  | 926 |    my %softwareIDs;
 | 
        
           |  |  | 927 |    my $count;
 | 
        
           |  |  | 928 |    # since we go by software and version id's, let's just precalculate them
 | 
        
           |  |  | 929 |    foreach my $package (keys %$softwareHash) {
 | 
        
           |  |  | 930 |       # this will also insert the package and/or version in the software or software_version tables
 | 
        
           |  |  | 931 |       ($$softwareHash{$package}{'softwareid'},$$softwareHash{$package}{'versionid'}) = 
 | 
        
           |  |  | 932 |                          &getSoftwareID( $package, $$softwareHash{$package}{'version'}, $$softwareHash{$package}{'description'}, $reportDate );
 | 
        
           |  |  | 933 |       # this is just a shortcut for when we need to query
 | 
        
           |  |  | 934 |       #$$softwareHash{$package}{'complexkey'} = $$softwareHash{$package}{'softwareid'} . '-' . $$softwareHash{$package}{'versionid'};
 | 
        
           |  |  | 935 |       #push @installedPackages,$$softwareHash{$package}{'softwareid'};
 | 
        
           |  |  | 936 |       $softwareIDs{$$softwareHash{$package}{'softwareid'}} = $$softwareHash{$package}{'versionid'};
 | 
        
           |  |  | 937 |    }
 | 
        
           |  |  | 938 |    # remove any software for this machine that no longer exists
 | 
        
           |  |  | 939 |    my $temp = join( ',', grep { /^\d+$/ } keys %softwareIDs); # make sure we only have numerics
 | 
        
           |  |  | 940 |    my $sql = "update installed_packages set removed_date = $reportDate where device_id = $computerID and removed_date is null and software_id not in ($temp)";
 | 
        
           |  |  | 941 |    &GenericSQL::doSQL( $dbh, $sql);
 | 
        
           |  |  | 942 |    # ok, at this point, all software in the database exists in the computer
 | 
        
           |  |  | 943 |    # now, lets see if there are any modified versions or something
 | 
        
           |  |  | 944 |    $sql = qq/select installed_packages_id,software_id,software_version_id from installed_packages where device_id = $computerID and removed_date is null/;
 | 
        
           |  |  | 945 |    my $sth = &GenericSQL::startQuery( $dbh, $sql );
 | 
        
           |  |  | 946 |    #print "Before we start processing, we have " . (scalar keys %$diskHash) . " Items in hash\n";
 | 
        
           |  |  | 947 |    while (my $thisRow = &GenericSQL::getNextRow($sth)) {
 | 
        
           |  |  | 948 |       # if the version is the same, just do the next one
 | 
        
           |  |  | 949 |       if ( $softwareIDs{$$thisRow{'software_id'}} == $$thisRow{'software_version_id'}) {
 | 
        
           |  |  | 950 |          delete $softwareIDs{$$thisRow{'software_id'}};
 | 
        
           |  |  | 951 |       } else { # we have a change. We simply remove the entry and let the "add new packages" section take care of it
 | 
        
           |  |  | 952 |          $sql = qq/update installed_packages set removed_date = $reportDate where installed_packages_id = $$thisRow{'installed_packages_id'}/;
 | 
        
           |  |  | 953 |          &GenericSQL::doSQL( $dbh, $sql);
 | 
        
           |  |  | 954 |       }
 | 
        
           |  |  | 955 |    }
 | 
        
           |  |  | 956 |    # at this point, the only items left in $softwareIDs are the packages that have changed or been added
 | 
        
           |  |  | 957 |    $count = 0;
 | 
        
           |  |  | 958 |    foreach my $softwareID ( keys %softwareIDs ) {
 | 
        
           |  |  | 959 |       $count++;
 | 
        
           |  |  | 960 |       $sql = qq/insert into installed_packages( device_id,software_id,software_version_id,added_date ) values 
 | 
        
           |  |  | 961 |                 ($computerID,$softwareID,$softwareIDs{$softwareID},$reportDate)/;
 | 
        
           |  |  | 962 |       &GenericSQL::doSQL( $dbh, $sql);
 | 
        
           |  |  | 963 |    }
 | 
        
           |  |  | 964 |    push @warnings, &createLogMessage("$count Software Packages changed or added") if $count;
 | 
        
           |  |  | 965 | }
 | 
        
           |  |  | 966 |   | 
        
           |  |  | 967 | ###############################################################################
 | 
        
           |  |  | 968 | #            BEGIN MAIN ROUTINE
 | 
        
           |  |  | 969 | ###############################################################################
 | 
        
           |  |  | 970 | BEGIN{
 | 
        
           |  |  | 971 |    # load the configuration file
 | 
        
           |  |  | 972 |    eval ( &loadConfigurationFile );
 | 
        
           |  |  | 973 |    push @INC, $LIBRARIES;
 | 
        
           |  |  | 974 | }
 | 
        
           |  |  | 975 |   | 
        
           |  |  | 976 | use strict;
 | 
        
           |  |  | 977 | no strict 'vars';
 | 
        
           |  |  | 978 | use Data::Dumper;
 | 
        
           |  |  | 979 | use GenericSQL; # generic, home grown MySQL access routines
 | 
        
           |  |  | 980 | #use GenericTemplates;
 | 
        
           |  |  | 981 | use Logging; # generic, home grown logging routines
 | 
        
           |  |  | 982 | use Date::Format; # allows us to format our dates nicely
 | 
        
           |  |  | 983 | use Date::Parse; # VERY KEWL, parses out a huge number of date formats
 | 
        
           |  |  | 984 |   | 
        
           |  |  | 985 |   | 
        
           |  |  | 986 | $dbh = DBI->connect( $DSN, $DB_USER , $DB_PASS ) or die $DBI::errstr; # try to connect to db first
 | 
        
           |  |  | 987 |   | 
        
           |  |  | 988 |   | 
        
           |  |  | 989 | # read the input, parse it into useable information
 | 
        
           |  |  | 990 | my $data = &readAndParseInput;
 | 
        
           |  |  | 991 | #print Data::Dumper->Dump([$data]);
 | 
        
           |  |  | 992 | #die; 
 | 
        
           |  |  | 993 | $reportDate = &dateToMySQL($$data{'report'}{'date'});
 | 
        
           |  |  | 994 | $clientName = $$data{'report'}{'client'};
 | 
        
           |  |  | 995 | $FATAL = 'No client name' unless $clientName;
 | 
        
           |  |  | 996 | $computerName = $$data{'system'}{'hostname'} unless $FATAL;
 | 
        
           |  |  | 997 | $FATAL = 'No computer name' unless $computerName;
 | 
        
           |  |  | 998 | # print STDERR "[$computerName]\n";
 | 
        
           |  |  | 999 |   | 
        
           |  |  | 1000 |   | 
        
           |  |  | 1001 | # try to figure out who the client is, creating if necessary
 | 
        
           |  |  | 1002 | $clientID = &getClientID( ) unless $FATAL;
 | 
        
           |  |  | 1003 | # try to figure out the computer ID, creating an entry if necessary
 | 
        
           |  |  | 1004 | $computerID = &getComputerID( ) unless $FATAL;
 | 
        
           |  |  | 1005 | # Ok, we have enough info, now let's make sure we aren't re-runing a report and record the current one.
 | 
        
           |  |  | 1006 | my $reportID = &recordReport( ) unless $FATAL;
 | 
        
           |  |  | 1007 | # we will simply verify memory, cpu, etc...
 | 
        
           |  |  | 1008 | &updateComputerMakeup($$data{'system'}) unless $FATAL;
 | 
        
           |  |  | 1009 | # check if the operating system has changed
 | 
        
           |  |  | 1010 | &updateOS( $$data{'operatingsystem'} ) unless $FATAL;
 | 
        
           |  |  | 1011 | # see if the machine has been rebooted and, if so, record it
 | 
        
           |  |  | 1012 | &updateBootTime ($$data{'system'}) unless $FATAL;
 | 
        
           |  |  | 1013 | # see what IP's this machine has
 | 
        
           |  |  | 1014 | &doIPAddresses($$data{'network'}) unless $FATAL;
 | 
        
           |  |  | 1015 | # Look at the disk usage, and report if they are above limits
 | 
        
           |  |  | 1016 | &processDisks($$data{'diskinfo'}) unless $FATAL;
 | 
        
           |  |  | 1017 | # and also if any hardware has changed
 | 
        
           |  |  | 1018 | &processPCI($$data{'pci'}) unless $FATAL;
 | 
        
           |  |  | 1019 | # see if any software packages have changed
 | 
        
           |  |  | 1020 | &processPackages($$data{'software'}) unless $FATAL;
 | 
        
           |  |  | 1021 | if ($FATAL) { # we had a fatal error, so just return it
 | 
        
           |  |  | 1022 |    print "ERROR: $FATAL\n";
 | 
        
           |  |  | 1023 |    exit 0;
 | 
        
           |  |  | 1024 | }
 | 
        
           |  |  | 1025 | # ok, work is done. If there are any values in $warnings, they should be either printed or e-mailed
 | 
        
           |  |  | 1026 | # to whoever the sysadmin is.
 | 
        
           |  |  | 1027 | if (@warnings) {
 | 
        
           |  |  | 1028 |    my $warnings = join ("\n", @warnings);
 | 
        
           |  |  | 1029 |    if ($iMailResults) {
 | 
        
           |  |  | 1030 |       &sendmail( $mailFrom, $mailTo, 'Process Sysinfo Warnings', $warnings, $mailCC, $mailBCC, $mailServer, $mailServerPort );
 | 
        
           |  |  | 1031 |    } else {
 | 
        
           |  |  | 1032 |       print "$warnings\n";
 | 
        
           |  |  | 1033 |    }
 | 
        
           |  |  | 1034 | }
 | 
        
           |  |  | 1035 |   | 
        
           |  |  | 1036 | exit 1;
 |