File Coverage

blib/lib/FusionInventory/Agent/Tools/Solaris.pm
Criterion Covered Total %
statement 18 134 13.4
branch 0 54 0.0
condition n/a
subroutine 6 17 35.2
pod 1 1 100.0
total 25 206 12.1


line stmt bran cond sub pod time code
1             package FusionInventory::Agent::Tools::Solaris;
2              
3 9     9   10854656 use strict;
  9         22  
  9         406  
4 9     9   61 use warnings;
  9         20  
  9         405  
5 9     9   51 use base 'Exporter';
  9         46  
  9         1068  
6              
7 9     9   49 use English qw(-no_match_vars);
  9         11  
  9         85  
8              
9 9     9   4968 use FusionInventory::Agent::Tools;
  9         15  
  9         1501  
10 9     9   51 use Memoize;
  9         13  
  9         19114  
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 0     0 1   my (%params) = (
31             command => '/usr/sbin/prtconf -vp',
32             @_
33             );
34              
35 0           my $handle = getFileHandle(%params);
36 0 0         return unless $handle;
37              
38 0           my $info = {};
39              
40             # a stack of nodes, as a list of couples [ node, level ]
41 0           my @parents = (
42             [ $info, -1 ]
43             );
44              
45 0           while (my $line = <$handle>) {
46 0           chomp $line;
47              
48             # new node
49 0 0         if ($line =~ /^(\s*)Node \s 0x[a-f\d]+/x) {
50 0 0         my $level = defined $1 ? length($1) : 0;
51              
52 0           my $parent_level = $parents[-1]->[1];
53              
54             # compare level with parent
55 0 0         if ($level > $parent_level) {
    0          
56             # down the tree: no change
57             } elsif ($level < $parent_level) {
58             # up the tree: unstack nodes until a suitable parent is found
59 0           while ($level <= $parents[-1]->[1]) {
60 0           pop @parents;
61             }
62             } else {
63             # same level: unstack last node
64 0           pop @parents;
65             }
66              
67             # push a new node on the stack
68 0           push (@parents, [ {}, $level ]);
69              
70 0           next;
71             }
72              
73 0 0         if ($line =~ /^\s* name: \s+ '(\S.*)'$/x) {
74 0           my $node = $parents[-1]->[0];
75 0           my $parent = $parents[-2]->[0];
76 0           $parent->{$1} = $node;
77 0           next;
78             }
79              
80             # value
81 0 0         if ($line =~ /^\s* (\S[^:]+): \s+ (\S.*)$/x) {
82 0           my $key = $1;
83 0           my $raw_value = $2;
84 0           my $node = $parents[-1]->[0];
85              
86 0 0         if ($raw_value =~ /^'[^']+'(?: \+ '[^']+')+$/) {
    0          
87             # list of string values
88 0           $node->{$key} = [
89 0           map { /^'([^']+)'$/; $1 }
  0            
90             split (/ \+ /, $raw_value)
91             ];
92             } elsif ($raw_value =~ /^'([^']+)'$/) {
93             # single string value
94 0           $node->{$key} = $1;
95             } else {
96             # other kind of value
97 0           $node->{$key} = $raw_value;
98             }
99 0           next;
100             }
101              
102             }
103 0           close $handle;
104              
105 0           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 0     0     my ($section, $handle) = @_;
134              
135 0           my ($offset, $callback);
136              
137             SWITCH: {
138 0 0         if ($section eq 'Physical Memory Configuration') {
  0            
139 0           my $i = 0;
140 0           $offset = 5;
141             $callback = sub {
142 0     0     my ($line) = @_;
143 0 0         return unless $line =~ qr/
144             (\d+ \s [MG]B) \s+
145             \S+
146             $/x;
147             return {
148 0           NUMSLOTS => $i++,
149             CAPACITY => getCanonicalSize($1)
150             };
151 0           };
152 0           last SWITCH;
153             }
154              
155 0 0         if ($section eq 'Memory Configuration') {
156             # use next line to determine actual format
157 0           my $next_line = <$handle>;
158              
159 0 0         if ($next_line =~ /^Segment Table/) {
160             # multi-table format: reach bank table
161 0           while ($next_line = <$handle>) {
162 0 0         last if $next_line =~ /^Bank Table/;
163             }
164              
165             # then parse using callback
166 0           my $i = 0;
167 0           $offset = 4;
168             $callback = sub {
169 0     0     my ($line) = @_;
170 0 0         return unless $line =~ qr/
171             \d+ \s+
172             \S+ \s+
173             \S+ \s+
174             (\d+ [MG]B)
175             /x;
176             return {
177 0           NUMSLOTS => $i++,
178             CAPACITY => getCanonicalSize($1)
179             };
180 0           };
181             } else {
182             # single-table format: start using callback directly
183 0           my $i = 0;
184 0           $offset = 4;
185             $callback = sub {
186 0     0     my ($line) = @_;
187 0 0         return unless $line =~ qr/
188             (\d+ [MG]B) \s+
189             \S+ \s+
190             (\d+ [MG]B) \s+
191             \S+ \s+
192             \d
193             $/x;
194             return {
195 0           NUMSLOTS => $i++,
196             CAPACITY => getCanonicalSize($1)
197             };
198 0           };
199             }
200              
201 0           last SWITCH;
202             }
203              
204 0 0         if ($section eq 'Memory Device Sockets') {
205 0           my $i = 0;
206 0           $offset = 3;
207             $callback = sub {
208 0     0     my ($line) = @_;
209 0 0         return unless $line =~ qr/^
210             (\w+) \s+
211             in \s use \s+
212             \d \s+
213             \w+ (?:\s \w+)*
214             /x;
215             return {
216 0           NUMSLOTS => $i++,
217             TYPE => $1
218             };
219 0           };
220 0           last SWITCH;
221             }
222              
223 0           return;
224             }
225              
226 0           return _parseAnySection($handle, $offset, $callback);
227             }
228              
229             sub _parseSlotsSection {
230 0     0     my ($section, $handle) = @_;
231              
232 0           my ($offset, $callback);
233              
234             SWITCH: {
235 0 0         if ($section eq 'IO Devices') {
  0            
236 0           $offset = 3;
237             $callback = sub {
238 0     0     my ($line) = @_;
239 0 0         return unless $line =~ /^
240             (\S+) \s+
241             ([A-Z]+) \s+
242             (\S+)
243             /x;
244             return {
245 0           NAME => $1,
246             DESCRIPTION => $2,
247             DESIGNATION => $3,
248             };
249 0           };
250 0           last SWITCH;
251             }
252              
253 0 0         if ($section eq 'IO Cards') {
254 0           $offset = 7;
255             $callback = sub {
256 0     0     my ($line) = @_;
257 0 0         return unless $line =~ /^
258             \S+ \s+
259             ([A-Z]+) \s+
260             \S+ \s+
261             \S+ \s+
262             (\d) \s+
263             \S+ \s+
264             \S+ \s+
265             \S+ \s+
266             \S+ \s+
267             (\S+)
268             /x;
269             return {
270 0           NAME => $2,
271             DESCRIPTION => $1,
272             DESIGNATION => $3,
273             };
274 0           };
275 0           last SWITCH;
276             }
277              
278 0 0         if ($section eq 'Upgradeable Slots') {
279 0           $offset = 3;
280             # use a column-based strategy, as most values include spaces
281             $callback = sub {
282 0     0     my ($line) = @_;
283              
284 0           my $name = substr($line, 0, 1);
285 0           my $status = substr($line, 4, 9);
286 0           my $description = substr($line, 14, 16);
287 0           my $designation = substr($line, 31, 28);
288              
289 0           $status =~ s/\s+$//;
290 0           $description =~ s/\s+$//;
291 0           $designation =~ s/\s+$//;
292              
293 0 0         $status =
    0          
294             $status eq 'in use' ? 'used' :
295             $status eq 'available' ? 'free' :
296             undef;
297              
298             return {
299 0           NAME => $name,
300             STATUS => $status,
301             DESCRIPTION => $description,
302             DESIGNATION => $designation,
303             };
304 0           };
305 0           last SWITCH;
306             }
307              
308 0           return;
309             };
310              
311 0           return _parseAnySection($handle, $offset, $callback);
312             }
313              
314             sub _parseAnySection {
315 0     0     my ($handle, $offset, $callback) = @_;
316              
317             # skip headers
318 0           foreach my $i (1 .. $offset) {
319 0           <$handle>;
320             }
321              
322             # parse content
323 0           my @items;
324 0           while (my $line = <$handle>) {
325 0 0         last if $line =~ /^$/;
326 0           chomp $line;
327 0           my $item = $callback->($line);
328 0 0         push @items, $item if $item;
329             }
330              
331 0           return \@items;
332             }
333              
334             sub getReleaseInfo {
335             my (%params) = (
336             file => '/etc/release',
337             @_
338             );
339              
340             my $first_line = getFirstLine(
341             file => $params{file},
342             logger => $params{logger},
343             );
344              
345             my ($fullname) =
346             $first_line =~ /^ \s+ (.+)/x;
347             my ($version, $date, $id) =
348             $fullname =~ /Solaris \s ([\d.]+) \s (?: (\d+\/\d+) \s)? (\S+)/x;
349             my ($subversion) = $id =~ /_(u\d+)/;
350              
351             return {
352             fullname => $fullname,
353             version => $version,
354             subversion => $subversion,
355             date => $date,
356             id => $id
357             };
358             }
359              
360             1;
361             __END__