Subversion Repositories camp_sysinfo_client (old)

Rev

Blame | Last modification | View Log | RSS feed

#! /usr/bin/perl -w
#
# This is part of the Sysinfo client package which collects information from a system
# and reports it back to a centralized server.
# this library is for reporting on Linux systems
#
# Author: R. W. Rodolico
#
# v0.1 20090101 RWR
# Created and entered into Sysinfo system
#
# v0.2 20090508 RWR
# lscpi causing some problems. Rewrote routine to solve issues where lspci is inconsistent on its reporting


package SysinfoLinux;



# gets information on disks and partitions. Returns them as a hash
# uses standard df -kT and parses the output
# skips anything that does not have a device with /dev in it
# assumes the structure of the output is:
# device fstype size usedSpace availableSpace percentSpace mountPoint
# however, the output can sometimes wrap to multi lines, especially if the 
# device is long. So, we will replace all newlines with spaces, then 
# remove space duplications, then split on spaces and process each item in
# turn.
# NOTE: this will totally break if you have spaces in your mount point
sub getDiskInfo {
   my @directoriesToWatch = @_; # optional directories to check
   my %returnValue; # the has we sill store the results in
   
   # process physical partitions
   my $temp = qx/df -kT/; # execute the system command df, returned values in kilobytes, showing file system types
   @temp = split("\n", $temp ); # get array of lines
   shift @temp; # get rid of the first line . . . it is nothing but header info
   $temp = join( ' ', @temp ); # rejoin everything back with spaces
   $temp =~ s/ +/ /gi; # remove all duplicate spaces
   @temp = split( ' ', $temp ); # turn it back into an array of space separated values
   while (@temp) {
      my $device = shift @temp; # get the device name
      my %thisDisk;
      $thisDisk{'fstype'} = shift @temp; # next is fs type
      $thisDisk{'size'} = shift @temp; # total partition size, in k
      $thisDisk{'used'} = shift @temp; # disk usage, in k
      shift @temp; # $available, not recorded
      shift @temp; # $percent, not recorded
      $thisDisk{'mount'} = shift @temp; # mount point
      # now, if it is a /dev device, we add it to the diskInfo hash
      $returnValue{$device} = \%thisDisk if $device =~ m/\/dev/;
   }
   
   # process any directories to watch
   while ( my $path = shift @directoriesToWatch ) {
      my @results = qx/du -sk $path/;
      chomp @results;
      while ( my $thisValue = shift @results ) {
         my ($used,$mount) = split( "\t", $thisValue );
         $returnValue{$mount}{'used'} = $used;
      }
   }
   return \%returnValue;
}


sub getNetwork {
   # eth1      Link encap:Ethernet  HWaddr 00:16:3E:1F:EF:4F
   my $regexHWADDR = 'hwaddr[^0-9a-f:]+([0-9a-f:]+)[^0-9a-f:]';
   # inet addr:10.110.110.2  Bcast:10.110.110.255  Mask:255.255.255.0
   my $regexINET = 'inet addr:\s*([0-9.]+)[^0-9].*mask:([0-9.]+)';
   # inet6 addr: fe80::216:3eff:fe1f:ef4f/64 Scope:Link
   my $regexINET6 = 'inet6 addr: ([0-9a-f:]+)\/([0-9]+)[^0-9]';
   # UP LOOPBACK RUNNING  MTU:16436  Metric:1
   my $regexMTU = 'mtu:([0-9]+)[^0-9]';
   my $temp = qx/ifconfig/;
   my @temp = split( "\n", $temp );
   my %returnValue;
   my $currentIF;
   while ( @temp ) {
      $line = shift @temp;
      next unless $line;
      if ( $line =~ m/^([^ ]+) /) { # if the first character is not a space, starting new entry
         $currentIF = $1;
         if ( $line =~ m/$regexHWADDR/i ) {
            $returnValue{$currentIF}{'mac'} = $1;
         } else {
            $returnValue{$currentIF}{'mac'} = 'unknown';
         }
      } elsif ( $line =~ m/$regexINET/i ) {
         $returnValue{$currentIF}{'address'} = $1;
         $returnValue{$currentIF}{'netmask'} = $2;
      } elsif ( $line =~ m/$regexINET6/i )  {
         $returnValue{$currentIF}{'ip6address'} = $1;
         $returnValue{$currentIF}{'ip6networkbits'} = $2;
      } elsif ( $line =~ m/$regexMTU/i )  {
         $returnValue{$currentIF}{'mtu'} = $1;
      }
   }
   return \%returnValue;
}

