File Coverage

blib/lib/Parse/Arcconf.pm
Criterion Covered Total %
statement 14 95 14.7
branch 1 58 1.7
condition 0 3 0.0
subroutine 4 6 66.6
pod 4 4 100.0
total 23 166 13.8


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2              
3             # Copyright 2012 Mathieu Alorent.
4             #
5             # This program is free software; you can redistribute it and/or modify it
6             # under the terms of either: the GNU General Public License as published
7             # by the Free Software Foundation; or the Artistic License.
8             #
9             # See http://dev.perl.org/licenses/ for more information.
10              
11             package Parse::Arcconf;
12              
13 2     2   23091 use warnings;
  2         4  
  2         50  
14 2     2   9 use strict;
  2         2  
  2         2558  
15              
16             =head1 NAME
17              
18             Parse::Arcconf - Parse the output of arcconf utility.
19              
20             =head1 VERSION
21              
22             Version 0.01
23              
24             =cut
25              
26             our $VERSION = '0.03';
27              
28             =head1 SYNOPSIS
29              
30             Parse::Arcconf parses the output of C utility to allow
31             programmatic access to the RAID configuration information provided by the
32             arcconf utility on Adaptec RAID cards.
33              
34             use Parse::Arcconf;
35              
36             my $arcconf = Parse::Arcconf->new();
37              
38             Run the C tool directly to query the hardware (requires root):
39              
40             my $controllers = $arcconf->parse_config();
41            
42             Parse a text file created already by running C tool:
43              
44             my $controllers = $arcconf->parse_config_file("foo.txt");
45              
46             Read from a file descriptor already opened by the program:
47              
48             my $controllers = $arcconf->parse_config_fh(\*STDIN);
49              
50             =head1 SUBROUTINES/METHODS
51              
52             =head2 new
53              
54             Return an instance of the Parse::Arcconf class that can be used to parse
55             input in one of several ways.
56              
57             =cut
58              
59             sub new
60             {
61 1     1 1 10 my ($class, $config, $plugin) = @_;
62 1         2 my $self = {};
63              
64 1         2 bless($self, $class);
65 1         4 return $self;
66             }
67              
68             =head2 parse_config
69              
70             Attempt to run the arcconf utility, and parse the output. This command
71             actually uses parse_config_fh() after opening a pipe to the relevant command.
72              
73             The command that is actually run is approximately:
74              
75             =over 4
76              
77             arcconf GETCONFIG 1
78              
79             =back
80              
81             This command requires root access, and Parse::Arcconf makes no attempt to
82             use sudo or any other method to gain root access. It is recommended to call
83             your script which uses this module as root.
84              
85             The parse_config_fh() and parse_config_file() will expect output equivalent
86             to that from the above command.
87              
88             =cut
89              
90             sub parse_config
91             {
92 0     0 1 0 my ($self) = @_;
93              
94 0         0 my $arcconf = "/usr/sbin/arcconf";
95 0         0 my $argument = "GETCONFIG 1";
96 0         0 my $command = sprintf("%s %s|", $arcconf, $argument);
97              
98 0         0 my $fh;
99 0 0       0 if(open $fh, $command)
100             {
101 0         0 my $c = $self->parse_config_fh($fh);
102 0         0 close $fh;
103 0         0 return $c;
104             }
105 0         0 return undef;
106             }
107              
108             =head2 parse_config_file
109              
110             Open and parse a file containing the output from arcconf.
111              
112             =cut
113              
114             sub parse_config_file
115             {
116 1     1 1 6 my ($self, $file) = @_;
117              
118 1         2 my $fh;
119 1 50       27 if(open $fh, "<".$file)
120             {
121 0         0 my $c = $self->parse_config_fh($fh);
122 0         0 close $fh;
123 0         0 return $c;
124             }
125 1         4 return undef;
126              
127             }
128              
129             =head2 parse_config_fh
130              
131             Read from the file handle and parse it, returning a hash-of-hashes.
132              
133             =cut
134              
135             sub parse_config_fh
136             {
137 0     0 1   my ($self, $fh) = @_;
138              
139 0           my $controller = {};
140 0           my $total_controller = 0;
141 0           my $current_controller = 0;
142 0           my $current_logical_drive = undef;
143 0           my $current_physical_drive = undef;
144 0           my $ctrl = undef;
145 0           my $line = undef;
146              
147 0           LEVEL1: while($line = <$fh>)
148             {
149 0           chomp $line;
150              
151 0 0         next if($line =~ /^$/);
152 0 0         next if($line =~ /^-+$/);
153              
154 0 0         if($line =~ /^Controllers found: (\d+)$/) {
155 0           $total_controller = $1;
156             }
157              
158 0 0         if($line =~ /^Controller information/) {
159 0           $current_controller = $current_controller + 1;
160 0           $current_logical_drive = undef;
161 0           $current_physical_drive = undef;
162 0           $controller->{$current_controller} = {};
163 0           $ctrl = $controller->{$current_controller};
164              
165 0           while($line = <$fh>) {
166 0           chomp $line;
167              
168 0 0         if ($line =~ /^\s+(.*\w)\s+:\s+(.*)$/) {
    0          
169 0           $ctrl->{$1} = $2;
170             } elsif ($line =~ /^\s+-+$/) {
171 0           last;
172             }
173             }
174              
175 0           LEVEL2: while($line = <$fh>) {
176 0 0         if ($line =~ /^\s+-+$/) {
177 0           $line = <$fh>;
178 0           chomp $line;
179             }
180 0 0         if($line =~ /^\s+(.*\w)\s*/) {
181 0           my $cat = $1;
182 0           $line = <$fh>;
183 0           LEVEL3: while($line = <$fh>) {
184 0           chomp $line;
185              
186 0 0         if ($line =~ /^\s+(.*\w)\s+:\s+(.*)$/) {
    0          
    0          
187 0           $ctrl->{$cat}{$1} = $2;
188             } elsif ($line =~ /^\s+-+$/) {
189 0           last LEVEL3;
190             } elsif ($line =~ /^$/) {
191 0           last LEVEL2;
192             }
193             }
194             }
195             }
196             }
197              
198 0 0         next if(!defined($current_controller));
199              
200 0 0 0       if($line =~ /^Logical drive information/ or $line =~ /^Logical device information/) {
201 0           LEVEL4: while($line = <$fh>) {
202 0           chomp $line;
203              
204 0 0         if ($line =~ /^\S+.*\w\s+(\d+)$/) {
    0          
    0          
205 0           $current_logical_drive = $1;
206             } elsif ($line =~ /^\s+(\S.*\S+)\s+:\s+(.*)$/) {
207 0           $ctrl->{'logical drive'}{$current_logical_drive}{$1} = $2;
208             } elsif ($line =~ /^\s+-+$/) {
209 0           my $cat = <$fh>;
210 0           $cat =~ s/^\s+(\S.*\S+)\s+/$1/;
211 0           chomp $cat;
212 0           LEVEL5: while($line = <$fh>) {
213 0           chomp $line;
214              
215 0 0         if ($line =~ /^\s+(\S.*\S+)\s+:\s+(.*)$/) {
    0          
    0          
    0          
216 0           $ctrl->{'logical drive'}{$current_logical_drive}{$cat}{$1} = $2;
217             } elsif ($line =~ /^\S+.*\w\s+(\d+)$/) {
218 0           $current_logical_drive = $1;
219 0           last LEVEL5;
220             } elsif ($line =~ /^-+$/) {
221 0           last LEVEL4;
222             } elsif ($line =~ /^\s+-+$/) {
223 0           next;
224             }
225             }
226             }
227             }
228             }
229              
230 0 0         if($line =~ /^Physical Device information/) {
231              
232 0           LEVEL2: while($line = <$fh>) {
233 0 0         if ($line =~ /^\s+-+$/) {
234 0           $line = <$fh>;
235 0           chomp $line;
236             }
237 0 0         if ($line =~ /^\s+Device\s+#(\d+)$/) {
    0          
    0          
    0          
    0          
238 0           $current_physical_drive = $1;
239             } elsif ($line =~ /^\s+Device is (.*\w)/) {
240 0           $ctrl->{'physical drive'}{$current_physical_drive}{'Device is'} = $1;
241             } elsif ($line =~ /^\s+(.*\w)\s+:\s+(.*)$/) {
242 0           $ctrl->{'physical drive'}{$current_physical_drive}{$1} = $2;
243             } elsif ($line =~ /^\s+-+$/) {
244 0           last LEVEL3;
245             } elsif ($line =~ /^$/) {
246 0           last LEVEL2;
247             }
248             }
249             }
250              
251             }
252            
253 0           return $controller;
254             }
255              
256             =head1 AUTHOR
257              
258             Mathieu Alorent, C<< >>
259              
260             =head1 BUGS
261              
262             Please report any bugs or feature requests to C, or through
263             the web interface at L. I will be notified, and then you'll
264             automatically be notified of progress on your bug as I make changes.
265              
266             =head1 SUPPORT
267              
268             You can find documentation for this module with the perldoc command.
269              
270             perldoc Parse::Arcconf
271              
272              
273             You can also look for information at:
274              
275             =over 4
276              
277             =item * Source code
278              
279             L
280              
281             =item * RT: CPAN's request tracker
282              
283             L
284              
285             =item * AnnoCPAN: Annotated CPAN documentation
286              
287             L
288              
289             =item * CPAN Ratings
290              
291             L
292              
293             =item * Search CPAN
294              
295             L
296              
297             =back
298              
299              
300             =head1 ACKNOWLEDGEMENTS
301              
302              
303             =head1 LICENSE AND COPYRIGHT
304              
305             Copyright 2012 Mathieu Alorent.
306              
307             This program is free software; you can redistribute it and/or modify it
308             under the terms of either: the GNU General Public License as published
309             by the Free Software Foundation; or the Artistic License.
310              
311             See http://dev.perl.org/licenses/ for more information.
312              
313             This program is based on Parse::HP::ACU a work of Jeremy Cole.
314              
315              
316             =cut
317              
318             1; # End of Parse::Arcconf