Subversion Repositories camp_sysinfo_client (old)

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 rodolico 1
#! /usr/bin/perl -w
2
#
3
# This is part of the Sysinfo client package which collects information from a system
4
# and reports it back to a centralized server.
5
# this library is for reporting on Linux systems
6
#
7
# Author: R. W. Rodolico
8
#
9
# v0.1 20090101 RWR
10
# Created and entered into Sysinfo system
11
#
12
# v0.2 20090508 RWR
13
# lscpi causing some problems. Rewrote routine to solve issues where lspci is inconsistent on its reporting
14
 
15
 
16
package SysinfoLinux;
17
 
18
 
19
 
20
# gets information on disks and partitions. Returns them as a hash
21
# uses standard df -kT and parses the output
22
# skips anything that does not have a device with /dev in it
23
# assumes the structure of the output is:
24
# device fstype size usedSpace availableSpace percentSpace mountPoint
25
# however, the output can sometimes wrap to multi lines, especially if the 
26
# device is long. So, we will replace all newlines with spaces, then 
27
# remove space duplications, then split on spaces and process each item in
28
# turn.
29
# NOTE: this will totally break if you have spaces in your mount point
30
sub getDiskInfo {
31
   my @directoriesToWatch = @_; # optional directories to check
32
   my %returnValue; # the has we sill store the results in
33
 
34
   # process physical partitions
35
   my $temp = qx/df -kT/; # execute the system command df, returned values in kilobytes, showing file system types
36
   @temp = split("\n", $temp ); # get array of lines
37
   shift @temp; # get rid of the first line . . . it is nothing but header info
38
   $temp = join( ' ', @temp ); # rejoin everything back with spaces
39
   $temp =~ s/ +/ /gi; # remove all duplicate spaces
40
   @temp = split( ' ', $temp ); # turn it back into an array of space separated values
41
   while (@temp) {
42
      my $device = shift @temp; # get the device name
43
      my %thisDisk;
44
      $thisDisk{'fstype'} = shift @temp; # next is fs type
45
      $thisDisk{'size'} = shift @temp; # total partition size, in k
46
      $thisDisk{'used'} = shift @temp; # disk usage, in k
47
      shift @temp; # $available, not recorded
48
      shift @temp; # $percent, not recorded
49
      $thisDisk{'mount'} = shift @temp; # mount point
50
      # now, if it is a /dev device, we add it to the diskInfo hash
51
      $returnValue{$device} = \%thisDisk if $device =~ m/\/dev/;
52
   }
53
 
54
   # process any directories to watch
55
   while ( my $path = shift @directoriesToWatch ) {
56
      my @results = qx/du -sk $path/;
57
      chomp @results;
58
      while ( my $thisValue = shift @results ) {
59
         my ($used,$mount) = split( "\t", $thisValue );
60
         $returnValue{$mount}{'used'} = $used;
61
      }
62
   }
63
   return \%returnValue;
64
}
65
 
66
 
67
sub getNetwork {
68
   # eth1      Link encap:Ethernet  HWaddr 00:16:3E:1F:EF:4F
69
   my $regexHWADDR = 'hwaddr[^0-9a-f:]+([0-9a-f:]+)[^0-9a-f:]';
70
   # inet addr:10.110.110.2  Bcast:10.110.110.255  Mask:255.255.255.0
71
   my $regexINET = 'inet addr:\s*([0-9.]+)[^0-9].*mask:([0-9.]+)';
72
   # inet6 addr: fe80::216:3eff:fe1f:ef4f/64 Scope:Link
73
   my $regexINET6 = 'inet6 addr: ([0-9a-f:]+)\/([0-9]+)[^0-9]';
74
   # UP LOOPBACK RUNNING  MTU:16436  Metric:1
75
   my $regexMTU = 'mtu:([0-9]+)[^0-9]';
76
   my $temp = qx/ifconfig/;
77
   my @temp = split( "\n", $temp );
78
   my %returnValue;
79
   my $currentIF;
80
   while ( @temp ) {
81
      $line = shift @temp;
82
      next unless $line;
83
      if ( $line =~ m/^([^ ]+) /) { # if the first character is not a space, starting new entry
84
         $currentIF = $1;
85
         if ( $line =~ m/$regexHWADDR/i ) {
86
            $returnValue{$currentIF}{'mac'} = $1;
87
         } else {
88
            $returnValue{$currentIF}{'mac'} = 'unknown';
89
         }
90
      } elsif ( $line =~ m/$regexINET/i ) {
91
         $returnValue{$currentIF}{'address'} = $1;
92
         $returnValue{$currentIF}{'netmask'} = $2;
93
      } elsif ( $line =~ m/$regexINET6/i )  {
94
         $returnValue{$currentIF}{'ip6address'} = $1;
95
         $returnValue{$currentIF}{'ip6networkbits'} = $2;
96
      } elsif ( $line =~ m/$regexMTU/i )  {
97
         $returnValue{$currentIF}{'mtu'} = $1;
98
      }
99
   }
100
   return \%returnValue;
101
}
102
 
