1 | import sys, string, SambaParm
|
---|
2 | from smbparm import parm_table
|
---|
3 |
|
---|
4 | ######################################################################
|
---|
5 | ##
|
---|
6 | ## smb.conf parser class
|
---|
7 | ##
|
---|
8 | ## Copyright (C) Gerald Carter 2004.
|
---|
9 | ##
|
---|
10 | ## This program is free software; you can redistribute it and/or modify
|
---|
11 | ## it under the terms of the GNU General Public License as published by
|
---|
12 | ## the Free Software Foundation; either version 2 of the License, or
|
---|
13 | ## (at your option) any later version.
|
---|
14 | ##
|
---|
15 | ## This program is distributed in the hope that it will be useful,
|
---|
16 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
17 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
18 | ## GNU General Public License for more details.
|
---|
19 | ##
|
---|
20 | ## You should have received a copy of the GNU General Public License
|
---|
21 | ## along with this program; if not, write to the Free Software
|
---|
22 | ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
23 | ##
|
---|
24 | ######################################################################
|
---|
25 |
|
---|
26 |
|
---|
27 | #####################################################################
|
---|
28 | ## multi line Samba comment
|
---|
29 | class SambaComment:
|
---|
30 |
|
---|
31 | def __init__( self, comment ):
|
---|
32 | self.comment = comment
|
---|
33 |
|
---|
34 | def Dump( self, stream, whitespace=None ):
|
---|
35 | if not self.comment:
|
---|
36 | return
|
---|
37 | for line in self.comment:
|
---|
38 | if whitespace:
|
---|
39 | stream.write( whitespace )
|
---|
40 | stream.write( line )
|
---|
41 | stream.write( "\n" )
|
---|
42 |
|
---|
43 |
|
---|
44 | #####################################################################
|
---|
45 | ## string smb.conf parms
|
---|
46 | class SambaParameter :
|
---|
47 |
|
---|
48 | ## indexs into the parm table tuples
|
---|
49 | DisplayName = 0
|
---|
50 | ObjectType = 1
|
---|
51 | DefaultValue = 2
|
---|
52 | Scope = 3
|
---|
53 |
|
---|
54 | ## Stores a key into the parm_table and creates an
|
---|
55 | ## SambaParmXXX object to store the value
|
---|
56 | def __init__( self, name, value, comment=None ):
|
---|
57 | self.key = string.upper(string.strip(name))
|
---|
58 | self.comment = None
|
---|
59 | assert parm_table.has_key( self.key ), "Bad parameter name! [%s]" % name
|
---|
60 | self.parm = parm_table[self.key][self.ObjectType]( value )
|
---|
61 | if comment :
|
---|
62 | self.comment = SambaComment( comment )
|
---|
63 |
|
---|
64 | #if not self.parm.valid:
|
---|
65 | # self.parm.SetValue( parm_table[self.key][self.DefaultValue] )
|
---|
66 |
|
---|
67 | ## simple test for global or service parameter scope
|
---|
68 | def isGlobalParm( self ) :
|
---|
69 | return parm_table[self.key][Scope]
|
---|
70 |
|
---|
71 | ## dump <the parameter to stdout
|
---|
72 | def Dump( self, stream ):
|
---|
73 | if self.comment:
|
---|
74 | self.comment.Dump( stream, "\t" )
|
---|
75 | stream.write( "\t%s = %s\n" % ( parm_table[self.key][self.DisplayName], self.parm.StringValue() ))
|
---|
76 |
|
---|
77 |
|
---|
78 | #####################################################################
|
---|
79 | ## Class for parsing and modifying Smb.conf
|
---|
80 | class SambaConf:
|
---|
81 |
|
---|
82 | def __init__( self ):
|
---|
83 | self.services = {}
|
---|
84 | self.valid = True
|
---|
85 | self.services["GLOBAL"] = {}
|
---|
86 | self.services_order = []
|
---|
87 |
|
---|
88 |
|
---|
89 | ## always return a non-empty line of input or None
|
---|
90 | ## if we hit EOF
|
---|
91 | def ReadLine( self, stream ):
|
---|
92 | result = None
|
---|
93 | input_str = None
|
---|
94 |
|
---|
95 | while True:
|
---|
96 | input_str = stream.readline()
|
---|
97 |
|
---|
98 | ## Are we done with the file ?
|
---|
99 |
|
---|
100 | if len(input_str) == 0:
|
---|
101 | return result
|
---|
102 |
|
---|
103 | ## we need one line of valid input at least
|
---|
104 | ## continue around the loop again if the result
|
---|
105 | ## string is empty
|
---|
106 |
|
---|
107 | input_str = string.strip( input_str )
|
---|
108 | if len(input_str) == 0:
|
---|
109 | if not result:
|
---|
110 | continue
|
---|
111 | else:
|
---|
112 | return result
|
---|
113 |
|
---|
114 | ## we have > 1` character so setup the result
|
---|
115 | if not result:
|
---|
116 | result = ""
|
---|
117 |
|
---|
118 | ## Check for comments -- terminated by \n -- no continuation
|
---|
119 |
|
---|
120 | if input_str[0] == '#' or input_str[0] == ';' :
|
---|
121 | result = input_str
|
---|
122 | break
|
---|
123 |
|
---|
124 | ## check for line continuation
|
---|
125 |
|
---|
126 | if input_str[-1] == "\\" :
|
---|
127 | result += input_str[0:-1]
|
---|
128 | contine
|
---|
129 |
|
---|
130 | ## otherwise we have a complete line
|
---|
131 | result += input_str
|
---|
132 | break
|
---|
133 |
|
---|
134 | return result
|
---|
135 |
|
---|
136 | ## convert the parameter name to a form suitable as a dictionary key
|
---|
137 | def NormalizeParamName( self, param ):
|
---|
138 | return string.upper( string.join(string.split(param), "") )
|
---|
139 |
|
---|
140 | ## Open the file and parse it into a services dictionary
|
---|
141 | ## if possible
|
---|
142 | def ReadConfig( self, filename ):
|
---|
143 | self.filename = filename
|
---|
144 |
|
---|
145 | try:
|
---|
146 | fconfig = open( filename, "r" )
|
---|
147 | except IOError:
|
---|
148 | self.valid = False
|
---|
149 | return
|
---|
150 |
|
---|
151 | section_name = None
|
---|
152 |
|
---|
153 | ## the most recent seen comment is stored as an array
|
---|
154 | current_comment = []
|
---|
155 |
|
---|
156 | while True:
|
---|
157 |
|
---|
158 | str = self.ReadLine( fconfig )
|
---|
159 | if not str:
|
---|
160 | break
|
---|
161 |
|
---|
162 | ## Check for comments
|
---|
163 | if str[0] == '#' or str[0] == ';' :
|
---|
164 | current_comment.append( str )
|
---|
165 | continue
|
---|
166 |
|
---|
167 | ## look for a next section name
|
---|
168 | if str[0]=='[' and str[-1]==']' :
|
---|
169 | section_name = str[1:-1]
|
---|
170 | self.AddService( section_name, current_comment )
|
---|
171 | current_comment = []
|
---|
172 | continue
|
---|
173 |
|
---|
174 | str_list = string.split( str, "=" )
|
---|
175 |
|
---|
176 | if len(str_list) != 2 :
|
---|
177 | continue
|
---|
178 |
|
---|
179 | if not section_name :
|
---|
180 | print "parameter given without section name!"
|
---|
181 | break
|
---|
182 |
|
---|
183 | param = self.NormalizeParamName( str_list[0] )
|
---|
184 | value = string.strip(str_list[1])
|
---|
185 |
|
---|
186 | self.SetServiceOption( section_name, param, value, current_comment )
|
---|
187 | self.dirty = False
|
---|
188 |
|
---|
189 | ## reset the comment strinf if we have one
|
---|
190 | current_comment = []
|
---|
191 |
|
---|
192 | fconfig.close()
|
---|
193 |
|
---|
194 | ## Add a parameter to the global section
|
---|
195 | def SetGlobalOption( self, param, value, comment=None ) :
|
---|
196 | self.SetServiceOption( "GLOBAL", param, value, comment )
|
---|
197 |
|
---|
198 | ## Add a parameter to a specific service
|
---|
199 | def SetServiceOption( self, servicename, param, value, comment=None ) :
|
---|
200 | service = string.upper(servicename)
|
---|
201 | parm = self.NormalizeParamName(param)
|
---|
202 | self.services[service]['_order_'].append( parm )
|
---|
203 | self.services[service][parm] = SambaParameter( parm, value, comment )
|
---|
204 | self.dirty = True
|
---|
205 |
|
---|
206 | ## remove a service from the config file
|
---|
207 | def DelService( self, servicename ) :
|
---|
208 | service = string.upper(servicename)
|
---|
209 | self.services[service] = None
|
---|
210 | self.dirty = True
|
---|
211 |
|
---|
212 | ## remove a service from the config file
|
---|
213 | def AddService( self, servicename, comment=None ) :
|
---|
214 | service = string.upper(servicename)
|
---|
215 |
|
---|
216 | self.services[service] = {}
|
---|
217 | self.services[service]['_order_'] = []
|
---|
218 |
|
---|
219 | if ( comment ):
|
---|
220 | self.services[service]['_comment_'] = SambaComment( comment )
|
---|
221 |
|
---|
222 | self.services_order.append( service )
|
---|
223 |
|
---|
224 | self.dirty = True
|
---|
225 |
|
---|
226 | def isService( self, servicename ):
|
---|
227 | service = string.upper(servicename)
|
---|
228 | return self.services.has_key( service )
|
---|
229 |
|
---|
230 | ## dump a single service to stream
|
---|
231 | def DumpService( self, stream, servicename ):
|
---|
232 |
|
---|
233 | ## comments first
|
---|
234 | if self.services[servicename].has_key( '_comment_' ):
|
---|
235 | self.services[servicename]['_comment_'].Dump( stream )
|
---|
236 |
|
---|
237 | ## section header
|
---|
238 | stream.write( "[%s]\n" % (servicename) )
|
---|
239 |
|
---|
240 | ## parameter = value
|
---|
241 | for parm in self.services[servicename]['_order_']:
|
---|
242 | self.services[servicename][parm].Dump(stream)
|
---|
243 |
|
---|
244 | ## dump the config to stream
|
---|
245 | def Dump( self, stream ):
|
---|
246 | self.DumpService( stream, "GLOBAL" )
|
---|
247 | stream.write("\n")
|
---|
248 |
|
---|
249 | for section in self.services_order:
|
---|
250 | ## already handled the global section
|
---|
251 | if section == "GLOBAL":
|
---|
252 | continue
|
---|
253 |
|
---|
254 | ## check for deleted sections ##
|
---|
255 | if not self.services[section]:
|
---|
256 | continue
|
---|
257 |
|
---|
258 | self.DumpService( stream, section )
|
---|
259 | stream.write( "\n" )
|
---|
260 |
|
---|
261 | ## write out any changes to disk
|
---|
262 | def Flush( self ):
|
---|
263 | if not self.dirty:
|
---|
264 | return
|
---|
265 |
|
---|
266 | try:
|
---|
267 | fconfig = open( self.filename, "w" )
|
---|
268 | except IOError:
|
---|
269 | sys.stderr.write( "ERROR!\n" )
|
---|
270 | return 1
|
---|
271 |
|
---|
272 | self.Dump( fconfig )
|
---|
273 | fconfig.close()
|
---|
274 | return 0
|
---|
275 |
|
---|
276 | def Services( self ):
|
---|
277 | service_list = []
|
---|
278 | for section in self.services.keys():
|
---|
279 | service_list.append( section )
|
---|
280 |
|
---|
281 | return service_list
|
---|
282 |
|
---|
283 | def NumServices( self ):
|
---|
284 | return len(self.Services())
|
---|
285 |
|
---|
286 | def Write( self, filename ):
|
---|
287 | self.filename = filename
|
---|
288 | self.valid = True
|
---|
289 |
|
---|
290 | if not self.dirty:
|
---|
291 | return
|
---|
292 |
|
---|
293 | self.Flush()
|
---|
294 |
|
---|
295 |
|
---|
296 |
|
---|
297 | ######################################################################
|
---|
298 | ## Unit tests
|
---|
299 | ######################################################################
|
---|
300 |
|
---|
301 | if __name__ == "__main__" :
|
---|
302 |
|
---|
303 | x = SambaConf( )
|
---|
304 | x.ReadConfig( sys.argv[1] )
|
---|
305 | if not x.valid :
|
---|
306 | print "Bad file!"
|
---|
307 | sys.exit(1)
|
---|
308 |
|
---|
309 | x.Dump( sys.stdout )
|
---|
310 |
|
---|
311 |
|
---|
312 |
|
---|
313 | ## end of SambaConfig.py ######################################################
|
---|
314 | ###############################################################################
|
---|
315 |
|
---|