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