File Coverage

blib/lib/Sys/Info/Driver/Linux/OS/Distribution.pm
Criterion Covered Total %
statement 128 191 67.0
branch 25 80 31.2
condition 10 47 21.2
subroutine 28 29 96.5
pod 9 9 100.0
total 200 356 56.1


line stmt bran cond sub pod time code
1             package Sys::Info::Driver::Linux::OS::Distribution;
2 2     2   45201 use strict;
  2         4  
  2         88  
3 2     2   12 use warnings;
  2         5  
  2         80  
4 2     2   12 use constant STD_RELEASE => 'lsb-release';
  2         5  
  2         150  
5 2     2   12 use constant STD_RELEASE_DIR => 'lsb-release.d';
  2         5  
  2         100  
6 2     2   10 use constant DEBIAN_RELEASE => 'os-release';
  2         5  
  2         97  
7 2     2   206 use constant STD_ETC_DIR => '/etc';
  2         5  
  2         106  
8              
9 2     2   10 use base qw( Sys::Info::Base );
  2         5  
  2         1706  
10 2     2   17778 use Carp qw( croak );
  2         5  
  2         128  
11 2     2   737 use Sys::Info::Driver::Linux;
  2         4  
  2         101  
12 2     2   611 use Sys::Info::Driver::Linux::Constants qw( :all );
  2         5  
  2         408  
13 2     2   1601 use Sys::Info::Driver::Linux::OS::Distribution::Conf;
  2         11  
  2         420  
14 2     2   28 use File::Spec;
  2         3  
  2         6018  
