File Coverage

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


line stmt bran cond sub pod time code
1             package Sys::Info::Driver::Linux::OS::Distribution;
2             $Sys::Info::Driver::Linux::OS::Distribution::VERSION = '0.7904';
3 2     2   61801 use strict;
  2         11  
  2         54  
4 2     2   8 use warnings;
  2         3  
  2         62  
5              
6 2     2   9 use constant STD_RELEASE => 'lsb-release';
  2         4  
  2         113  
7 2     2   11 use constant STD_RELEASE_DIR => 'lsb-release.d';
  2         4  
  2         81  
8 2     2   10 use constant DEBIAN_RELEASE => 'os-release';
  2         3  
  2         74  
9 2     2   10 use constant STD_ETC_DIR => '/etc';
  2         3  
  2         91  
10              
11 2     2   11 use base qw( Sys::Info::Base );
  2         4  
  2         499  
12 2     2   10508 use Carp qw( croak );
  2         4  
  2         85  
13 2     2   412 use Sys::Info::Driver::Linux;
  2         4  
  2         83  
14 2     2   345 use Sys::Info::Driver::Linux::Constants qw( :all );
  2         4  
  2         261  
15 2     2   849 use Sys::Info::Driver::Linux::OS::Distribution::Conf;
  2         6  
  2         219  
16 2     2   16 use File::Spec;
  2         3  
  2         3817  
