File Coverage

blib/lib/FusionInventory/Agent/Tools/Solaris.pm
Criterion Covered Total %
statement 144 146 98.6
branch 53 62 85.4
condition 1 3 33.3
subroutine 18 18 100.0
pod 1 1 100.0
total 217 230 94.3


line stmt bran cond sub pod time code
1             package FusionInventory::Agent::Tools::Solaris;
2              
3 15     15   13002172 use strict;
  15         22  
  15         375  
4 15     15   68 use warnings;
  15         22  
  15         384  
5 15     15   49 use base 'Exporter';
  15         46  
  15         1092  
6              
7 15     15   453 use English qw(-no_match_vars);
  15         2387  
  15         102  
8              
9 15     15   5477 use FusionInventory::Agent::Tools;
  15         21  
  15         1698  
10 15     15   51 use Memoize;
  15         19  
  15         23576  
11              
12             our @EXPORT = qw(
13             getZone
14             getPrtconfInfos
15             getPrtdiagInfos
16             getReleaseInfo
17             );
18              
19             memoize('getZone');
20             memoize('getPrtdiagInfos');
21             memoize('getReleaseInfo');
22              
23             sub getZone {
24             return canRun('zonename') ?
25             getFirstLine(command => 'zonename') : # actual zone name
26             'global'; # outside zone name
27             }
28              
29             sub getPrtconfInfos {
30 3     3 1 26801 my (%params) = (
31             command => '/usr/sbin/prtconf -vp',
32             @_
33             );
34              
35 3         13 my $handle = getFileHandle(%params);
36 3 50       7 return unless $handle;
37              
38 3         6 my $info = {};
39              
40             # a stack of nodes, as a list of couples [ node, level ]
41 3         6 my @parents = (
42             [ $info, -1 ]
43             );
44              
45 3         64 while (my $line = <$handle>) {
46 2833         1746 chomp $line;
47              
48             # new node
49 2833 100       3684 if ($line =~ /^(\s*)Node \s 0x[a-f\d]+/x) {
50 293 50       402 my $level = defined $1 ? length($1) : 0;
51              
52 293         203 my $parent_level = $parents[-1]->[1];
53              
54             # compare level with parent
55 293 100       380 if ($level > $parent_level) {
    100          
56             # down the tree: no change
57             } elsif ($level < $parent_level) {
58             # up the tree: unstack nodes until a suitable parent is found
59 30         41 while ($level <= $parents[-1]->[1]) {
60 71         104 pop @parents;
61             }
62             } else {
63             # same level: unstack last node
64 217         161 pop @parents;
65             }
66              
67             # push a new node on the stack
68 293         374 push (@parents, [ {}, $level ]);
69              
70 293         640 next;
71             }
72              
73 2540 100       3002 if ($line =~ /^\s* name: \s+ '(\S.*)'$/x) {
74 293         243 my $node = $parents[-1]->[0];
75 293         177 my $parent = $parents[-2]->[0];
76 293         314 $parent->{$1} = $node;
77 293         642 next;
78             }
79              
80             # value
81 2247 100       4692 if ($line =~ /^\s* (\S[^:]+): \s+ (\S.*)$/x) {
82 1877         1664 my $key = $1;
83 1877         1474 my $raw_value = $2;
84 1877         1289 my $node = $parents[-1]->[0];
85              
86 1877 100       3001 if ($raw_value =~ /^'[^']+'(?: \+ '[^']+')+$/) {
    100          
87             # list of string values
88             $node->{$key} = [
89 47         100 map { /^'([^']+)'$/; $1 }
  200         232  
  200         265  
90             split (/ \+ /, $raw_value)
91             ];
92             } elsif ($raw_value =~ /^'([^']+)'$/) {
93             # single string value
94 552         713 $node->{$key} = $1;
95             } else {
96             # other kind of value
97 1278         1605 $node->{$key} = $raw_value;
98             }
99 1877         3295 next;
100             }
101              
102             }
103 3         22 close $handle;
104              
105 3         18 return $info;
106             }
107              
108             sub getPrtdiagInfos {
109             my (%params) = (
110             command => 'prtdiag',
111             @_
112             );
113              
114             my $handle = getFileHandle(%params);
115             return unless $handle;
116              
117             my $info = {};
118              
119             while (my $line = <$handle>) {
120             next unless $line =~ /^=+ \s ([\w\s]+) \s =+$/x;
121             my $section = $1;
122             $info->{memories} = _parseMemorySection($section, $handle)
123             if $section =~ /Memory/;
124             $info->{slots} = _parseSlotsSection($section, $handle)
125             if $section =~ /(IO|Slots)/;
126             }
127             close $handle;
128              
129             return $info;
130             }
131              
132             sub _parseMemorySection {
133 21     21   30 my ($section, $handle) = @_;
134              
135 21         19 my ($offset, $callback);
136              
137             SWITCH: {
138 21 100       22 if ($section eq 'Physical Memory Configuration') {
  21         39  
139 3         5 my $i = 0;
140 3         5 $offset = 5;
141             $callback = sub {
142 12     12   11 my ($line) = @_;
143 12 50       70 return unless $line =~ qr/
144             (\d+ \s [MG]B) \s+
145             \S+
146             $/x;
147             return {
148 12         32 NUMSLOTS => $i++,
149             CAPACITY => getCanonicalSize($1)
150             };
151 3         15 };
152 3         6 last SWITCH;
153             }
154              
155 18 100       33 if ($section eq 'Memory Configuration') {
156             # use next line to determine actual format
157 9         13 my $next_line = <$handle>;
158              
159             # Skip next line if empty
160 9 100       32 $next_line = <$handle> if ($next_line =~ /^\s*$/);
161              
162 9 100       37 if ($next_line =~ /^Segment Table/) {
    100          
163             # multi-table format: reach bank table
164 4         13 while ($next_line = <$handle>) {
165 26 100       52 last if $next_line =~ /^Bank Table/;
166             }
167              
168             # then parse using callback
169 4         27 my $i = 0;
170 4         3 $offset = 4;
171             $callback = sub {
172 18     18   14 my ($line) = @_;
173 18 50       91 return unless $line =~ qr/
174             \d+ \s+
175             \S+ \s+
176             \S+ \s+
177             (\d+ [MG]B)
178             /x;
179             return {
180 18         43 NUMSLOTS => $i++,
181             CAPACITY => getCanonicalSize($1)
182             };
183 4         13 };
184             } elsif ($next_line =~ /Memory\s+Available\s+Memory\s+DIMM\s+# of/) {
185             # single-table format: start using callback directly
186 2         3 my $i = 0;
187 2         3 $offset = 2;
188             $callback = sub {
189 4     4   6 my ($line) = @_;
190 4 50       30 return unless $line =~ qr/
191             \d+ [MG]B \s+
192             \S+ \s+
193             (\d+ [MG]B) \s+
194             (\d+) \s+
195             /x;
196 4         16 return map { {
197 64         100 NUMSLOTS => $i++,
198             CAPACITY => getCanonicalSize($1)
199             } } 1..$2;
200 2         9 };
201             } else {
202             # single-table format: start using callback directly
203 3         6 my $i = 0;
204 3         3 $offset = 3;
205             $callback = sub {
206 96     96   81 my ($line) = @_;
207 96 50       472 return unless $line =~ qr/
208             (\d+ [MG]B) \s+
209             \S+ \s+
210             (\d+ [MG]B) \s+
211             \S+ \s+
212             /x;
213 96         169 my $dimmsize = getCanonicalSize($2);
214 96         140 my $logicalsize = getCanonicalSize($1);
215             # Compute DIMM count from "Logical Bank Size" and "DIMM Size"
216 96 50 33     297 my $dimmcount = ( $dimmsize && $dimmsize != $logicalsize ) ?
217             int($logicalsize/$dimmsize) : 1 ;
218 96         98 return map { {
219 192         622 NUMSLOTS => $i++,
220             CAPACITY => $dimmsize
221             } } 1..$dimmcount;
222 3         13 };
223             }
224              
225 9         15 last SWITCH;
226             }
227              
228 9 50       19 if ($section eq 'Memory Device Sockets') {
229 9         12 my $i = 0;
230 9         7 $offset = 3;
231             $callback = sub {
232 264     264   186 my ($line) = @_;
233 264 100       823 return unless $line =~ qr/^
234             (\w+) \s+
235             in \s use \s+
236             \d \s+
237             \w+ (?:\s \w+)*
238             /x;
239             return {
240 78         205 NUMSLOTS => $i++,
241             TYPE => $1
242             };
243 9         36 };
244 9         14 last SWITCH;
245             }
246              
247 0         0 return;
248             }
249              
250 21         36 return _parseAnySection($handle, $offset, $callback);
251             }
252              
253             sub _parseSlotsSection {
254 21     21   25 my ($section, $handle) = @_;
255              
256 21         13 my ($offset, $callback);
257              
258             SWITCH: {
259 21 100       20 if ($section eq 'IO Devices') {
  21         37  
260 7         9 $offset = 3;
261             $callback = sub {
262 62     62   41 my ($line) = @_;
263 62 100       128 return unless $line =~ /^
264             (\S+) \s+
265             ([A-Z]+) \s+
266             (\S+)
267             /x;
268             return {
269 27         76 NAME => $1,
270             DESCRIPTION => $2,
271             DESIGNATION => $3,
272             };
273 7         25 };
274 7         9 last SWITCH;
275             }
276              
277 14 100       26 if ($section eq 'IO Cards') {
278 5         5 $offset = 7;
279             $callback = sub {
280 25     25   22 my ($line) = @_;
281 25 100       64 return unless $line =~ /^
282             \S+ \s+
283             ([A-Z]+) \s+
284             \S+ \s+
285             \S+ \s+
286             (\d) \s+
287             \S+ \s+
288             \S+ \s+
289             \S+ \s+
290             \S+ \s+
291             (\S+)
292             /x;
293             return {
294 15         43 NAME => $2,
295             DESCRIPTION => $1,
296             DESIGNATION => $3,
297             };
298 5         16 };
299 5         8 last SWITCH;
300             }
301              
302 9 50       16 if ($section eq 'Upgradeable Slots') {
303 9         9 $offset = 3;
304             # use a column-based strategy, as most values include spaces
305             $callback = sub {
306 33     33   28 my ($line) = @_;
307              
308 33         38 my $name = substr($line, 0, 1);
309 33         29 my $status = substr($line, 4, 9);
310 33         28 my $description = substr($line, 14, 16);
311 33         29 my $designation = substr($line, 31, 28);
312              
313 33         48 $status =~ s/\s+$//;
314 33         56 $description =~ s/\s+$//;
315 33         44 $designation =~ s/\s+$//;
316              
317 33 100       62 $status =
    100          
318             $status eq 'in use' ? 'used' :
319             $status eq 'available' ? 'free' :
320             undef;
321              
322             return {
323 33         82 NAME => $name,
324             STATUS => $status,
325             DESCRIPTION => $description,
326             DESIGNATION => $designation,
327             };
328 9         27 };
329 9         15 last SWITCH;
330             }
331              
332 0         0 return;
333             };
334              
335 21         27 return _parseAnySection($handle, $offset, $callback);
336             }
337              
338             sub _parseAnySection {
339 42     42   43 my ($handle, $offset, $callback) = @_;
340              
341             # skip headers
342 42         71 foreach my $i (1 .. $offset) {
343 154         178 <$handle>;
344             }
345              
346             # parse content
347 42         39 my @items;
348 42         91 while (my $line = <$handle>) {
349 547 100       825 last if $line =~ /^$/;
350 514         335 chomp $line;
351 514         481 my @item = $callback->($line);
352 514 100       1402 push @items, @item if @item;
353             }
354              
355 42         247 return \@items;
356             }
357              
358             sub getReleaseInfo {
359             my (%params) = (
360             file => '/etc/release',
361             @_
362             );
363              
364             my $first_line = getFirstLine(
365             file => $params{file},
366             logger => $params{logger},
367             );
368              
369             my ($fullname) =
370             $first_line =~ /^ \s+ (.+)/x;
371             my ($version, $date, $id) =
372             $fullname =~ /Solaris \s ([\d.]+) \s (?: (\d+\/\d+) \s)? (\S+)/x;
373             my ($subversion) = $id =~ /_(u\d+)/;
374              
375             return {
376             fullname => $fullname,
377             version => $version,
378             subversion => $subversion,
379             date => $date,
380             id => $id
381             };
382             }
383              
384             1;
385             __END__