File Coverage

blib/lib/Sman/Config.pm
Criterion Covered Total %
statement 32 140 22.8
branch 1 58 1.7
condition 1 21 4.7
subroutine 9 22 40.9
pod 0 11 0.0
total 43 252 17.0


line stmt bran cond sub pod time code
1             package Sman::Config;
2              
3             #$Id: Config.pm,v 1.19 2005/09/15 02:44:55 joshr Exp $
4              
5 2     2   7198 use 5.006;
  2         7  
  2         128  
6 2     2   11 use strict;
  2         4  
  2         60  
7 2     2   10 use warnings;
  2         3  
  2         144  
8 2     2   2322 use FindBin qw($Bin);
  2         2728  
  2         283  
9 2     2   2309 use POSIX qw(sysconf _PC_CHOWN_RESTRICTED); # for _isverysafe
  2         15288  
  2         17  
10 2     2   2607 use Cwd; # for _isverysafe
  2         5  
  2         156  
11 2     2   224591 use File::stat; # used in _issafe()
  2         658530  
  2         27  
12 2     2   13926 use fields qw( conf );
  2         1869  
  2         17  
13              
14             # call like my $smanconfig = new Sman::Config();
15             sub new {
16 1     1 0 12 my $proto = shift;
17 1   33     7 my $class = ref($proto) || $proto;
18 1         2 my $self = {};
19 1         3 bless ($self, $class);
20 1         8 $self->{conf} = []; # empty list
21 1         3 my $configfile = shift;
22 1 50       3 if (defined($configfile)) {
23 0         0 $self->ReadSingleConfigFile($configfile);
24             }
25 1         4 return $self;
26             }
27              
28             # Gets a config var. Because we're case INsensitive.
29             # returns "" if no data found.
30             sub GetConfigData {
31 0     0 0   my ($self, $directive) = @_;
32             #print "Looking for $directive...\n";
33 0           for(@ {$self->{conf}} ) {
  0            
34 0 0 0       return $_->[1] if (uc($_->[0]) eq uc($directive) && defined($_->[1]));
35             }
36 0           return "";
37             }
38              
39             # Sets a config var. Because we're case INsensitive.
40             # if an existing value is set for a name, it's replaced, WHERE IT WAS.
41             # returns the data.
42             sub SetConfigData {
43 0     0 0   my ($self, $directive, $data) = @_;
44             #print "Setting '$directive' to '$data'\n";
45 0           for (my $i=0; $i < scalar(@ {$self->{conf}}); $i++ ) {
  0            
46 0 0         if (uc($self->{conf}->[$i]->[0]) eq uc($directive)) {
47 0 0         warn "Clobbering previous setting for '$directive'\n"
48             if defined($self->{verbose}); # there is no self->{verbose}. Why no error?
49 0           $self->{conf}->[$i]->[1] = $data;
50 0           return $data;
51             }
52             }
53 0           my @line = ($directive, $data); # stored as originally input
54 0           push(@ {$self->{conf}}, \@line); # push the listref on the list
  0            
55 0           return $data;
56             }
57              
58             # this returns only the first one found in the path
59             # $Bin/sman.conf, ~/.sman.conf, /usr/local/etc/sman.conf, /etc/sman.conf
60             sub FindDefaultConfigFile {
61 0     0 0   my $self = shift;
62 0           my (@dirs) = $self->_getconfigdirs();
63 0           for(@dirs) {
64 0 0         if (-e "$_/sman-defaults.conf") {
65 0 0         if($self->_isverysafe("$_/sman-defaults.conf") ) {
66 0           return "$_/sman-defaults.conf";
67             } else {
68 0           warn "$0: Can't use $_/sman-defaults.conf: ownership not safe.\n";
69             }
70             }
71             }
72 0           return "";
73             }
74              
75             # finds and returns the config file(s). Looks for sman.conf(s) in:
76             # $Bin/sman.conf, ~/.sman.conf, /usr/local/etc/sman.conf, /etc/sman.conf
77             # (in that order)
78             sub FindConfigFiles {
79 0     0 0   my $self = shift;
80 0           my (@dirs, @configs) = $self->_getconfigdirs();
81 0           for(@dirs) {
82 0           my $f = "$_/sman.conf";
83 0 0 0       if (-e $f && $self->_isverysafe($f) ) {
84 0           push(@configs, $f);
85             }
86             }
87 0           my $defaultconfig = $self->FindDefaultConfigFile();
88 0 0         push(@configs, $defaultconfig) if ($defaultconfig);
89 0           return @configs;
90             }
91              
92             # we pass verbose here because it could be that the user's verbose setting is overridden from above
93             # returns the name of the file read, or "" if none found.
94             sub ReadDefaultConfigFile {
95 0     0 0   my ($self, $verbose) = @_;
96 0           my @configfiles = $self->FindConfigFiles(); # this includes the default one.
97            
98             # read the first config file.
99 0           for (@configfiles) {
100 0 0         print "Reading config file $_\n" if $verbose;
101 0           $self->ReadSingleConfigFile($_);
102 0           last;
103             }
104             #print "Used config file '$configfiles[0]', found '" . join(", ", @configfiles) . "'.\n"
105             # if ($verbose || $self->GetConfigData("VERBOSE"));
106 0 0         if (scalar(@configfiles)) {
107 0           return $configfiles[0];
108             } else {
109 0           return "";
110             }
111             }
112              
113             # adds data from the file into our configuration data
114             # returns the filename read, or "" on error
115             sub ReadSingleConfigFile {
116 0     0 0   my ($self, $file) = @_;
117 0           my $prevline;
118 0 0         if (!open(FILE, "< $file")) {
119 0           die "Couldn't open $file: $!";
120             } else {
121 0           while(defined(my $line = )) {
122 0           chomp($line);
123 0 0         if (defined($prevline)) {
124 0           $line = "$prevline $line";
125 0           undef $prevline;
126             }
127 0 0         if ($line =~ s/\\$//) { # if the last char is \, remove it, and
128 0           $prevline = $line; # record it
129             } else { # else parse it
130 0 0         next if $line =~ /^\s*$/; # empty line
131 0 0         next if $line =~ /^\s*#/; # a comment
132 0           $line =~ s/^\s+//; # strip leading ws
133 0           my ($directive, $value) = split(/\s+/, $line, 2);
134 0 0 0       if (defined($directive) && $directive && defined($value)) {
      0        
135 0           $self->SetConfigData($directive, $value); # will clobber old setting
136             }
137             }
138             }
139 0 0         close(FILE) || die "Couldn't close $file: $!";
140             }
141 0           return $file;
142             }
143              
144             sub Reset {
145 0     0 0   my $self = shift;
146 0           $self->{conf} = {}; # reset the puppy
147             }
148              
149             # returns a list of params from the config
150             sub GetConfigNames {
151 0     0 0   my $self = shift;
152 0           my @names = ();
153 0           for( @ {$self->{conf}} ) {
  0            
154 0 0 0       if (defined($_->[0]) && defined($_->[1])) {
155 0           push(@names, $_->[0]);
156             }
157             }
158 0           return @names;
159             }
160              
161             sub Dump {
162 0     0 0   my $self = shift;
163 0           my $str = "# Sman::Config settings:\n";
164 0           for (@ { $self->{conf} } ) {
  0            
165 0           $str .= " $_->[0] $_->[1]\n";
166             }
167 0           return $str;
168             }
169              
170             sub SetEnvironmentVariablesFromConfig
171             {
172 0     0 0   my $self = shift;
173 0           my $verbose = $self->GetConfigData("VERBOSE");
174 0           my @envs = grep { /^ENV_/ } $self->GetConfigNames();
  0            
175 0           for my $e (@envs) {
176 0           (my $copy = $e ) =~ s/^ENV_//;
177 0           $ENV{uc($copy)} = $self->GetConfigData($e);
178 0 0         print "Set ENV{$copy} to " . $self->GetConfigData($e) . "\n"
179             if ($verbose);
180             }
181 0           return @envs;
182             }
183              
184             sub _getconfigdirs {
185 0     0     my (@dirs, @configs) = ( $Bin ); # From FindBin
186 0 0         if (defined($ENV{HOME})) { push(@dirs, $ENV{HOME}); }
  0            
187 0           push(@dirs, qw(/etc/ /usr/local/etc/));
188 0           return @dirs;
189             }
190              
191             #from perl cookbook "8.17. Testing a File for Trustworthiness"
192             sub _issafe {
193 0     0     my ($self, $path) = @_;
194 0           my $info = stat($path);
195 0 0         return 0 unless $info;
196              
197             # owner neither superuser nor me
198             # the real uid is in stored in the $< variable
199 0 0 0       if (($info->uid != 0) && ($info->uid != $<)) {
200 0           return 0;
201             }
202              
203             # check whether group or other can write file.
204             # use 066 to detect either reading or writing
205 0 0         if ($info->mode & 022) { # someone else can write this
206 0 0         return 0 unless -d _; # non-directories aren't safe
207             # but directories with the sticky bit (01000) are
208 0 0         return 0 unless $info->mode & 01000;
209             }
210 0           return 1;
211             }
212              
213             #from perl cookbook "8.17. Testing a File for Trustworthiness"
214             sub _isverysafe {
215 0     0     my ($self, $path) = @_;
216 0 0         return $self->_issafe($path) if sysconf(_PC_CHOWN_RESTRICTED);
217 0 0         $path = getcwd() . '/' . $path if $path !~ m{^/};
218 0           do {
219 0 0         return unless $self->_issafe($path);
220 0           $path =~ s#([^/]+|/)$##; # dirname
221 0 0         $path =~ s#/$## if length($path) > 1; # last slash
222             } while length $path;
223              
224 0           return 1;
225             }
226              
227              
228              
229              
230              
231              
232              
233             1;
234             __END__