sub getSoftware {
   my $CUSTOM_PACKAGE_FINDER = shift; # used if there is an additional routine to call for software
   my %returnValue;
   
   # We currently handle dpkg and rpm
   if ( `which dpkg 2>/dev/null` ) {  # system uses dpkg, ie debian or derivitive
      my @packageList  = split( "\n", qx(dpkg -l | grep ^i));
      chomp @packageList;
      for ( $i = 0; $i < @packageList; $i++ ) {
         my ($status,$package, $version, @description) = split ' ', $packageList[$i];
         $returnValue{$package}{'version'} = $version;
         $returnValue{$package}{'description'} = join(" ", @description);
      }
   } elsif ( `which rpm 2>/dev/null` ) { # system uses rpm, ie most RedHat derivitives
      my @packageList = split( "\n", qx( rpm -qa --qf "%{NAME}\\t%{VERSION}\\t%{DISTRIBUTION}\\n" ) );
      chomp @packageList;
      for ( $i = 0; $i < @packageList; $i++ ) {
         my ($package, $version, $distribution)  = split( "\t", $packageList[$i]);
         $returnValue{$package}{'version'} = $version;
         $returnValue{$package}{'description'} = join(" ", @description);
      }
   } else {
      die 'Unknown package manager, please modify the script';
   }
   # ok, we have the packages found by "normal" means, not do the package manager if it exists
   # it is assumed to return a tab delimited list of package, version and description
   if ( $CUSTOM_PACKAGE_FINDER ) {
      my $customPackages = qx/$CUSTOM_PACKAGE_FINDER $APPLICATION_ROOT/ if ( -e $CUSTOM_PACKAGE_FINDER );
      my @packageList = split( "\n", $customPackages);
      foreach my $thisPackage ( @packageList ) {
         my ($package,$version,$description) = split( "\t", $thisPackage );
         $returnValue{$package}{'version'} = $version;
         $returnValue{$package}{'description'} = $description;
      }
   }
   return \%returnValue;
}

sub cleanUp {
   my ($delimiter, $text) = @_;
   $text =~ m/[^$delimiter]*$delimiter\s*(.*)/;
   return $1;
}

sub chompHash {
   my $hash = shift;
   foreach my $key ( keys %$hash ) {
      chomp $$hash{$key} if $$hash{$key};
   }
   return $hash;
}

# Just get various OS parameters; name, description, release, etc...
sub getOperatingSystem {
   my %returnValue;
   $returnValue{'distribution'} = &cleanUp(':', qx(lsb_release -i));
   $returnValue{'description'} =  &cleanUp(':', qx(lsb_release -d)) . "\n";
   $returnValue{'release'} = &cleanUp(':', qx(lsb_release -r)) . "\n";
   $returnValue{'codename'} = &cleanUp(':', qx(lsb_release -c)) . "\n";
   $returnValue{'os_name'} =  qx(uname -s);
   $returnValue{'os_version'} =  qx(cat /proc/version);
   $returnValue{'kernel'} =  qx(uname -r);
   return &chompHash(\%returnValue);
}

