File Coverage

blib/lib/FusionInventory/Agent/Tools.pm
Criterion Covered Total %
statement 209 243 86.0
branch 105 152 69.0
condition 6 8 75.0
subroutine 38 43 88.3
pod 29 29 100.0
total 387 475 81.4


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