15              
16             our $VERSION = '0.7903';
17              
18             # XXX:
19             my $RELX = sub {
20             my $master = shift;
21             my $t = sub {
22             my($k, $v) = @_;
23             return map { $_ => $v} ref $k ? @{$k} : ($k);
24             };
25             map { $t->($CONF{$_}->{$master}, $_ ) }
26             grep { $CONF{$_}->{$master} }
27             keys %CONF
28             };
29              
30             my %ORIGINAL_RELEASE = $RELX->('release');
31             my %DERIVED_RELEASE = $RELX->('release_derived');
32             #
33              
34             sub new {
35 2     2 1 25 my $class = shift;
36 2         5 my %option;
37 2 50       12 if ( @_ ) {
38 0 0       0 die "Parameters must be in name => value format" if @_ % 2;
39 0         0 %option = @_;
40             }
41              
42 2         33 my $self = {
43             DISTRIB_ID => q{},
44             DISTRIB_NAME => q{}, # workround field for new distros
45             DISTRIB_RELEASE => q{},
46             DISTRIB_CODENAME => q{},
47             DISTRIB_DESCRIPTION => q{},
48             release_file => q{},
49             pattern => q{},
50             PROBE => undef,
51             RESULTS => undef,
52             etc_dir => STD_ETC_DIR,
53             %option,
54             };
55              
56 2         22 $self->{etc_dir} =~ s{[/]+$}{}xms;
57              
58 2         11 bless $self, $class;
59 2         11 $self->_initial_probe;
60 2         17 return $self;
61             }
62              
63 3     3 1 12 sub raw_name { return shift->{RESULTS}{raw_name} }
64 6     6 1 99 sub name { return shift->{RESULTS}{name} }
65 4     4 1 16 sub version { return shift->{RESULTS}{version} }
66 1     1 1 4 sub edition { return shift->{RESULTS}{edition} }
67 1     1 1 4 sub kernel { return shift->{PROBE}{kernel} }
68 1     1 1 5 sub build { return shift->{PROBE}{build} }
69 1     1 1 4 sub build_date { return shift->{PROBE}{build_date} }
70             sub manufacturer {
71 1     1 1 2 my $self = shift;
72 1   50     2 my $slot = $CONF{ lc $self->raw_name } || return;
73 1 50       4 return if ! exists $slot->{manufacturer};
74 1         5 return $slot->{manufacturer};
75             }
76              
77             sub _probe {
78 2     2   5 my $self = shift;
79 2 50       13 return $self->{RESULTS} if $self->{RESULTS};
80 2         7 $self->{RESULTS} = {};
81 2         11 $self->{RESULTS}{name} = $self->_probe_name;
82 2         8 $self->{RESULTS}{raw_name} = $self->{RESULTS}{name};
83 2         10 $self->{RESULTS}{version} = $self->_probe_version;
84             # this has to be last, since this also modifies the two above
85 2         10 $self->{RESULTS}{edition} = $self->_probe_edition;
86 2         4 return $self->{RESULTS};
87             }
88              
89             sub _probe_name {
90 2     2   4 my $self = shift;
91 2         9 my $distro = $self->_get_lsb_info;
92 2 50       88 return $distro if $distro;
93 0   0     0 return $self->_probe_release( \%DERIVED_RELEASE )
94             || $self->_probe_release( \%ORIGINAL_RELEASE );
95             }
96              
97             sub _probe_release {
98 0     0   0 my($self, $r) = @_;
99              
100 0         0 foreach my $id ( keys %{ $r } ) {
  0         0  
101 0         0 my $file = File::Spec->catfile( $self->{etc_dir}, $id );
102 0 0 0     0 if ( -f $file && ! -l $file ) {
103 0         0 $self->{DISTRIB_ID} = $r->{ $id };
104 0         0 $self->{release_file} = $id;
105 0         0 return $self->{DISTRIB_ID};
106             }
107             }
108              
109 0         0 return;
110             }
111              
112             sub _probe_version {
113 2     2   5 my $self = shift;
114 2         8 my $release = $self->_get_lsb_info('DISTRIB_RELEASE');
115 2 50       19 return $release if $release;
116              
117 0 0 0     0 if ( ! $self->{DISTRIB_ID} && ! $self->name ) {
118 0         0 croak 'No version because no distribution';
119             }
120              
121 0         0 my $slot = $CONF{ lc $self->{DISTRIB_ID} };
122 0 0       0 $self->{pattern} = exists $slot->{version_match} ? $slot->{version_match} : q{};
123 0         0 $release = $self->_get_file_info;
124 0         0 $self->{DISTRIB_RELEASE} = $release;
125 0         0 return $release;
126             }
127              
128             sub _probe_edition {
129 2     2   6 my $self = shift;
130 2         7 my $p = $self->{PROBE};
131              
132 2 50       10 if ( my $dn = $self->name ) {
133 2   33     13 my $n = $self->{DISTRIB_NAME} || do {
134             my $slot = $CONF{ $dn };
135             exists $slot->{name} ? $slot->{name} : ucfirst $dn;
136             };
137 2         14 $dn = $self->trim( $n );
138 2 50       33 $dn .= ' Linux' if $dn !~ m{Linux}xmsi;
139 2         9 $self->{RESULTS}{name} = $dn;
140             }
141             else {
142 0         0 $self->{RESULTS}{name} = $p->{distro};
143 0         0 $self->{RESULTS}{version} = $p->{kernel};
144             }
145              
146 2         7 my $name = $self->name;
147 2         11 my $raw_name = $self->raw_name;
148 2         10 my $version = $self->version;
149 2   50     11 my $slot = $CONF{$raw_name} || return;
150 2 50       12 my $edition = exists $slot->{edition} ? $slot->{edition}{ $version } : undef;
151              
152 2 50       8 if ( ! $edition ) {
153 2 50 33     20 if ( $version && $version !~ m{[0-9]}xms ) {
154 0 0       0 if ( $name =~ m{debian}xmsi ) {
155 0         0 my @buf = split m{/}xms, $version;
156 0 0       0 if ( my $test = $CONF{debian}->{vfix}{ lc $buf[0] } ) {
157             # Debian version comes as the edition name
158 0         0 $edition = $version;
159 0         0 $self->{RESULTS}{version} = $test;
160             }
161             }
162             }
163             else {
164 2 50 33     13 if ( $slot->{use_codename_for_edition}
165             && $self->{DISTRIB_CODENAME}
166             ) {
167 0         0 my $cn = $self->{DISTRIB_CODENAME};
168 0 0       0 $edition = $cn if $cn !~ m{[0-9]}xms;
169             }
170             }
171             }
172              
173 2         10 return $edition;
174             }
175              
176             sub _initial_probe {
177 2     2   6 my $self = shift;
178 2         4 my $version = q{};
179              
180 2 50 33     142 if ( -e proc->{version} && -f _) {
181 2         31 $version = $self->trim(
182             $self->slurp(
183             proc->{version},
184             'I can not open linux version file %s for reading: '
185             )
186             );
187             }
188              
189 2         485 my($str, $build_date) = split /\#/xms, $version;
190 2         7 my($kernel, $distro) = (q{},q{});
191              
192             #$build_date = "1 Fri Jul 23 20:48:29 CDT 2004';";
193             #$build_date = "1 SMP Mon Aug 16 09:25:06 EDT 2004";
194 2 50       11 $build_date = q{} if not $build_date; # running since blah thingie
195              
196 2 50 33     40 if ( $str =~ RE_LINUX_VERSION || $str =~ RE_LINUX_VERSION2 ) {
197 2         9 $kernel = $1;
198 2 50       17 if ( $distro = $self->trim( $2 ) ) {
199 2 50       45 if ( $distro =~ m{ \s\((.+?)\)\) \z }xms ) {
200 0         0 $distro = $1;
201             }
202             }
203             }
204              
205 2 50 33     21 $distro = 'Linux' if ! $distro || $distro =~ m{\(gcc}xms;
206              
207             # kernel build date
208 2 50       25 $build_date = $self->date2time($build_date) if $build_date;
209 2 50       11169 my $build = $build_date ? localtime $build_date : q{};
210              
211 2         40 $self->{PROBE} = {
212             version => $version,
213             kernel => $kernel,
214             build => $build,
215             build_date => $build_date,
216             distro => $distro,
217             };
218              
219 2         14 $self->_probe;
220 2         8 return;
221             }
222              
223             sub _get_lsb_info {
224 4     4   8 my $self = shift;
225 4   100     20 my $field = shift || 'DISTRIB_ID';
226 4         8 my $tmp = $self->{release_file};
227              
228 8         1181 my($rfile) = grep { -r $_->[1] }
  8         122  
229             map {
230 4         11 [ $_ => File::Spec->catfile( $self->{etc_dir}, $_ ) ]
231             }
232             STD_RELEASE,
233             DEBIAN_RELEASE
234             ;
235              
236 4 50       18 if ( $rfile ) {
237 4         10 $self->{release_file} = $rfile->[0];
238 4         28 $self->{pattern} = $field . '=(.+)';
239 4         13 my $info = $self->_get_file_info;
240 4 50       26 return $self->{$field} = $info if $info;
241             }
242             else {
243             # CentOS6+? RHEL? Any new distro?
244 0         0 my $dir = File::Spec->catdir( $self->{etc_dir}, STD_RELEASE_DIR );
245 0 0       0 if ( -d $dir ) {
246 0 0       0 my $rv = join q{: },
247 0         0 map { m{$dir/(.*)}xms ? $1 : () }
248 0         0 grep { $_ !~ m{ \A [.] }xms }
249             glob "$dir/*";
250 0 0       0 $self->{LSB_VERSION} = $rv if $rv;
251             }
252 0         0 my($release) = do {
253 0 0       0 if ( my @files = glob $self->{etc_dir} . "/*release" ) {
254 0         0 my($real) = sort grep { ! -l } @files;
  0         0  
255 0         0 my %uniq = map { $self->trim( $self->slurp( $_ ) ) => 1 }
  0         0  
256             @files;
257 0 0       0 if ( $real ) {
258 0         0 my $etc = $self->{etc_dir};
259 0         0 ($self->{release_file} = $real) =~ s{$etc/}{}xms;
260 0         0 $self->{pattern} = '(.+)';
261             }
262 0         0 keys %uniq;
263             }
264             };
265              
266 0 0       0 return if ! $release; # huh?
267              
268 0         0 my($rname) = split m{\-}xms, $self->{release_file};
269 0         0 my($distrib_id, @rest) = split m{release}xms, $release, 2;
270 0         0 my($version, $codename) = split m{ \s+ }xms, $self->trim( join ' ', @rest ), 2;
271 0 0       0 $codename =~ s{[()]}{}xmsg if $codename;
272 0         0 $distrib_id = $self->trim( $distrib_id );
273 0         0 $self->{DISTRIB_DESCRIPTION} = $release;
274 0   0     0 $self->{DISTRIB_ID} = $rname || $distrib_id;
275 0         0 $self->{DISTRIB_NAME} = $distrib_id;
276 0         0 $self->{DISTRIB_RELEASE} = $version;
277 0   0     0 $self->{DISTRIB_CODENAME} = $codename || q{};
278              
279             # fix stupidity
280 0 0 0     0 if ( $self->{DISTRIB_ID}
      0        
      0        
281             && $self->{DISTRIB_ID} eq 'redhat'
282             && $self->{DISTRIB_NAME}
283             && index($self->{DISTRIB_NAME}, 'CentOS') != -1
284             ) {
285 0         0 $self->{DISTRIB_ID} = 'centos';
286             }
287              
288 0 0       0 return $self->{ $field } if $self->{ $field };
289             }
290              
291 0         0 $self->{release_file} = $tmp;
292 0         0 $self->{pattern} = q{};
293 0         0 return;
294             }
295              
296             sub _get_file_info {
297 4     4   7 my $self = shift;
298 4         39 my $file = File::Spec->catfile( $self->{etc_dir}, $self->{release_file} );
299 4         38 require IO::File;
300 4         38 my $FH = IO::File->new;
301 4 50       143 $FH->open( $file, '<' ) || croak "Can't open $file: $!";
302 4         388 my @raw = <$FH>;
303 4 50       21 $FH->close || croak "Can't close FH($file): $!";
304 4         75 my $rv;
305 4         51 foreach my $line ( @raw ){
306 6         13 chomp $line;
307             ## no critic (RequireExtendedFormatting)
308 6         94 my($info) = $line =~ m/$self->{pattern}/ms;
309 6 100       26 if ( $info ) {
310 4         8 $rv = "\L$info";
311 4         11 last;
312             }
313             }
314 4         21 return $rv;
315             }
316              
317             1;
318              
319             __END__