sub getRebootInfo {
   # get uptime from /proc/uptime
   my $uptime = qx(cat /proc/uptime);
   $uptime =~ m/(\d+)/;
   $uptime = int($1); # uptime now has the up time in seconds
   return time - $uptime;
   # following has been commented out as process_sysinfo knows how to read the information in unix time
   # Now, calculate the last boot time. This may be off by a second, but that is close
   # enough for these purposes. this used to be done by capturing the output of
   # procinfo | grep Bootup | sed 's/Bootup: //g' | cut -f1-6 -d' '
   # but, I wanted to return a database ready date, and Windows systems will be off more
   # than this anyway.
   #my $lastBoot = time - $uptime;
   #my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
   #  localtime($lastBoot);
   #$year += 1900;
   #$mon++;
   #return (sprintf( "%04d%02d%02d%02d%02d%02d", $year, $mon, $mday, $hour, $min, $sec ),$uptime);
}

sub getSystemInformation {
   my $hostname = shift;
   my %returnValue;
   $returnValue{'hostname'} = ( $hostname ? $hostname : qx(hostname -f) );
   $returnValue{'memory'} =  qx(free | grep Mem | awk '{print \$2}');
   $returnValue{'num_cpu'} =  qx(cat /proc/cpuinfo | grep processor | wc -l | awk '{print \$1}');
   $returnValue{'cpu_speed'} = qx(cat /proc/cpuinfo | grep MHz | tail -n1 | awk '{print \$4}');
   $returnValue{'cpu_type'} = qx(cat /proc/cpuinfo | grep vendor_id | tail -n 1 | awk '{print \$3}');
   $returnValue{'cpu_sub'} =  qx(uname -m);
   $returnValue{'last_boot'} = &getRebootInfo;
   return &chompHash(\%returnValue);
}

sub getPCI {
   my %returnValue;
   my $pciInfo =  qx(lspci -Dvmm);
   # this is a regular expression to "find" the slot number, if one exists
   # Different versions of lspci use different keys for the name and the slot
   # in some cases, the key Device: is used for both the device name and the slot (Debian Etch lspci version 2.2.4-pre4)
   # so I have to use this kludge. I may rewrite it to just search the sys directory tree later.
   my $SLOT_REGEX = '^[0-9a-z]+[:.][0-9a-z]+';
   my @pciInfo = split ("\n\n", $pciInfo);
   my $i = 0;
   while (my $test = shift (@pciInfo)) {
      foreach my $thisLine (sort split("\n", $test)) {
         if ($thisLine =~ m/([a-z]+):\s*(\S.*)/i) {
            my ($key, $value) = (lc $1,$2);
            # remove any leading whitespace
            $key =~ s/^\s*//g;
            $value =~ s/^\s*//g;
            while (defined($returnValue{$i}{$key})) { # dup key, so give it a unique value
               $key .= '0'; # just add some 0's at the end
            }
            $returnValue{$i}{$key} = $value;
         }
      }
      unless (defined $returnValue{$i}{'slot'}) { # no slot number, so see if we have one
         $returnValue{$i}{'slot'} = 'Unknown';
         for my $thisKey ( keys %{$returnValue{$i}} ) {
             if ($returnValue{$i}{$thisKey} =~ m/$SLOT_REGEX/i) {
               $returnValue{$i}{'slot'} = $returnValue{$i}{$thisKey}; # this puts it in two places, so remove the original
               delete $returnValue{$i}{$thisKey};
               last;
             }
          }
      }
      
      if (defined ($returnValue{$i}{'name'})) { # we need to not have this; it messes up the xml package
         $returnValue{$i}{'device name'} = $returnValue{$i}{'name'};
         delete $returnValue{$i}{'name'}
      }
      unless (defined ($returnValue{$i}{'name'})) { # no name, so see if we have one
         $returnValue{$i}{'name'} = 'Unknown';
         foreach my $thisKey ( 'slot', 'device', 'device0', 'sdevice', 'class', 'vendor', 'svendor' ) {
            if (defined($returnValue{$i}{$thisKey}) && ($returnValue{$i} ne 'Unknown') ) {
               $returnValue{$i}{'name'} = $returnValue{$i}{$thisKey};
               last;
            }
         }
      }
      $i++;
   }
   return \%returnValue;
}


1;

Generated by GNU Enscript 1.6.5.90.