103
sub getSoftware {
104
   my $CUSTOM_PACKAGE_FINDER = shift; # used if there is an additional routine to call for software
105
   my %returnValue;
106
 
107
   # We currently handle dpkg and rpm
108
   if ( `which dpkg 2>/dev/null` ) {  # system uses dpkg, ie debian or derivitive
109
      my @packageList  = split( "\n", qx(dpkg -l | grep ^i));
110
      chomp @packageList;
111
      for ( $i = 0; $i < @packageList; $i++ ) {
112
         my ($status,$package, $version, @description) = split ' ', $packageList[$i];
113
         $returnValue{$package}{'version'} = $version;
114
         $returnValue{$package}{'description'} = join(" ", @description);
115
      }
116
   } elsif ( `which rpm 2>/dev/null` ) { # system uses rpm, ie most RedHat derivitives
117
      my @packageList = split( "\n", qx( rpm -qa --qf "%{NAME}\\t%{VERSION}\\t%{DISTRIBUTION}\\n" ) );
118
      chomp @packageList;
119
      for ( $i = 0; $i < @packageList; $i++ ) {
120
         my ($package, $version, $distribution)  = split( "\t", $packageList[$i]);
121
         $returnValue{$package}{'version'} = $version;
122
         $returnValue{$package}{'description'} = join(" ", @description);
123
      }
124
   } else {
125
      die 'Unknown package manager, please modify the script';
126
   }
127
   # ok, we have the packages found by "normal" means, not do the package manager if it exists
128
   # it is assumed to return a tab delimited list of package, version and description
129
   if ( $CUSTOM_PACKAGE_FINDER ) {
130
      my $customPackages = qx/$CUSTOM_PACKAGE_FINDER $APPLICATION_ROOT/ if ( -e $CUSTOM_PACKAGE_FINDER );
131
      my @packageList = split( "\n", $customPackages);
132
      foreach my $thisPackage ( @packageList ) {
133
         my ($package,$version,$description) = split( "\t", $thisPackage );
134
         $returnValue{$package}{'version'} = $version;
135
         $returnValue{$package}{'description'} = $description;
136
      }
137
   }
138
   return \%returnValue;
139
}
140
 
141
sub cleanUp {
142
   my ($delimiter, $text) = @_;
143
   $text =~ m/[^$delimiter]*$delimiter\s*(.*)/;
144
   return $1;
145
}
146
 
147
sub chompHash {
148
   my $hash = shift;
149
   foreach my $key ( keys %$hash ) {
150
      chomp $$hash{$key} if $$hash{$key};
151
   }
152
   return $hash;
153
}
154
 
155
# Just get various OS parameters; name, description, release, etc...
156
sub getOperatingSystem {
157
   my %returnValue;
158
   $returnValue{'distribution'} = &cleanUp(':', qx(lsb_release -i));
159
   $returnValue{'description'} =  &cleanUp(':', qx(lsb_release -d)) . "\n";
160
   $returnValue{'release'} = &cleanUp(':', qx(lsb_release -r)) . "\n";
161
   $returnValue{'codename'} = &cleanUp(':', qx(lsb_release -c)) . "\n";
162
   $returnValue{'os_name'} =  qx(uname -s);
163
   $returnValue{'os_version'} =  qx(cat /proc/version);
164
   $returnValue{'kernel'} =  qx(uname -r);
165
   return &chompHash(\%returnValue);
166
}
167
 
