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   14009332 use strict;
  15         30  
  15         422  
4 15     15   78 use warnings;
  15         38  
  15         496  
5 15     15   82 use base 'Exporter';
  15         96  
  15         1466  
6              
7 15     15   911 use English qw(-no_match_vars);
  15         4364  
  15         140  
8              
9 15     15   8935 use FusionInventory::Agent::Tools;
  15         32  
  15         2911  
10 15     15   82 use Memoize;
  15         34  
  15         35054  
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 87875 my (%params) = (
31             command => '/usr/sbin/prtconf -vp',
32             @_
33             );
34              
35 3         15 my $handle = getFileHandle(%params);
36 3 50       10 return unless $handle;
37              
38 3         6 my $info = {};
39              
40             # a stack of nodes, as a list of couples [ node, level ]
41 3         9 my @parents = (
42             [ $info, -1 ]
43             );
44              
45 3         121 while (my $line = <$handle>) {
46 2833         3426 chomp $line;
47              
48             # new node
49 2833 100       6164 if ($line =~ /^(\s*)Node \s 0x[a-f\d]+/x) {
50 293 50       742 my $level = defined $1 ? length($1) : 0;
51              
52 293         375 my $parent_level = $parents[-1]->[1];
53              
54             # compare level with parent
55 293 100       640 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         69 while ($level <= $parents[-1]->[1]) {
60 71         164 pop @parents;
61             }
62             } else {
63             # same level: unstack last node
64 217         259 pop @parents;
65             }
66              
67             # push a new node on the stack
68 293         609 push (@parents, [ {}, $level ]);
69              
70 293         1134 next;
71             }
72              
73 2540 100       5341 if ($line =~ /^\s* name: \s+ '(\S.*)'$/x) {
74 293         381 my $node = $parents[-1]->[0];
75 293         353 my $parent = $parents[-2]->[0];
76 293         559 $parent->{$1} = $node;
77 293         1111 next;
78             }
79              
80             # value
81 2247 100       8065 if ($line =~ /^\s* (\S[^:]+): \s+ (\S.*)$/x) {
82 1877         3209 my $key = $1;
83 1877         3213 my $raw_value = $2;
84 1877         2528 my $node = $parents[-1]->[0];
85              
86 1877 100       5575 if ($raw_value =~ /^'[^']+'(?: \+ '[^']+')+$/) {
    100          
87             # list of string values
88             $node->{$key} = [
89 47         156 map { /^'([^']+)'$/; $1 }
  200         400  
  200         478  
90             split (/ \+ /, $raw_value)
91             ];
92             } elsif ($raw_value =~ /^'([^']+)'$/) {
93             # single string value
94 552         1317 $node->{$key} = $1;
95             } else {
96             # other kind of value
97 1278         2515 $node->{$key} = $raw_value;
98             }
99 1877         6153 next;
100             }
101              
102             }
103 3         114 close $handle;
104              
105 3         20 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   40 my ($section, $handle) = @_;
134              
135 21         29 my ($offset, $callback);
136              
137             SWITCH: {
138 21 100       28 if ($section eq 'Physical Memory Configuration') {
  21         61  
139 3         6 my $i = 0;
140 3         6 $offset = 5;
141             $callback = sub {
142 12     12   18 my ($line) = @_;
143 12 50       105 return unless $line =~ qr/
144             (\d+ \s [MG]B) \s+
145             \S+
146             $/x;
147             return {
148 12         51 NUMSLOTS => $i++,
149             CAPACITY => getCanonicalSize($1)
150             };
151 3         16 };
152 3         9 last SWITCH;
153             }
154              
155 18 100       50 if ($section eq 'Memory Configuration') {
156             # use next line to determine actual format
157 9         19 my $next_line = <$handle>;
158              
159             # Skip next line if empty
160 9 100       48 $next_line = <$handle> if ($next_line =~ /^\s*$/);
161              
162 9 100       45 if ($next_line =~ /^Segment Table/) {
    100          
163             # multi-table format: reach bank table
164 4         18 while ($next_line = <$handle>) {
165 26 100       90 last if $next_line =~ /^Bank Table/;
166             }
167              
168             # then parse using callback
169 4         47 my $i = 0;
170 4         8 $offset = 4;
171             $callback = sub {
172 18     18   29 my ($line) = @_;
173 18 50       131 return unless $line =~ qr/
174             \d+ \s+
175             \S+ \s+
176             \S+ \s+
177             (\d+ [MG]B)
178             /x;
179             return {
180 18         69 NUMSLOTS => $i++,
181             CAPACITY => getCanonicalSize($1)
182             };
183 4         16 };
184             } elsif ($next_line =~ /Memory\s+Available\s+Memory\s+DIMM\s+# of/) {
185             # single-table format: start using callback directly
186 2         4 my $i = 0;
187 2         3 $offset = 2;
188             $callback = sub {
189 4     4   7 my ($line) = @_;
190 4 50       40 return unless $line =~ qr/
191             \d+ [MG]B \s+
192             \S+ \s+
193             (\d+ [MG]B) \s+
194             (\d+) \s+
195             /x;
196 4         21 return map { {
197 64         171 NUMSLOTS => $i++,
198             CAPACITY => getCanonicalSize($1)
199             } } 1..$2;
200 2         12 };
201             } else {
202             # single-table format: start using callback directly
203 3         7 my $i = 0;
204 3         6 $offset = 3;
205             $callback = sub {
206 96     96   142 my ($line) = @_;
207 96 50       738 return unless $line =~ qr/
208             (\d+ [MG]B) \s+
209             \S+ \s+
210             (\d+ [MG]B) \s+
211             \S+ \s+
212             /x;
213 96         305 my $dimmsize = getCanonicalSize($2);
214 96         292 my $logicalsize = getCanonicalSize($1);
215             # Compute DIMM count from "Logical Bank Size" and "DIMM Size"
216 96 50 33     485 my $dimmcount = ( $dimmsize && $dimmsize != $logicalsize ) ?
217             int($logicalsize/$dimmsize) : 1 ;
218 96         165 return map { {
219 192         623 NUMSLOTS => $i++,
220             CAPACITY => $dimmsize
221             } } 1..$dimmcount;
222 3         17 };
223             }
224              
225 9         21 last SWITCH;
226             }
227              
228 9 50       28 if ($section eq 'Memory Device Sockets') {
229 9         14 my $i = 0;
230 9         15 $offset = 3;
231             $callback = sub {
232 264     264   341 my ($line) = @_;
233 264 100       1445 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         357 NUMSLOTS => $i++,
241             TYPE => $1
242             };
243 9         39 };
244 9         21 last SWITCH;
245             }
246              
247 0         0 return;
248             }
249              
250 21         60 return _parseAnySection($handle, $offset, $callback);
251             }
252              
253             sub _parseSlotsSection {
254 21     21   44 my ($section, $handle) = @_;
255              
256 21         32 my ($offset, $callback);
257              
258             SWITCH: {
259 21 100       24 if ($section eq 'IO Devices') {
  21         61  
260 7         13 $offset = 3;
261             $callback = sub {
262 62     62   95 my ($line) = @_;
263 62 100       217 return unless $line =~ /^
264             (\S+) \s+
265             ([A-Z]+) \s+
266             (\S+)
267             /x;
268             return {
269 27         139 NAME => $1,
270             DESCRIPTION => $2,
271             DESIGNATION => $3,
272             };
273 7         27 };
274 7         17 last SWITCH;
275             }
276              
277 14 100       39 if ($section eq 'IO Cards') {
278 5         10 $offset = 7;
279             $callback = sub {
280 25     25   39 my ($line) = @_;
281 25 100       107 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         78 NAME => $2,
295             DESCRIPTION => $1,
296             DESIGNATION => $3,
297             };
298 5         31 };
299 5         11 last SWITCH;
300             }
301              
302 9 50       26 if ($section eq 'Upgradeable Slots') {
303 9         14 $offset = 3;
304             # use a column-based strategy, as most values include spaces
305             $callback = sub {
306 33     33   49 my ($line) = @_;
307              
308 33         66 my $name = substr($line, 0, 1);
309 33         55 my $status = substr($line, 4, 9);
310 33         63 my $description = substr($line, 14, 16);
311 33         57 my $designation = substr($line, 31, 28);
312              
313 33         77 $status =~ s/\s+$//;
314 33         98 $description =~ s/\s+$//;
315 33         77 $designation =~ s/\s+$//;
316              
317 33 100       97 $status =
    100          
318             $status eq 'in use' ? 'used' :
319             $status eq 'available' ? 'free' :
320             undef;
321              
322             return {
323 33         156 NAME => $name,
324             STATUS => $status,
325             DESCRIPTION => $description,
326             DESIGNATION => $designation,
327             };
328 9         37 };
329 9         19 last SWITCH;
330             }
331              
332 0         0 return;
333             };
334              
335 21         47 return _parseAnySection($handle, $offset, $callback);
336             }
337              
338             sub _parseAnySection {
339 42     42   76 my ($handle, $offset, $callback) = @_;
340              
341             # skip headers
342 42         89 foreach my $i (1 .. $offset) {
343 154         374 <$handle>;
344             }
345              
346             # parse content
347 42         92 my @items;
348 42         140 while (my $line = <$handle>) {
349 547 100       1332 last if $line =~ /^$/;
350 514         615 chomp $line;
351 514         967 my @item = $callback->($line);
352 514 100       2485 push @items, @item if @item;
353             }
354              
355 42         336 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__