File Coverage

blib/lib/FusionInventory/Agent/Tools.pm
Criterion Covered Total %
statement 52 234 22.2
branch 5 142 3.5
condition 0 8 0.0
subroutine 14 41 34.1
pod 28 28 100.0
total 99 453 21.8


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