17              
18             # XXX: <REMOVE>
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             #</REMOVE>
33              
34             sub new {
35 2     2 1 74 my $class = shift;
36 2         5 my %option;
37 2 50       6 if ( @_ ) {
38 0 0       0 die "Parameters must be in name => value format" if @_ % 2;
39 0         0 %option = @_;
40             }
41              
42 2         16 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         10 $self->{etc_dir} =~ s{[/]+$}{}xms;
57              
58 2         5 bless $self, $class;
59 2         7 $self->_initial_probe;
60 2         9 return $self;
61             }
62              
63 3     3 1 17 sub raw_name { return shift->{RESULTS}{raw_name} }
64 6     6 1 19 sub name { return shift->{RESULTS}{name} }
65 4     4 1 11 sub version { return shift->{RESULTS}{version} }
66 1     1 1 3 sub edition { return shift->{RESULTS}{edition} }
67 1     1 1 3 sub kernel { return shift->{PROBE}{kernel} }
68 1     1 1 2 sub build { return shift->{PROBE}{build} }
69 1     1 1 3 sub build_date { return shift->{PROBE}{build_date} }
70             sub manufacturer {
71 1     1 1 1 my $self = shift;
72 1   50     3 my $slot = $CONF{ lc $self->raw_name } || return;
73 1 50       4 return if ! exists $slot->{manufacturer};
74 1         9 return $slot->{manufacturer};
75             }
76              
77             sub _probe {
78 2     2   4 my $self = shift;
79 2 50       7 return $self->{RESULTS} if $self->{RESULTS};
80 2         4 $self->{RESULTS} = {};
81 2         5 $self->{RESULTS}{name} = $self->_probe_name;
82 2         6 $self->{RESULTS}{raw_name} = $self->{RESULTS}{name};
83 2         7 $self->{RESULTS}{version} = $self->_probe_version;
84             # this has to be last, since this also modifies the two above
85 2         6 $self->{RESULTS}{edition} = $self->_probe_edition;
86 2         3 return $self->{RESULTS};
87             }
88              
89             sub _probe_name {
90 2     2   4 my $self = shift;
91 2         5 my $distro = $self->_get_lsb_info;
92 2 50       7 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   2 my $self = shift;
114 2         7 my $release = $self->_get_lsb_info('DISTRIB_RELEASE');
115 2 50       10 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         3 my $p = $self->{PROBE};
131              
132 2 50       7 if ( my $dn = $self->name ) {
133 2   33     8 my $n = $self->{DISTRIB_NAME} || do {
134             my $slot = $CONF{ $dn };
135             exists $slot->{name} ? $slot->{name} : ucfirst $dn;
136             };
137 2         7 $dn = $self->trim( $n );
138 2 50       23 $dn .= ' Linux' if $dn !~ m{Linux}xmsi;
139 2         5 $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         5 my $name = $self->name;
147 2         6 my $raw_name = $self->raw_name;
148 2         6 my $version = $self->version;
149 2   50     7 my $slot = $CONF{$raw_name} || return;
150 2 50       7 my $edition = exists $slot->{edition} ? $slot->{edition}{ $version } : undef;
151              
152 2 50       8 if ( ! $edition ) {
153 2 50 33     11 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 0 33     7 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         5 return $edition;
174             }
175              
176             sub _initial_probe {
177 2     2   3 my $self = shift;
178 2         4 my $version = q{};
179              
180 2 50 33     64 if ( -e proc->{version} && -f _) {
181             $version = $self->trim(
182             $self->slurp(
183             proc->{version},
184 2         21 'I can not open linux version file %s for reading: '
185             )
186             );
187             }
188              
189 2         324 my($str, $build_date) = split /\#/xms, $version;
190 2         5 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       6 $build_date = q{} if not $build_date; # running since blah thingie
195              
196 2 50 33     31 if ( $str =~ RE_LINUX_VERSION || $str =~ RE_LINUX_VERSION2 ) {
197 2         7 $kernel = $1;
198 2 50       10 if ( $distro = $self->trim( $2 ) ) {
199 2 50       35 if ( $distro =~ m{ \s\((.+?)\)\) \z }xms ) {
200 0         0 $distro = $1;
201             }
202             }
203             }
204              
205 2 50 33     18 $distro = 'Linux' if ! $distro || $distro =~ m{\(gcc}xms;
206              
207             # kernel build date
208 2 50       17 $build_date = $self->date2time($build_date) if $build_date;
209 2 50       5815 my $build = $build_date ? localtime $build_date : q{};
210              
211             $self->{PROBE} = {
212 2         21 version => $version,
213             kernel => $kernel,
214             build => $build,
215             build_date => $build_date,
216             distro => $distro,
217             };
218              
219 2         10 $self->_probe;
220 2         4 return;
221             }
222              
223             sub _get_lsb_info {
224 4     4   7 my $self = shift;
225 4   100     14 my $field = shift || 'DISTRIB_ID';
226 4         8 my $tmp = $self->{release_file};
227              
228 8         158 my($rfile) = grep { -r $_->[1] }
229             map {
230 4         8 [ $_ => File::Spec->catfile( $self->{etc_dir}, $_ ) ]
  8         114  
231             }
232             STD_RELEASE,
233             DEBIAN_RELEASE
234             ;
235              
236 4 50       40 if ( $rfile ) {
237 4         10 $self->{release_file} = $rfile->[0];
238 4         9 $self->{pattern} = $field . '=(.+)';
239 4         13 my $info = $self->_get_file_info;
240 4 50       16 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             my $rv = join q{: },
247 0 0       0 map { m{$dir/(.*)}xms ? $1 : () }
248 0         0 grep { $_ !~ m{ \A [.] }xms }
  0         0  
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   6 my $self = shift;
298 4         26 my $file = File::Spec->catfile( $self->{etc_dir}, $self->{release_file} );
299 4         55 require IO::File;
300 4         21 my $FH = IO::File->new;
301 4 50       109 $FH->open( $file, '<' ) || croak "Can't open $file: $!";
302 4         252 my @raw = <$FH>;
303 4 50       18 $FH->close || croak "Can't close FH($file): $!";
304 4         59 my $rv;
305 4         9 foreach my $line ( @raw ){
306 6         8 chomp $line;
307             ## no critic (RequireExtendedFormatting)
308 6         67 my($info) = $line =~ m/$self->{pattern}/ms;
309 6 100       16 if ( $info ) {
310 4         10 $rv = "\L$info";
311 4         7 last;
312             }
313             }
314 4         17 return $rv;
315             }
316              
317             1;
318              
319             __END__
320              
321             =pod
322              
323             =encoding UTF-8
324              
325             =head1 NAME
326              
327             Sys::Info::Driver::Linux::OS::Distribution
328              
329             =head1 VERSION
330              
331             version 0.7904
332              
333             =head1 SYNOPSIS
334              
335             use Sys::Info::Driver::Linux::OS::Distribution;
336             my $distro = Sys::Info::Driver::Linux::OS::Distribution->new;
337             my $name = $distro->name;
338             if( $name ) {
339             my $version = $distro->version;
340             print "you are running $distro, version $version\n";
341             }
342             else {
343             print "distribution unknown\n";
344             }
345              
346             =head1 DESCRIPTION
347              
348             This is a simple module that tries to guess on what linux distribution
349             we are running by looking for release's files in /etc. It now looks for
350             'lsb-release' first as that should be the most correct and adds ubuntu support.
351             Secondly, it will look for the distro specific files.
352              
353             It currently recognizes slackware, debian, suse, fedora, redhat, turbolinux,
354             yellowdog, knoppix, mandrake, conectiva, immunix, tinysofa, va-linux, trustix,
355             adamantix, yoper, arch-linux, libranet, gentoo, ubuntu and redflag.
356              
357             It has function to get the version for debian, suse, redhat, gentoo, slackware,
358             redflag and ubuntu(lsb). People running unsupported distro's are greatly
359             encouraged to submit patches.
360              
361             =head1 NAME
362              
363             Sys::Info::Driver::Linux::OS::Distribution - Linux distribution probe
364              
365             =head1 METHODS
366              
367             =head2 build
368              
369             =head2 build_date
370              
371             =head2 edition
372              
373             =head2 kernel
374              
375             =head2 manufacturer
376              
377             =head2 name
378              
379             =head2 new
380              
381             =head2 raw_name
382              
383             =head2 version
384              
385             =head1 TODO
386              
387             Add the capability of recognize the version of the distribution for all
388             recognized distributions.
389              
390             =head1 Linux::Distribution AUTHORS
391              
392             Some parts of this module were originally taken from C<Linux::Distribution>
393             and it's authors are:
394              
395             Alberto Re E<lt>alberto@accidia.netE<gt>
396             Judith Lebzelter E<lt>judith@osdl.orgE<gt>
397             Alexandr Ciornii E<lt>alexchorny@gmail.com<gt>
398              
399             =head1 AUTHOR
400              
401             Burak Gursoy <burak@cpan.org>
402              
403             =head1 COPYRIGHT AND LICENSE
404              
405             This software is copyright (c) 2006 by Burak Gursoy.
406              
407             This is free software; you can redistribute it and/or modify it under
408             the same terms as the Perl 5 programming language system itself.
409              
410             =cut