| 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 |
|
|---|