File Coverage

blib/lib/FusionInventory/Agent/Tools.pm
Criterion Covered Total %
statement 211 245 86.1
branch 104 152 68.4
condition 7 11 63.6
subroutine 39 44 88.6
pod 30 30 100.0
total 391 482 81.1


line stmt bran cond sub pod time code
1             package FusionInventory::Agent::Tools;
2              
3 310     310   2880182 use strict;
  310         460  
  310         8057  
4 310     310   1042 use warnings;
  310         414  
  310         8607  
5 310     310   1099 use base 'Exporter';
  310         466  
  310         33660  
6              
7 310     310   152474 use Encode qw(encode);
  310         2267070  
  310         20195  
8 310     310   7141 use English qw(-no_match_vars);
  310         34290  
  310         3294  
9 310     310   115968 use File::Basename;
  310         399  
  310         27093  
10 310     310   1250 use File::Spec;
  310         344  
  310         3459  
11 310     310   133962 use File::stat;
  310         1500579  
  310         1112  
12 310     310   141422 use File::Which;
  310         197331  
  310         12578  
13 310     310   155244 use Memoize;
  310         514189  
  310         12787  
14 310     310   37629 use UNIVERSAL::require;
  310         80035  
  310         3745  
15              
16             our @EXPORT = qw(
17             getDirectoryHandle
18             getFileHandle
19             getFormatedLocalTime
20             getFormatedGMTTime
21             getFormatedDate
22             getCanonicalManufacturer
23             getCanonicalSpeed
24             getCanonicalInterfaceSpeed
25             getCanonicalSize
26             getSanitizedString
27             trimWhitespace
28             getFirstLine
29             getFirstMatch
30             getLastLine
31             getAllLines
32             getLinesCount
33             compareVersion
34             canRun
35             hex2char
36             hex2dec
37             dec2hex
38             any
39             all
40             none
41             uniq
42             file2module
43             module2file
44             runFunction
45             delay
46             slurp
47             isParamArrayAndFilled
48             );
49              
50             my $nowhere = $OSNAME eq 'MSWin32' ? 'nul' : '/dev/null';
51              
52             # this trigger some errors on Perl 5.12/Win32:
53             # Anonymous function called in forbidden scalar context
54             if ($OSNAME ne 'MSWin32') {
55             memoize('canRun');
56             }
57              
58             sub getFormatedLocalTime {
59 0     0 1 0 my ($time) = @_;
60              
61 0 0       0 return unless $time;
62              
63 0         0 my ($year, $month , $day, $hour, $min, $sec) =
64             (localtime ($time))[5, 4, 3, 2, 1, 0];
65              
66 0         0 return getFormatedDate(
67             ($year + 1900), ($month + 1), $day, $hour, $min, $sec
68             );
69             }
70              
71             sub getFormatedGMTTime {
72 1     1 1 1 my ($time) = @_;
73              
74 1         20 my ($year, $month , $day, $hour, $min, $sec) =
75             (gmtime ($time))[5, 4, 3, 2, 1, 0];
76              
77 1         4 return getFormatedDate(
78             ($year - 70), $month, ($day - 1), $hour, $min, $sec
79             );
80             }
81              
82             sub getFormatedDate {
83 1     1 1 2 my ($year, $month, $day, $hour, $min, $sec) = @_;
84              
85 1         6 return sprintf
86             "%02d-%02d-%02d %02d:%02d:%02d",
87             $year, $month, $day, $hour, $min, $sec;
88             }
89              
90             sub getCanonicalManufacturer {
91 68     68 1 9132 my ($manufacturer) = @_;
92              
93 68 100       128 return unless $manufacturer;
94              
95 67         250 my %manufacturers = (
96             GenuineIntel => 'Intel',
97             AuthenticAMD => 'AMD',
98             TMx86 => 'Transmeta',
99             TransmetaCPU => 'Transmeta',
100             CyrixInstead => 'Cyrix',
101             CentaurHauls => 'VIA'
102             );
103              
104 67 100       436 if (exists $manufacturers{$manufacturer}) {
    100          
    100          
    100          
    100          
    100          
105 8         9 $manufacturer = $manufacturers{$manufacturer};
106             } elsif ($manufacturer =~ /(
107             maxtor |
108             sony |
109             compaq |
110             ibm |
111             toshiba |
112             fujitsu |
113             lg |
114             samsung |
115             nec |
116             transcend |
117             matshita |
118             hitachi |
119             pioneer
120             )/xi) {
121 15         40 $manufacturer = ucfirst(lc($1));
122             } elsif ($manufacturer =~ /^(hp|HP|(?i)hewlett[ -]packard)/) {
123 3         3 $manufacturer = "Hewlett-Packard";
124             } elsif ($manufacturer =~ /^(WDC|(?i)western)/) {
125 6         8 $manufacturer = "Western Digital";
126             } elsif ($manufacturer =~ /^(ST|(?i)seagate)/) {
127 14         14 $manufacturer = "Seagate";
128             } elsif ($manufacturer =~ /^(HD|IC|HU|HGST)/) {
129 5         6 $manufacturer = "Hitachi";
130             }
131              
132 67         333 return $manufacturer;
133             }
134              
135             sub getCanonicalSpeed {
136 30     30 1 3129 my ($speed) = @_;
137              
138             ## no critic (ExplicitReturnUndef)
139              
140 30 100       45 return undef unless $speed;
141              
142 29 50       63 return 400 if $speed =~ /^PC3200U/;
143              
144 29 100       87 return undef unless $speed =~ /^([,.\d]+) \s? (\S+)$/x;
145 12         19 my $value = $1;
146 12         17 my $unit = lc($2);
147              
148             return
149 12 50       56 $unit eq 'ghz' ? $value * 1000 :
    100          
150             $unit eq 'mhz' ? $value :
151             undef ;
152             }
153              
154             sub getCanonicalInterfaceSpeed {
155             # Expected unit is Mb/s as specified in inventory protocol
156 7     7 1 13 my ($speed) = @_;
157              
158             ## no critic (ExplicitReturnUndef)
159              
160 7 50       15 return undef unless $speed;
161              
162 7 100       22 return undef unless $speed =~ /^([,.\d]+) \s? (\S\S)\S*$/x;
163 6         9 my $value = $1;
164 6         9 my $unit = lc($2);
165              
166             return
167 6 0       24 $unit eq 'gb' ? $value * 1000 :
    0          
    50          
168             $unit eq 'mb' ? $value :
169             $unit eq 'kb' ? int($value / 1000) :
170             undef ;
171             }
172              
173             sub getCanonicalSize {
174 357     357 1 6919 my ($size, $base) = @_;
175 357   100     761 $base ||= 1000;
176              
177             ## no critic (ExplicitReturnUndef)
178              
179 357 100       399 return undef unless $size;
180              
181 356 100       661 return $size if $size =~ /^\d+$/;
182              
183 354         327 $size =~ s/ //g;
184              
185 354 100       718 return undef unless $size =~ /^([,.\d]+) (\S+)$/x;
186 341         328 my $value = $1;
187 341         315 my $unit = lc($2);
188              
189             return
190 341 50       1184 $unit eq 'tb' ? $value * $base * $base :
    50          
    100          
    100          
    100          
191             $unit eq 'gb' ? $value * $base :
192             $unit eq 'mb' ? $value :
193             $unit eq 'kb' ? int($value / ($base)) :
194             $unit eq 'bytes' ? int($value / ($base * $base)) :
195             undef ;
196             }
197              
198             sub compareVersion {
199 6     6 1 1016 my ($major, $minor, $min_major, $min_minor) = @_;
200              
201 6 100       15 $major = 0 unless $major;
202 6 100       9 $minor = 0 unless $minor;
203 6 100       9 $min_major = 0 unless $min_major;
204 6 100       8 $min_minor = 0 unless $min_minor;
205              
206             return
207 6   66     49 $major > $min_major
208             ||
209             (
210             $major == $min_major
211             &&
212             $minor >= $min_minor
213             );
214             }
215              
216             sub getSanitizedString {
217 20050     20050 1 17798 my ($string) = @_;
218              
219 20050 50       21523 return unless defined $string;
220              
221             # clean control caracters
222 20050         17869 $string =~ s/[[:cntrl:]]//g;
223              
224             # encode to utf-8 if needed
225 20050 100 33     81824 if (!Encode::is_utf8($string) && $string !~ m/\A(
226             [\x09\x0A\x0D\x20-\x7E] # ASCII
227             | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
228             | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
229             | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
230             | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
231             | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
232             | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
233             | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
234             )*\z/x) {
235 4         10 $string = encode("UTF-8", $string);
236             };
237              
238 20050         28476 return $string;
239             }
240              
241             sub trimWhitespace {
242 43948     43948 1 43611 my ($value) = @_;
243 43948         41531 $value =~ s/^\s+//;
244 43948         36981 $value =~ s/\s+$//;
245 43948         55203 $value =~ s/\s+/ /g;
246 43948         152702 return $value;
247             }
248              
249             sub getDirectoryHandle {
250 0     0 1 0 my (%params) = @_;
251              
252 0 0       0 die "no directory parameter given" unless $params{directory};
253              
254 0         0 my $handle;
255              
256 0 0       0 if (!opendir $handle, $params{directory}) {
257             $params{logger}->error("Can't open directory $params{directory}: $ERRNO")
258 0 0       0 if $params{logger};
259 0         0 return;
260             }
261              
262 0         0 return $handle;
263             }
264              
265             sub getFileHandle {
266 661     661 1 1221 my (%params) = @_;
267              
268 661         673 my $handle;
269              
270             SWITCH: {
271 661 100       614 if ($params{file}) {
  661         1579  
272 649 100       22249 if (!open $handle, '<', $params{file}) {
273             $params{logger}->error(
274             "Can't open file $params{file}: $ERRNO"
275 5 50       10 ) if $params{logger};
276 5         17 return;
277             }
278 644         1429 last SWITCH;
279             }
280 12 100       35 if ($params{command}) {
281             # FIXME: 'Bad file descriptor' error message on Windows
282             $params{logger}->debug2("executing $params{command}")
283 10 100       31 if $params{logger};
284             # Turn off localised output for commands
285 10         56 local $ENV{LC_ALL} = 'C';
286 10         35 local $ENV{LANG} = 'C';
287             # Ignore 'Broken Pipe' warnings on Solaris
288 10 50       37 local $SIG{PIPE} = 'IGNORE' if $OSNAME eq 'solaris';
289 10 50       12397 if (!open $handle, '-|', $params{command} . " 2>$nowhere") {
290             $params{logger}->error(
291             "Can't run command $params{command}: $ERRNO"
292 0 0       0 ) if $params{logger};
293 0         0 return;
294             }
295 10         221 last SWITCH;
296             }
297 2 50       5 if ($params{string}) {
298 2 50   1   35 open $handle, "<", \$params{string} or die;
  1         4  
  1         1  
  1         20  
299 2         600 last SWITCH;
300             }
301 0         0 die "neither command, file or string parameter given";
302             }
303              
304 656         1982 return $handle;
305             }
306              
307             sub getFirstLine {
308 10     10 1 1269 my (%params) = @_;
309              
310 10         24 my $handle = getFileHandle(%params);
311 10 50       22 return unless $handle;
312              
313 10         2789 my $result = <$handle>;
314 10         319 close $handle;
315              
316 10 50       26 chomp $result if $result;
317 10         54 return $result;
318             }
319              
320             sub getLastLine {
321 2     2 1 5 my (%params) = @_;
322              
323 2         6 my $handle = getFileHandle(%params);
324 2 50       7 return unless $handle;
325              
326 2         2 my $result;
327 2         1821 while (my $line = <$handle>) {
328 6         294 $result = $line;
329             }
330 2         22 close $handle;
331              
332 2 50       7 chomp $result if $result;
333 2         45 return $result;
334             }
335              
336             sub getFirstMatch {
337 22     22 1 71 my (%params) = @_;
338              
339 22 50       60 return unless $params{pattern};
340 22         65 my $handle = getFileHandle(%params);
341 22 50       65 return unless $handle;
342              
343 22         23 my @results;
344 22         9730 while (my $line = <$handle>) {
345 76         352 @results = $line =~ $params{pattern};
346 76 100       207 last if @results;
347             }
348 22         602 close $handle;
349              
350 22 100       212 return wantarray ? @results : $results[0];
351             }
352              
353             sub getAllLines {
354 73     73 1 67615 my (%params) = @_;
355              
356 73         162 my $handle = getFileHandle(%params);
357 73 50       136 return unless $handle;
358              
359 73 100       115 if (wantarray) {
360 2         1884 my @lines = map { chomp; $_ } <$handle>;
  6         6  
  6         13  
361 2         22 close $handle;
362 2         32 return @lines;
363             } else {
364 71         178 local $RS;
365 71         2854 my $lines = <$handle>;
366 71         352 close $handle;
367 71         354 return $lines;
368             }
369             }
370              
371             sub getLinesCount {
372 2     2 1 5 my (%params) = @_;
373              
374 2         6 my $handle = getFileHandle(%params);
375 2 50       7 return unless $handle;
376              
377 2         4 my $count = 0;
378 2         1680 while (my $line = <$handle>) {
379 6         217 $count++;
380             }
381 2         32 close $handle;
382              
383 2         24 return $count;
384             }
385              
386             sub canRun {
387             my ($binary) = @_;
388              
389             return $binary =~ m{^/} ?
390             -x $binary : # full path
391             scalar(which($binary)); # executable name
392             }
393              
394             sub hex2char {
395 9     9 1 969 my ($value) = @_;
396              
397             ## no critic (ExplicitReturnUndef)
398 9 100       19 return undef unless $value;
399 7 100       24 return $value unless $value =~ /^0x/;
400              
401 2         5 $value =~ s/^0x//; # drop hex prefix
402 2         21 return pack('H*', $value);
403             }
404              
405             sub hex2dec {
406 2     2 1 722 my ($value) = @_;
407              
408             ## no critic (ExplicitReturnUndef)
409 2 50       5 return undef unless $value;
410 2 100       8 return $value unless $value =~ /^0x/;
411              
412 1         7 return oct($value);
413             }
414              
415             sub dec2hex {
416 24     24 1 664 my ($value) = @_;
417              
418             ## no critic (ExplicitReturnUndef)
419 24 50       33 return undef unless $value;
420 24 100       37 return $value if $value =~ /^0x/;
421              
422 23         78 return sprintf("0x%x", $value);
423             }
424              
425             # shamelessly imported from List::MoreUtils to avoid a dependency
426             sub any (&@) { ## no critic (SubroutinePrototypes)
427 38     38 1 3642644 my $f = shift;
428 38         65 foreach ( @_ ) {
429 84 100       143 return 1 if $f->();
430             }
431 7         19 return 0;
432             }
433              
434             sub all (&@) { ## no critic (SubroutinePrototypes)
435 6     6 1 552 my $f = shift;
436 6         10 foreach ( @_ ) {
437 221 100       529 return 0 unless $f->();
438             }
439 4         43 return 1;
440             }
441              
442             sub none (&@) { ## no critic (SubroutinePrototypes)
443 0     0 1 0 my $f = shift;
444 0         0 foreach ( @_ ) {
445 0 0       0 return 0 if $f->();
446             }
447 0         0 return 1;
448             }
449              
450             sub uniq (@) { ## no critic (SubroutinePrototypes)
451 33     33 1 37 my %seen = ();
452 33         40 grep { not $seen{$_}++ } @_;
  247         305  
453             }
454              
455             sub file2module {
456 234     234 1 304 my ($file) = @_;
457 234         376 $file =~ s{.pm$}{};
458 234         444 $file =~ s{/}{::}g;
459 234         350 return $file;
460             }
461              
462             sub module2file {
463 1     1 1 2 my ($module) = @_;
464 1         2 $module .= '.pm';
465 1         4 $module =~ s{::}{/}g;
466 1         2 return $module;
467             }
468              
469             sub runFunction {
470 3     3 1 1884 my (%params) = @_;
471              
472 3         7 my $logger = $params{logger};
473              
474             # ensure module is loaded
475 3 100       13 if ($params{load}) {
476 1         16 $params{module}->require();
477 1 50       128 if ($EVAL_ERROR) {
478 0 0       0 $logger->debug("Failed to load $params{module}: $EVAL_ERROR")
479             if $logger;
480 0         0 return;
481             }
482             }
483              
484 3         5 my $result;
485 3         5 eval {
486 3     1   54 local $SIG{ALRM} = sub { die "alarm\n" };
  1         1000068  
487             # set a timeout if needed
488 3 100       16 alarm $params{timeout} if $params{timeout};
489              
490 310     310   626247 no strict 'refs'; ## no critic (ProhibitNoStrict)
  310         473  
  310         82995  
491 3         51 $result = &{$params{module} . '::' . $params{function}}(
492 0         0 ref $params{params} eq 'HASH' ? %{$params{params}} :
493 0         0 ref $params{params} eq 'ARRAY' ? @{$params{params}} :
494             $params{params}
495 3 50       14 );
    50          
496 1         30 alarm 0;
497             };
498              
499 3 100       13 if ($EVAL_ERROR) {
500 2 100       17 my $message = $EVAL_ERROR eq "alarm\n" ?
501             "$params{module} killed by a timeout" :
502             "unexpected error in $params{module}: $EVAL_ERROR";
503 2 50       7 $logger->debug($message) if $logger;
504             }
505              
506 3         12 return $result;
507             }
508              
509             sub delay {
510 0     0 1 0 my ($delay) = @_;
511              
512 0 0       0 if ($OSNAME eq 'MSWin32') {
513 0         0 Win32->require();
514 0         0 Win32::Sleep($delay*1000);
515             } else {
516 0         0 sleep($delay);
517             }
518             }
519              
520             sub slurp {
521 0     0 1 0 my($file) = @_;
522              
523 0         0 my $handler;
524 0 0       0 return unless open $handler, '<', $file;
525 0         0 local $INPUT_RECORD_SEPARATOR; # Set input to "slurp" mode.
526 0         0 my $content = <$handler>;
527 0         0 close $handler;
528 0         0 return $content;
529             }
530              
531             sub isParamArrayAndFilled {
532 20     20 1 16 my ($hash, $paramName) = @_;
533            
534             return (defined ($hash->{$paramName}))
535             && UNIVERSAL::isa($hash->{$paramName}, 'ARRAY')
536 20   66     116 && (scalar(@{$hash->{$paramName}}) > 0);
537             }
538              
539             1;
540             __END__