File Coverage

blib/lib/FusionInventory/Agent/Tools/Generic.pm
Criterion Covered Total %
statement 18 114 15.7
branch 0 84 0.0
condition 0 30 0.0
subroutine 6 17 35.2
pod 7 7 100.0
total 31 252 12.3


line stmt bran cond sub pod time code
1             package FusionInventory::Agent::Tools::Generic;
2              
3 22     22   5323269 use strict;
  22         49  
  22         975  
4 22     22   116 use warnings;
  22         34  
  22         754  
5 22     22   102 use base 'Exporter';
  22         90  
  22         2683  
6              
7 22     22   121 use English qw(-no_match_vars);
  22         33  
  22         203  
8 22     22   14088 use Memoize;
  22         21522  
  22         1370  
9              
10 22     22   2511 use FusionInventory::Agent::Tools;
  22         40  
  22         49929  
11              
12             our @EXPORT = qw(
13             getDmidecodeInfos
14             getCpusFromDmidecode
15             getHdparmInfo
16             getPCIDevices
17             getPCIDeviceVendor
18             getPCIDeviceClass
19             getUSBDeviceVendor
20             getUSBDeviceClass
21             getEDIDVendor
22             );
23              
24             my $PCIVendors;
25             my $PCIClasses;
26             my $USBVendors;
27             my $USBClasses;
28             my $EDIDVendors;
29              
30             memoize('getDmidecodeInfos');
31             memoize('getPCIDevices');
32              
33             sub getDmidecodeInfos {
34             my (%params) = (
35             command => 'dmidecode',
36             @_
37             );
38              
39             my $handle = getFileHandle(%params);
40             return unless $handle;
41             my ($info, $block, $type);
42              
43             while (my $line = <$handle>) {
44             chomp $line;
45              
46             if ($line =~ /DMI type (\d+)/) {
47             # start of block
48              
49             # push previous block in list
50             if ($block) {
51             push(@{$info->{$type}}, $block);
52             undef $block;
53             }
54              
55             # switch type
56             $type = $1;
57              
58             next;
59             }
60              
61             next unless defined $type;
62              
63             next unless $line =~ /^\s+ ([^:]+) : \s (.*\S)/x;
64              
65             next if
66             $2 eq 'N/A' ||
67             $2 eq 'Not Specified' ||
68             $2 eq 'Not Present' ||
69             $2 eq 'Unknown' ||
70             $2 eq '' ||
71             $2 eq '' ||
72             $2 eq '' ;
73              
74             $block->{$1} = trimWhitespace($2);
75             }
76             close $handle;
77              
78             # do not return anything if dmidecode output is obviously truncated
79             return if keys %$info < 2;
80              
81             return $info;
82             }
83              
84             sub getCpusFromDmidecode {
85 0     0 1   my $infos = getDmidecodeInfos(@_);
86              
87 0 0         return unless $infos->{4};
88              
89 0           my @cpus;
90 0           foreach my $info (@{$infos->{4}}) {
  0            
91 0 0 0       next if $info->{Status} && $info->{Status} =~ /Unpopulated|Disabled/i;
92              
93 0   0       my $manufacturer = $info->{'Manufacturer'} ||
94             $info->{'Processor Manufacturer'};
95 0   0       my $version = $info->{'Version'} ||
96             $info->{'Processor Version'};
97              
98             # VMware
99             next if
100 0 0 0       ($manufacturer && $manufacturer eq '000000000000') &&
      0        
      0        
101             ($version && $version eq '00000000000000000000000000000000');
102              
103 0   0       my $cpu = {
104             SERIAL => $info->{'Serial Number'},
105             ID => $info->{ID},
106             CORE => $info->{'Core Count'} || $info->{'Core Enabled'},
107             THREAD => $info->{'Thread Count'},
108             FAMILYNAME => $info->{'Family'},
109             MANUFACTURER => $manufacturer
110             };
111 0   0       $cpu->{NAME} =
112             ($cpu->{MANUFACTURER} =~ /Intel/ ? $info->{'Family'} : undef) ||
113             $info->{'Version'} ||
114             $info->{'Processor Family'} ||
115             $info->{'Processor Version'};
116              
117 0 0         if ($cpu->{ID}) {
118              
119             # Split CPUID to get access to its content
120 0           my @id = split ("",$cpu->{ID});
121             # convert hexadecimal value
122 0           $cpu->{STEPPING} = hex $id[1];
123             # family number is composed of 3 hexadecimal number
124 0           $cpu->{FAMILYNUMBER} = hex $id[9] . $id[10] . $id[4];
125 0           $cpu->{MODEL} = hex $id[7] . $id[0];
126             }
127              
128 0 0         if ($info->{Version}) {
129 0 0         if ($info->{Version} =~ /([\d\.]+)MHz$/) {
    0          
130 0           $cpu->{SPEED} = $1;
131             } elsif ($info->{Version} =~ /([\d\.]+)GHz$/) {
132 0           $cpu->{SPEED} = $1 * 1000;
133             }
134             }
135 0 0 0       if (!$cpu->{SPEED} && $info->{'Max Speed'}) {
136             # We only look for 3 digit Mhz frequency to avoid abvious bad
137             # value like 30000 (#633)
138 0 0         if ($info->{'Max Speed'} =~ /^\s*(\d{3,4})\s*Mhz/i) {
    0          
139 0           $cpu->{SPEED} = $1;
140             } elsif ($info->{'Max Speed'} =~ /^\s*(\d+)\s*Ghz/i) {
141 0           $cpu->{SPEED} = $1 * 1000;
142             }
143             }
144 0 0 0       if (!$cpu->{SPEED} && $info->{'Current Speed'}) {
145 0 0         if ($info->{'Current Speed'} =~ /^\s*(\d{3,4})\s*Mhz/i) {
    0          
146 0           $cpu->{SPEED} = $1;
147             } elsif ($info->{'Current Speed'} =~ /^\s*(\d+)\s*Ghz/i) {
148 0           $cpu->{SPEED} = $1 * 1000;
149             }
150             }
151              
152 0 0         if ($info->{'External Clock'}) {
153 0 0         if ($info->{'External Clock'} =~ /^\s*(\d+)\s*Mhz/i) {
    0          
154 0           $cpu->{EXTERNAL_CLOCK} = $1;
155             } elsif ($info->{'External Clock'} =~ /^\s*(\d+)\s*Ghz/i) {
156 0           $cpu->{EXTERNAL_CLOCK} = $1 * 1000;
157             }
158             }
159              
160 0           push @cpus, $cpu;
161             }
162              
163 0           return @cpus;
164             }
165              
166             sub getHdparmInfo {
167 0     0 1   my (%params) = @_;
168              
169 0 0         my $handle = getFileHandle(
170             %params,
171             command => $params{device} ? "hdparm -I $params{device}" : undef,
172             );
173 0 0         return unless $handle;
174              
175 0           my $info;
176 0           while (my $line = <$handle>) {
177 0 0         $info->{model} = $1 if $line =~ /Model Number:\s+(\S.+\S)/;
178 0 0         $info->{firmware} = $1 if $line =~ /Firmware Revision:\s+(\S+)/;
179 0 0         $info->{serial} = $1 if $line =~ /Serial Number:\s+(\S*)/;
180 0 0         $info->{size} = $1 if $line =~ /1000:\s+(\d*)\sMBytes/;
181 0 0         $info->{transport} = $1 if $line =~ /Transport:.+(SCSI|SATA|USB)/;
182 0 0         $info->{wwn} = $1 if $line =~ /WWN Device Identifier:\s+(\S+)/;
183             }
184 0           close $handle;
185              
186 0           return $info;
187             }
188              
189             sub getPCIDevices {
190             my (%params) = (
191             command => 'lspci -v -nn',
192             @_
193             );
194             my $handle = getFileHandle(%params);
195              
196             my (@controllers, $controller);
197              
198             while (my $line = <$handle>) {
199             chomp $line;
200              
201             if ($line =~ /^
202             (\S+) \s # slot
203             ([^[]+) \s # name
204             \[([a-f\d]+)\]: \s # class
205             (\S.+) \s # manufacturer
206             \[([a-f\d]+:[a-f\d]+)\] # id
207             (?:\s \(rev \s (\d+)\))? # optional version
208             /x) {
209              
210             $controller = {
211             PCISLOT => $1,
212             NAME => $2,
213             PCICLASS => $3,
214             MANUFACTURER => $4,
215             PCIID => $5,
216             REV => $6
217             };
218             next;
219             }
220              
221             next unless defined $controller;
222              
223             if ($line =~ /^$/) {
224             push(@controllers, $controller);
225             undef $controller;
226             } elsif ($line =~ /^\tKernel driver in use: (\w+)/) {
227             $controller->{DRIVER} = $1;
228             } elsif ($line =~ /^\tSubsystem: ([a-f\d]{4}:[a-f\d]{4})/) {
229             $controller->{PCISUBSYSTEMID} = $1;
230             }
231             }
232              
233             close $handle;
234              
235             return @controllers;
236             }
237              
238             sub getPCIDeviceVendor {
239 0     0 1   my (%params) = @_;
240              
241 0 0         _loadPCIDatabase(%params) if !$PCIVendors;
242              
243 0 0         return unless $params{id};
244 0           return $PCIVendors->{$params{id}};
245             }
246              
247             sub getPCIDeviceClass {
248 0     0 1   my (%params) = @_;
249              
250 0 0         _loadPCIDatabase(%params) if !$PCIClasses;
251              
252 0 0         return unless $params{id};
253 0           return $PCIClasses->{$params{id}};
254             }
255              
256             sub getUSBDeviceVendor {
257 0     0 1   my (%params) = @_;
258              
259 0 0         _loadUSBDatabase(%params) if !$USBVendors;
260              
261 0 0         return unless $params{id};
262 0           return $USBVendors->{$params{id}};
263             }
264              
265             sub getUSBDeviceClass {
266 0     0 1   my (%params) = @_;
267              
268 0 0         _loadUSBDatabase(%params) if !$USBClasses;
269              
270 0 0         return unless $params{id};
271 0           return $USBClasses->{$params{id}};
272             }
273              
274             sub getEDIDVendor {
275 0     0 1   my (%params) = @_;
276              
277 0 0         _loadEDIDDatabase(%params) if !$EDIDVendors;
278              
279 0 0         return unless $params{id};
280 0           return $EDIDVendors->{$params{id}};
281             }
282              
283             sub _loadPCIDatabase {
284 0     0     my (%params) = @_;
285              
286 0           ($PCIVendors, $PCIClasses) = _loadDatabase(
287             file => "$params{datadir}/pci.ids"
288             );
289             }
290              
291             sub _loadUSBDatabase {
292 0     0     my (%params) = @_;
293              
294 0           ($USBVendors, $USBClasses) = _loadDatabase(
295             file => "$params{datadir}/usb.ids"
296             );
297             }
298              
299             sub _loadDatabase {
300 0     0     my $handle = getFileHandle(@_);
301 0 0         return unless $handle;
302              
303 0           my ($vendors, $classes);
304 0           my ($vendor_id, $device_id, $class_id);
305 0           while (my $line = <$handle>) {
306              
307 0 0         if ($line =~ /^\t (\S{4}) \s+ (.*)/x) {
    0          
    0          
    0          
    0          
308             # Device ID
309 0           $device_id = $1;
310 0           $vendors->{$vendor_id}->{devices}->{$device_id}->{name} = $2;
311             } elsif ($line =~ /^\t\t (\S{4}) \s+ (\S{4}) \s+ (.*)/x) {
312             # Subdevice ID
313 0           my $subdevice_id = "$1:$2";
314 0           $vendors->{$vendor_id}->{devices}->{$device_id}->{subdevices}->{$subdevice_id}->{name} = $3;
315             } elsif ($line =~ /^(\S{4}) \s+ (.*)/x) {
316             # Vendor ID
317 0           $vendor_id = $1;
318 0           $vendors->{$vendor_id}->{name} = $2;
319             } elsif ($line =~ /^C \s+ (\S{2}) \s+ (.*)/x) {
320             # Class ID
321 0           $class_id = $1;
322 0           $classes->{$class_id}->{name} = $2;
323             } elsif ($line =~ /^\t (\S{2}) \s+ (.*)/x) {
324             # SubClass ID
325 0           my $subclass_id = $1;
326 0           $classes->{$class_id}->{subclasses}->{$subclass_id}->{name} = $2;
327             }
328             }
329 0           close $handle;
330              
331 0           return ($vendors, $classes);
332             }
333              
334              
335             sub _loadEDIDDatabase {
336 0     0     my (%params) = @_;
337              
338 0           my $handle = getFileHandle(file => "$params{datadir}/edid.ids");
339 0 0         return unless $handle;
340              
341 0           foreach my $line (<$handle>) {
342 0 0         next unless $line =~ /^([A-Z]{3}) __ (.*)$/;
343 0           $EDIDVendors->{$1} = $2;
344             }
345              
346 0           return;
347             }
348              
349             1;
350             __END__