File Coverage

blib/lib/File/Samba.pm
Criterion Covered Total %
statement 92 148 62.1
branch 34 50 68.0
condition 9 21 42.8
subroutine 10 15 66.6
pod 11 11 100.0
total 156 245 63.6


line stmt bran cond sub pod time code
1             package File::Samba;
2              
3 1     1   23855 use strict;
  1         2  
  1         43  
4 1     1   6 use warnings;
  1         2  
  1         36  
5 1     1   6 use Carp qw(cluck croak confess);
  1         7  
  1         100  
6 1     1   991 use Data::Dump qw(dump);
  1         9688  
  1         1879  
7              
8             require Exporter;
9              
10             our @ISA = qw(Exporter);
11              
12             #
13             # We all for several exports
14             #
15             our $VERSION = '0.03';
16             our (@EXPORT, @EXPORT_OK, %EXPORT_TAGS);
17             #
18             # Exported Functions by request
19             #
20             @EXPORT_OK = qw(
21             version
22             keys
23             value
24             listShares
25             deleteShare
26             createShare
27             sectionParameter
28             globalParameter
29             load
30             save
31             ); # symbols to export on request
32              
33             =head1 Object Methods
34              
35             =head2 new([config file])
36              
37             Optionally a file can be specifided in the constructor to load the file
38             on creation.
39              
40             Returns a new Samba Object
41              
42             =cut
43              
44             sub new
45             {
46 1     1 1 13 my $proto = shift;
47 1   33     7 my $class = ref($proto) || $proto;
48 1         3 my $self = {};
49 1         4 $self->{_global} = {};
50 1         4 $self->{_section} = {};
51 1         3 $self->{_version} = 2;
52             eval
53 1         3 {
54 1         6 while()
55             {
56 645         655 chomp;
57 645 100       1158 next if /^#/;
58 643         1609 my ($st,$vers,$cmd) = split(/:/);
59 643 50 66     3387 if($cmd && $vers && $st)
      66        
60             {
61 642         665 chomp($cmd);
62 642         2401 $self->{_VALID}->{$st}->{"v$vers"}->{$cmd} = "1";
63             }
64 643 100       2314 last if /__END__/;
65             }
66             };
67              
68 1         8 bless ($self, $class);
69 1 50       8 if(@_)
70             {
71 1         10 $self->load(shift);
72             }
73              
74 1         24 return $self;
75             }
76              
77             =head2 version([version])
78              
79             Set or get the version of this smb.conf your want to edit
80             the load method tries to determine the smb.conf version based on the keys
81             it find
82              
83             Params:
84             [Optional] the version number
85             Returns:
86             the current version (either 2 or 3)
87             Example:
88             if($obj->version == 3)
89             {
90             # do Samba 3 options
91             }
92              
93             =cut
94              
95             sub version
96             {
97 2     2 1 12 my $self = shift;
98 2 100       6 if (@_)
99             {
100 1         3 my $ver = shift;
101 1 50 33     8 croak "Samba version 2 or 3 only " if($ver < 2 || $ver > 3);
102 1         4 $self->{_version} = $ver;
103             # do we strip out bad values? NOPE
104             }
105 2         10 return $self->{_version};
106             }
107              
108             =head2 keys(section)
109              
110             Get a list of key for a given section, use 'global' for the globl section
111              
112             Params:
113             section to list
114             Returns:
115             a sorted list of section keys
116             Example:
117             my @keys = $smb->keys('some section');
118              
119             =cut
120              
121             sub keys
122             {
123 0     0 1 0 my $self = shift;
124 0         0 my $section = shift;
125 0 0       0 if($section eq "global")
126             {
127 0         0 return sort(CORE::keys(%{$self->{_global}}));
  0         0  
128             }
129             else
130             {
131 0         0 return sort(CORE::keys(%{$self->{_section}->{$section}}));
  0         0  
132             }
133             }
134              
135             =head2 value(section,key)
136              
137             Get the value associated with a key in a given section (READ ONLY)
138              
139             Params:
140             section to list
141             key to read
142             Returns:
143             the value associated with the key/section combination or undef if the key/section
144             does nto exists
145             Example:
146             my $value = $smb->keys('some section','some key');
147              
148             =cut
149              
150             sub value
151             {
152 0     0 1 0 my $self = shift;
153 0         0 my $section = shift;
154 0         0 my $key = shift;
155 0 0       0 if($section eq "global")
156             {
157 0         0 return $self->{_global}->{$key};
158             }
159             else
160             {
161 0         0 return $self->{_section}->{$section}->{$key};
162             }
163             }
164              
165             =head2 listShares()
166              
167             Get a list of shares defined in the smb.conf file EXCLUDING the global section
168              
169             Params:
170             none
171             Returns:
172             a sorted list of section names
173             Example:
174             my @list = $smb->listShares;
175              
176             =cut
177              
178             sub listShares
179             {
180 0     0 1 0 my $self = shift;
181 0         0 my @list = CORE::keys(%{$self->{_section}});
  0         0  
182 0         0 return sort(@list);
183             }
184              
185             =head2 deleteShare(share name)
186              
187             Delete a given share, this method can't delete the global section
188              
189             Params:
190             the share to delete
191             Returns:
192             none
193             Example:
194             $smb->deleteShare('some share');
195              
196             =cut
197              
198              
199             sub deleteShare
200             {
201 0     0 1 0 my $self = shift;
202 0         0 my $share = shift;
203 0         0 delete $self->{_section}->{$share};
204             }
205              
206             =head2 createShare(share name)
207              
208             Create a share with a given name
209              
210             Params:
211             the share to create
212             Returns:
213             none
214             Example:
215             $smb->createShare('some share');
216             Exceptions:
217             If you try to create a share called global, the method will croak
218              
219             =cut
220              
221             sub createShare
222             {
223 1     1 1 2 my $self = shift;
224 1         1 my $share = shift;
225 1 50       4 if($share eq 'global')
226             {
227 0         0 croak("You can't create a share called global");
228             }
229 1 50       7 $self->{_section}->{$share} = {} unless exists $self->{_section}->{$share};
230             }
231              
232             =head2 sectionParameter(section,key,[value])
233              
234             Get or set a key in a given section, if value is not sepecifed this methods performs
235             a lookup, otherwise it performs an edit
236              
237             Params:
238             the section you wish to modify/view
239             the key to view
240             the value to set
241             Returns:
242             the value set or read
243             Example:
244             $smb->sectionParameter('homes','guest ok','yes');
245             Exceptions:
246             The key you pass in for a 'Set' operrtion will be checked against a list of valid
247             key names, based on the smb.conf version. Setting an invalid key will result if croak
248              
249             =cut
250              
251              
252             sub sectionParameter
253             {
254 2     2 1 2 my $self = shift;
255 2         3 my $section = shift;
256 2         4 my $param = shift;
257 2 100       7 if(@_)
258             {
259 1         2 my $value = shift;
260 1         2 my $version = $self->{_version};
261 1 50       6 if($self->{_VALID}->{section}->{"v$version"}->{$param})
262             {
263 1         3 $self->{_section}->{$section}->{$param} = $value;
264             }
265             else
266             {
267 0         0 croak("Invalid section key \"$param\" for samba version $version");
268             }
269             }
270 2         7 return $self->{_section}->{$section}->{$param};
271             }
272              
273             =head2 globalParameter(key,[value])
274              
275             Get or set a key in the global section, if value is not sepecifed this methods performs
276             a lookup, otherwise it performs an edit
277              
278             Params:
279             the key to view
280             the value to set
281             Returns:
282             the value set or read
283             Example:
284             $smb->globalParameter('homes','guest ok','yes');
285             Exceptions:
286             The key you pass in for a 'Set' operrtion will be checked against a list of valid
287             key names, based on the smb.conf version. Setting an invalid key will result if croak
288              
289             =cut
290              
291             sub globalParameter
292             {
293 2     2 1 3 my $self = shift;
294 2         2 my $param = shift;
295 2 100       16 if(@_)
296             {
297 1         2 my $value = shift;
298 1         2 my $version = $self->{_version};
299 1 50 33     10 if($self->{_VALID}->{global}->{"v$version"}->{$param} || $self->{_VALID}->{section}->{"v$version"}->{$param})
300             {
301 1         3 $self->{_global}->{$param} = $value;
302             }
303             else
304             {
305 0         0 croak("Invalid key \"$param\" for samba version $version");
306             }
307             }
308 2         7 return $self->{_global}->{$param};
309             }
310              
311             =head2 load(filename)
312              
313             Read a smb.conf file from disk, and parse it. The version will be identified as best as possible
314             but may not be correct, you should use version method after calling load to make sure the version
315             detected correctly
316              
317             Params:
318             the smb.conf file to load
319             Returns:
320             none
321             Example:
322             $smb->load('/etc/samba/smbconf');
323             Exceptions:
324             If the file does not exist croak
325              
326             =cut
327              
328              
329             sub load
330             {
331 1     1 1 2 my $self = shift;
332 1         11 my $file = shift;
333 1 50       35 cluck("No such file $file") unless -e $file;
334             # Load the file and run
335 1         42 open(FH,$file);
336 1         3 my $isGlobal;
337             my $lastSection;
338             # guess version 2 we need a good wy to see if version 3
339 1         2 my $lastDetVersion = 2;
340 1         26 while()
341             {
342 114         119 chomp;
343 114 100       519 next if /^;|^#/;
344 71 50       164 next if /^\s+$/;
345 71 100       125 next if length($_) <= 1;
346 62         104 s/\t//;
347 62         72 s/\n//;
348 62         102 s/^\s+//;
349 62         129 s/\s+$//;
350 62 100       129 next if /^;/;
351 58 100       137 if(/\[global\]/i)
    100          
352             {
353 1         8 $isGlobal = 1;
354             }
355             elsif(/\[(\w+)\]/)
356             {
357 4         6 $isGlobal = 0;
358 4         16 $lastSection = $1;
359             }
360             else
361             {
362 53         113 my($key,$value) = split('=',$_,2);
363 53         135 $key =~ s/\s+$//;
364 53         98 $value =~ s/^\s+//;
365 53 100       74 if($isGlobal)
366             {
367 32         74 $self->{_global}->{$key}=$value;
368 32         28 my ($v2,$v3);
369 32         69 $v2 = $self->{_VALID}->{global}->{v2}->{$key};
370 32         53 $v3 = $self->{_VALID}->{global}->{v3}->{$key};
371 32 50 66     179 if($v3 && !$v2)
372             {
373 0         0 $self->{_version} = 3;
374             }
375             }
376             else
377             {
378 21 100       41 if($self->{_section}->{$lastSection})
379             {
380 17         77 $self->{_section}->{$lastSection}->{$key} = $value;
381             }
382             else
383             {
384 4         8 $self->{_section}->{$lastSection} = {};
385 4         20 $self->{_section}->{$lastSection}->{$key} = $value;
386             }
387             }
388             }
389             }
390 1         18 close(FH);
391             #print "[Global] \n",dump($self->{_global});
392             #print "\n[Sections] \n",dump($self->{_section});
393             #print "\n[Version] \n",$self->{_version};
394             }
395              
396             =head2 save(filename)
397              
398             Save the current inmemory smb.conf file
399              
400             Params:
401             the file to save to
402             Returns:
403             none
404             Example:
405             $smb->save('/home/test.conf');
406              
407             =cut
408              
409              
410             sub save
411             {
412 0     0 1   my $self = shift;
413 0           my $outputFile = shift;
414             # Save it now !!
415 0           open(WH,">$outputFile");
416             # Ok write Header
417 0           print WH "################################################################################\n";
418 0           print WH "# Generate By File::Samba $VERSION #\n";
419 0           print WH "# This is the main Samba configuration file. You should read the #\n";
420 0           print WH "# smb.conf(5) manual page in order to understand the options listed #\n";
421 0           print WH "# here. #\n";
422 0           print WH "# Any line which starts with a ; (semi-colon) or a # (hash) #\n";
423 0           print WH "# is a comment and is ignored. In this example we will use a # #\n";
424 0           print WH "# for commentry and a ; for parts of the config file that you #\n";
425 0           print WH "# may wish to enable #\n";
426 0           print WH "# #\n";
427 0           print WH "# NOTE: Whenever you modify this file you should run the command \"testparm\" #\n";
428 0           print WH "# to check that you have not made any basic syntactic errors. #\n";
429 0           print WH "################################################################################\n";
430 0           print WH ";========================= Global Settings =====================================\n";
431             # write global section
432 0           print WH "[global]\n";
433 0           foreach my $key ($self->keys('global'))
434             {
435 0           print WH "\t$key = ",$self->{_global}->{$key},"\n";
436             }
437 0           print WH "\n";
438 0           print WH ";=========================== Share Settings =====================================\n";
439 0           my @sList = $self->listShares;
440 0           foreach my $skey (@sList)
441             {
442 0           print WH "[$skey]\n";
443 0 0 0       if($skey eq "homes" || $skey eq "printers" )
444             {
445 0           print WH "\t;special shares for samba see smb.conf(5)\n";
446             }
447 0           my @skList = $self->keys($skey);
448 0           foreach my $subK (@skList)
449             {
450 0           print WH "\t$subK = ",$self->{_section}->{$skey}->{$subK},"\n";
451             }
452 0           print WH "\n";
453             }
454 0           close(WH);
455             }
456              
457             1;
458             __DATA__