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;
|