168
sub getRebootInfo {
169
   # get uptime from /proc/uptime
170
   my $uptime = qx(cat /proc/uptime);
171
   $uptime =~ m/(\d+)/;
172
   $uptime = int($1); # uptime now has the up time in seconds
173
   return time - $uptime;
174
   # following has been commented out as process_sysinfo knows how to read the information in unix time
175
   # Now, calculate the last boot time. This may be off by a second, but that is close
176
   # enough for these purposes. this used to be done by capturing the output of
177
   # procinfo | grep Bootup | sed 's/Bootup: //g' | cut -f1-6 -d' '
178
   # but, I wanted to return a database ready date, and Windows systems will be off more
179
   # than this anyway.
180
   #my $lastBoot = time - $uptime;
181
   #my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) =
182
   #  localtime($lastBoot);
183
   #$year += 1900;
184
   #$mon++;
185
   #return (sprintf( "%04d%02d%02d%02d%02d%02d", $year, $mon, $mday, $hour, $min, $sec ),$uptime);
186
}
187
 
188
sub getSystemInformation {
189
   my $hostname = shift;
190
   my %returnValue;
191
   $returnValue{'hostname'} = ( $hostname ? $hostname : qx(hostname -f) );
192
   $returnValue{'memory'} =  qx(free | grep Mem | awk '{print \$2}');
193
   $returnValue{'num_cpu'} =  qx(cat /proc/cpuinfo | grep processor | wc -l | awk '{print \$1}');
194
   $returnValue{'cpu_speed'} = qx(cat /proc/cpuinfo | grep MHz | tail -n1 | awk '{print \$4}');
195
   $returnValue{'cpu_type'} = qx(cat /proc/cpuinfo | grep vendor_id | tail -n 1 | awk '{print \$3}');
196
   $returnValue{'cpu_sub'} =  qx(uname -m);
197
   $returnValue{'last_boot'} = &getRebootInfo;
198
   return &chompHash(\%returnValue);
199
}
200
 
201
sub getPCI {
202
   my %returnValue;
203
   my $pciInfo =  qx(lspci -Dvmm);
204
   # this is a regular expression to "find" the slot number, if one exists
205
   # Different versions of lspci use different keys for the name and the slot
206
   # in some cases, the key Device: is used for both the device name and the slot (Debian Etch lspci version 2.2.4-pre4)
207
   # so I have to use this kludge. I may rewrite it to just search the sys directory tree later.
208
   my $SLOT_REGEX = '^[0-9a-z]+[:.][0-9a-z]+';
209
   my @pciInfo = split ("\n\n", $pciInfo);
210
   my $i = 0;
211
   while (my $test = shift (@pciInfo)) {
212
      foreach my $thisLine (sort split("\n", $test)) {
213
         if ($thisLine =~ m/([a-z]+):\s*(\S.*)/i) {
214
            my ($key, $value) = (lc $1,$2);
215
            # remove any leading whitespace
216
            $key =~ s/^\s*//g;
217
            $value =~ s/^\s*//g;
218
            while (defined($returnValue{$i}{$key})) { # dup key, so give it a unique value
219
               $key .= '0'; # just add some 0's at the end
220
            }
221
            $returnValue{$i}{$key} = $value;
222
         }
223
      }
224
      unless (defined $returnValue{$i}{'slot'}) { # no slot number, so see if we have one
225
         $returnValue{$i}{'slot'} = 'Unknown';
226
         for my $thisKey ( keys %{$returnValue{$i}} ) {
227
             if ($returnValue{$i}{$thisKey} =~ m/$SLOT_REGEX/i) {
228
               $returnValue{$i}{'slot'} = $returnValue{$i}{$thisKey}; # this puts it in two places, so remove the original
229
               delete $returnValue{$i}{$thisKey};
230
               last;
231
             }
232
          }
233
      }
234
 
235
      if (defined ($returnValue{$i}{'name'})) { # we need to not have this; it messes up the xml package
236
         $returnValue{$i}{'device name'} = $returnValue{$i}{'name'};
237
         delete $returnValue{$i}{'name'}
238
      }
239
      unless (defined ($returnValue{$i}{'name'})) { # no name, so see if we have one
240
         $returnValue{$i}{'name'} = 'Unknown';
241
         foreach my $thisKey ( 'slot', 'device', 'device0', 'sdevice', 'class', 'vendor', 'svendor' ) {
242
            if (defined($returnValue{$i}{$thisKey}) && ($returnValue{$i} ne 'Unknown') ) {
243
               $returnValue{$i}{'name'} = $returnValue{$i}{$thisKey};
244
               last;
245
            }
246
         }
247
      }
248
      $i++;
249
   }
250
   return \%returnValue;
251
}
252
 
253
 
254
1;