|
Server : Apache/2.2.17 (Unix) mod_ssl/2.2.17 OpenSSL/0.9.8e-fips-rhel5 DAV/2 PHP/5.2.17 System : Linux localhost 2.6.18-419.el5 #1 SMP Fri Feb 24 22:47:42 UTC 2017 x86_64 User : nobody ( 99) PHP Version : 5.2.17 Disable Function : NONE Directory : /proc/21572/root/usr/share/system-config-network/netconfpkg/conf/ |
Upload File : |
# Copyright (C) 1996-2002 Red Hat, Inc.
# Use of this software is subject to the terms of the GNU General
# Public License
# This module manages standard configuration file handling
# These classes are available:
# Conf:
# This is the base class. This is good for working with just about
# any line-oriented configuration file.
# Currently does not deal with newline escaping; may never...
# ConfShellVar(Conf):
# This is a derived class which implements a dictionary for standard
# VARIABLE=value
# shell variable setting.
# Limitations:
# o one variable per line
# o assumes everything on the line after the '=' is the value
# ConfShellVarClone(ConfShellVar):
# Takes a ConfShellVar instance and records in another ConfShellVar
# "difference file" only those settings which conflict with the
# original instance. The delete operator does delete the variable
# text in the cloned instance file, but that will not really delete
# the shell variable that occurs, because it does not put an "unset"
# command in the file.
# ConfESNetwork(ConfShellVar):
# This is a derived class specifically intended for /etc/sysconfig/network
# It is another dictionary, but magically fixes /etc/HOSTNAME when the
# hostname is changed.
# ConfEHosts(Conf):
# Yet another dictionary, this one for /etc/hosts
# Dictionary keys are numeric IP addresses in string form, values are
# 2-item lists, the first item of which is the canonical hostname,
# and the second of which is a list of nicknames.
# ConfEResolv(Conf):
# Yet another dictionary, this one for /etc/resolv.conf
# This ugly file has two different kinds of entries. All but one
# take the form "key list of arguments", but one entry (nameserver)
# instead takes multiple lines of "key argument" pairs.
# In this dictionary, all keys have the same name as the keys in
# the file, EXCEPT that the multiple nameserver entries are all
# stored under 'nameservers'. Each value (even singleton values)
# is a list.
# ConfESStaticRoutes(Conf):
# Yet another dictionary, this one for /etc/sysconfig/static-routes
# This file has a syntax similar to that of /etc/gateways;
# the interface name is added and active/passive is deleted:
# <interface> net <netaddr> netmask <netmask> gw <gateway>
# The key is the interface, the value is a list of
# [<netaddr>, <netmask>, <gateway>] lists
# ConfChat(Conf):
# Not a dictionary!
# This reads chat files, and writes a subset of chat files that
# has all items enclosed in '' and has one expect/send pair on
# each line.
# Uses a list of two-element tuples.
# ConfChatFile(ConfChat):
# This class is a ConfChat which it interprets as a netcfg-written
# chat file with a certain amount of structure. It interprets it
# relative to information in an "ifcfg-" file (devconf) and has a
# set of abortstrings that can be turned on and off.
# It exports the following data items:
# abortstrings list of standard strings on which to abort
# abortlist list of alternative strings on which to abort
# defabort boolean: use the default abort strings or not
# dialcmd string containing dial command (ATDT, for instance)
# phonenum string containing phone number
# chatlist list containing chat script after CONNECT
# chatfile ConfChat instance
# ConfChatFileClone(ConfChatFile):
# Creates a chatfile, then removes it if it is identical to the chat
# file it clones.
# ConfDIP:
# This reads chat files, and writes a dip file based on that chat script.
# Takes three arguments:
# o The chatfile
# o The name of the dipfile
# o The ConfSHellVar instance from which to take variables in the dipfile
# ConfModules(Conf)
# This reads /etc/modprobe.conf into a dictionary keyed on device type,
# holding dictionaries: cm['eth0']['alias'] --> 'smc-ultra'
# cm['eth0']['options'] --> {'io':'0x300', 'irq':'10'}
# cm['eth0']['post-install'] --> ['/bin/foo','arg1','arg2']
# path[*] entries are ignored (but not removed)
# New entries are added at the end to make sure that they
# come after any path[*] entries.
# Comments are delimited by initial '#'
# ConfModInfo(Conf)
# This READ-ONLY class reads /boot/module-info.
# The first line of /boot/module-info is "Version = <version>";
# this class reads versions 0 and 1 module-info files.
# ConfPw(Conf)
# This class implements a dictionary based on a :-separated file.
# It takes as arguments the filename and the field number to key on;
# The data provided is a list including all fields including the key.
# Has its own write method to keep files sane.
# ConfPasswd(ConfPw)
# This class presents a data-oriented class for making changes
# to the /etc/passwd file.
# ConfShadow(ConfPw)
# This class presents a data-oriented class for making changes
# to the /etc/shadow file.
# ConfGroup(ConfPw)
# This class presents a data-oriented class for making changes
# to the /etc/group file.
# May be replaced by a pwdb-based module, we hope.
# ConfUnix()
# This class presents a data-oriented class which uses the ConfPasswd
# and ConfShadow classes (if /etc/shadow exists) to hold data.
# Designed to be replaced by a pwdb module eventually, we hope.
# ConfPAP(Conf):
# Yet another dictionary, this one for /etc/ppp/pap-secrets
# The key is the remotename, the value is a list of
# [<user>, <secret>] lists
# ConfCHAP(ConfPAP):
# Yet another dictionary, this one for /etc/ppp/chap-secrets
# The key is the remotename, the value is a list of
# [<local>, <secret>] lists
# ConfSecrets:
# Has-a ConfPAP and ConfCHAP
# Yet another dictionary, which reads from pap-secrets and
# chap-secrets, and writes to both when an entry is set.
# When conflicts occur while reading, the pap version is
# used in preference to the chap version (this is arbitrary).
# ConfSysctl:
# Guess what? A dictionary, this time with key/value pairs for sysctl vars.
# Duplicate keys get appended to existing values, and broken out again when
# the file is written (does that even work?)
# This library exports several Errors, including
# FileMissing
# Conf raises this error if create_if_missing == 0 and the file does not
# exist
# IndexError
# ConfShVar raises this error if unbalanced quotes are found
# BadFile
# Raised to indicate improperly formatted files
# WrongMethod
# Raised to indicate that the wrong method is being called. May indicate
# that a dictionary class should be written to through methods rather
# than assignment.
# VersionMismatch
# An unsupported file version was found.
# SystemFull
# No more UIDs or GIDs are available
class FileMissing(Exception):
def __init__(self, filename):
self.filename = filename
def __str__(self):
return self.filename + " does not exist."
class IndexError(Exception):
def __init__(self, filename, var):
self.filename = filename
self.var = var
def __str__(self):
return "end quote not found in %s: %s" % (self.filename, self.var[0])
class BadFile(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return self.msg
WrongMethod = BadFile
VersionMismatch = BadFile
SystemFull = BadFile
from string import *
from UserDict import UserDict
import re
import os
import types
# Implementation:
# A configuration file is a list of lines.
# a line is a string.
class Conf:
def __init__(self, filename, commenttype='#',
separators='\t ', separator='\t',
merge=1, create_if_missing=1):
self.commenttype = commenttype
self.separators = separators
self.separator = separator
self.codedict = {}
self.splitdict = {}
self.merge = merge
self.create_if_missing = create_if_missing
self.line = 0
self.rcs = 0
self.mode = -1
# self.line is a "point" -- 0 is before the first line;
# 1 is between the first and second lines, etc.
# The "current" line is the line after the point.
self.filename = filename
self.read()
def rewind(self):
self.line = 0
def fsf(self):
self.line = len(self.lines)
def tell(self):
return self.line
def seek(self, line):
self.line = line
def nextline(self):
self.line = min([self.line + 1, len(self.lines)])
def findnextline(self, regexp=None):
# returns False if no more lines matching pattern
while self.line < len(self.lines):
if regexp:
if hasattr(regexp, "search"):
if regexp.search(self.lines[self.line]):
return 1
elif re.search(regexp, self.lines[self.line]):
return 1
elif not regexp:
return 1
self.line = self.line + 1
# if while loop terminated, pattern not found.
return 0
def findnextcodeline(self):
# optional whitespace followed by non-comment character
# defines a codeline. blank lines, lines with only whitespace,
# and comment lines do not count.
if not self.codedict.has_key((self.separators, self.commenttype)):
self.codedict[(self.separators, self.commenttype)] = \
re.compile('^[' + self.separators \
+ ']*' + '[^' + \
self.commenttype + \
self.separators + ']+')
codereg = self.codedict[(self.separators, self.commenttype)]
return self.findnextline(codereg)
def findlinewithfield(self, fieldnum, value):
if self.merge:
seps = '['+self.separators+']+'
else:
seps = '['+self.separators+']'
rx = '^'
for i in range(fieldnum - 1):
rx = rx + '[^'+self.separators+']*' + seps
rx = rx + value + '\(['+self.separators+']\|$\)'
return self.findnextline(rx)
def getline(self):
if self.line >= len(self.lines):
return ''
return self.lines[self.line]
def getfields(self):
# returns list of fields split by self.separators
if self.line >= len(self.lines):
return []
if self.merge:
seps = '['+self.separators+']+'
else:
seps = '['+self.separators+']'
#print "re.split(%s, %s) = " % (self.lines[self.line], seps) + str(re.split(seps, self.lines[self.line]))
if not self.splitdict.has_key(seps):
self.splitdict[seps] = re.compile(seps)
regexp = self.splitdict[seps]
return regexp.split(self.lines[self.line])
def setfields(self, list):
# replaces current line with line built from list
# appends if off the end of the array
if self.line < len(self.lines):
self.deleteline()
self.insertlinelist(list)
def insertline(self, line=''):
self.lines.insert(self.line, line)
def insertlinelist(self, linelist):
self.insertline(joinfields(linelist, self.separator))
def sedline(self, pat, repl):
if self.line < len(self.lines):
self.lines[self.line] = re.sub(pat, repl, \
self.lines[self.line])
def changefield(self, fieldno, fieldtext):
fields = self.getfields()
fields[fieldno:fieldno+1] = [fieldtext]
self.setfields(fields)
def setline(self, line=[]):
self.deleteline()
self.insertline(line)
def deleteline(self):
self.lines[self.line:self.line+1] = []
def chmod(self, mode=-1):
self.mode = mode
def read(self):
file_exists = 0
if os.path.isfile(self.filename):
file_exists = 1
if not self.create_if_missing and not file_exists:
raise FileMissing, self.filename
if file_exists and os.access(self.filename, os.R_OK):
self.file = open(self.filename, 'r', -1)
self.lines = self.file.readlines()
# strip newlines
for index in range(len(self.lines)):
if len(self.lines[index]) and self.lines[index][-1] == '\n':
self.lines[index] = self.lines[index][:-1]
if len(self.lines[index]) and self.lines[index][-1] == '\r':
self.lines[index] = self.lines[index][:-1]
self.file.close()
else:
self.lines = []
def write(self):
# rcs checkout/checkin errors are thrown away, because they
# aren't this tool's fault, and there's nothing much it could
# do about them. For example, if the file is already locked
# by someone else, too bad! This code is for keeping a trail,
# not for managing contention. Too many deadlocks that way...
if self.rcs or os.path.exists(os.path.split(self.filename)[0]+'/RCS'):
self.rcs = 1
os.system('/usr/bin/co -l '+self.filename+' </dev/null >/dev/null 2>&1')
self.file = open(self.filename, 'w', -1)
if self.mode >= 0:
os.chmod(self.filename, self.mode)
# add newlines
for index in range(len(self.lines)):
self.file.write(self.lines[index] + '\n')
self.file.close()
if self.rcs:
mode = os.stat(self.filename)[0]
os.system('/usr/bin/ci -u -m"control panel update" ' +
self.filename+' </dev/null >/dev/null 2>&1')
os.chmod(self.filename, mode)
class ConfShellVar(Conf):
def __init__(self, filename):
self.nextreg = re.compile('^[\t ]*[A-Za-z_][A-Za-z0-9_]*=')
self.quotereg = re.compile('[ \t${}*@!~<>?;%^()#&=]')
Conf.__init__(self, filename, commenttype='#',
separators='=', separator='=')
def __quote(self, s):
s = s.replace('\\', '\\\\')
s = s.replace('$', '\\$')
s = s.replace('"', '\\"')
return s
def read(self):
Conf.read(self)
self.initvars()
def initvars(self):
self.vars = {}
self.rewind()
while self.findnextline(self.nextreg):
# initialize dictionary of variable/name pairs
var = self.getfields()
# fields 1..n are False separations on "=" character in string,
# so we need to join them back together.
var[1] = joinfields(var[1:len(var)], '=')
if len(var[1]) and var[1][0] in '\'"':
# found quote; strip from beginning and end
quote = var[1][0]
var[1] = var[1][1:]
p = -1
try:
while cmp(var[1][p], quote):
# ignore whitespace, etc.
p = p - 1
except:
raise IndexError (self.filename, var)
var[1] = var[1][:p]
else:
var[1] = re.sub('#.*', '', var[1])
var[1] = var[1].replace('\\', '')
self.vars[var[0]] = var[1]
self.nextline()
self.rewind()
def __getitem__(self, varname):
if self.vars.has_key(varname):
return self.vars[varname]
else:
return ''
def __setitem__(self, varname, value):
# prevent tracebacks
if not value:
value=""
# set *every* instance of varname to value to avoid surprises
place=self.tell()
self.rewind()
missing=1
value = self.__quote(value)
while self.findnextline('^[\t ]*' + varname + '='):
if self.quotereg.search(value):
self.sedline('=.*', "=\"" + value + "\"")
else:
self.sedline('=.*', '=' + value)
missing=0
self.nextline()
if missing:
self.seek(place)
if self.quotereg.search(value):
self.insertline(varname + "=\"" + value + "\"")
else:
self.insertline(varname + '=' + value)
self.vars[varname] = value
def __delitem__(self, varname):
# delete *every* instance...
self.rewind()
while self.findnextline('^[\t ]*' + varname + '='):
self.deleteline()
if self.vars.has_key(varname):
del self.vars[varname]
def has_key(self, key):
if self.vars.has_key(key): return 1
return 0
def keys(self):
return self.vars.keys()
# ConfShellVarClone(ConfShellVar):
# Takes a ConfShellVar instance and records in another ConfShellVar
# "difference file" only those settings which conflict with the
# original instance. The delete operator does delete the variable
# text in the cloned instance file, but that will not really delete
# the shell variable that occurs, because it does not put an "unset"
# command in the file.
class ConfShellVarClone(ConfShellVar):
def __init__(self, cloneInstance, filename):
Conf.__init__(self, filename, commenttype='#',
separators='=', separator='=')
self.ci = cloneInstance
def __getitem__(self, varname):
if self.vars.has_key(varname):
return self.vars[varname]
elif self.ci.has_key(varname):
return self.ci[varname]
else:
return ''
def __setitem__(self, varname, value):
if value != self.ci[varname]:
# differs from self.ci; save a local copy.
ConfShellVar.__setitem__(self, varname, value)
else:
# self.ci already has the variable with the same value,
# don't duplicate it
if self.vars.has_key(varname):
del self[varname]
# inherit delitem because we don't want to pass it through to self.ci
def has_key(self, key):
if self.vars.has_key(key): return 1
if self.ci.has_key(key): return 1
return 0
# FIXME: should we implement keys()?
class ConfESNetwork(ConfShellVar):
# explicitly for /etc/sysconfig/network: HOSTNAME is magical value
# that writes /etc/HOSTNAME as well
def __init__ (self):
ConfShellVar.__init__(self, '/etc/sysconfig/network')
self.writehostname = 0
def __setitem__(self, varname, value):
ConfShellVar.__setitem__(self, varname, value)
if varname == 'HOSTNAME':
self.writehostname = 1
def write(self):
ConfShellVar.write(self)
if self.writehostname:
file = open('/etc/HOSTNAME', 'w', -1)
file.write(self.vars['HOSTNAME'] + '\n')
file.close()
os.chmod('/etc/HOSTNAME', 0644)
def keys(self):
# There doesn't appear to be a need to return keys in order
# here because we normally always have the same entries in this
# file, and order isn't particularly important.
return self.vars.keys()
def has_key(self, key):
return self.vars.has_key(key)
class ConfEHosts(Conf):
# for /etc/hosts
# implements a dictionary keyed by IP address, with values
# consisting of a list: [ hostname, [list, of, nicknames] ]
def __init__(self, filename = '/etc/hosts'):
Conf.__init__(self, filename)
def read(self):
Conf.read(self)
self.initvars()
def initvars(self):
self.vars = {}
self.rewind()
while self.findnextcodeline():
# initialize dictionary of variable/name pairs
var = self.getfields()
if len(var) > 2:
# has nicknames
self.vars[var[0]] = [ var[1], var[2:] ]
elif len(var) > 1:
self.vars[var[0]] = [ var[1], [] ]
else:
pass
# exception is a little bit hard.. just skip the line
# raise BadFile, 'Malformed /etc/hosts file'
self.nextline()
self.rewind()
def __getitem__(self, varname):
if self.vars.has_key(varname):
return self.vars[varname]
else:
return ''
def __setitem__(self, varname, value):
# set first (should be only) instance to values in list value
place=self.tell()
self.rewind()
while self.findnextline('^\S*' + varname + '[' + \
self.separators + ']+'):
self.deleteline()
self.seek(place)
self.insertlinelist([ varname, value[0],
joinfields(value[1], self.separator) ])
self.vars[varname] = value
def __delitem__(self, varname):
# delete *every* instance...
self.rewind()
while self.findnextline('^\S*' + varname + '[' + \
self.separators + ']+'):
self.deleteline()
del self.vars[varname]
def keys(self):
# It is rather important to return the keys in order here,
# in order to maintain a consistent presentation in apps.
place=self.tell()
self.rewind()
keys = []
while self.findnextcodeline():
# initialize dictionary of variable/name pairs
var = self.getfields()
if len(var) > 1:
keys.append(var[0])
self.nextline()
self.seek(place)
return keys
class ConfFHosts(Conf):
# for /etc/hosts
# implements a dictionary keyed by Hostname, with values
# consisting of a list: [ IP-Adress, [list, of, nicknames] ]
def __init__(self, filename = '/etc/hosts'):
Conf.__init__(self, filename)
def read(self):
Conf.read(self)
self.initvars()
def initvars(self):
self.vars = {}
self.rewind()
while self.findnextcodeline():
# initialize dictionary of variable/name pairs
var = self.getfields()
if len(var) > 2:
# has nicknames
self.vars[var[1]] = [ var[0], var[2:] ]
elif len(var) > 1:
self.vars[var[1]] = [ var[0], [] ]
else:
# exception is a little bit hard.. just skip the line
# raise BadFile, 'Malformed /etc/hosts file'
pass
self.nextline()
self.rewind()
def __getitem__(self, varname):
if self.vars.has_key(varname):
return self.vars[varname]
else:
return ''
def __setitem__(self, varname, value):
# set first (should be only) instance to values in list value
place=self.tell()
self.rewind()
lastdel = place
while self.findnextline('^\S*' + '[' + \
self.separators + ']+' + varname):
self.deleteline()
lastdel = self.tell()
self.seek(lastdel)
if type(value) != types.ListType and type(value) != types.TupleType:
value = [ value, [] ]
self.insertlinelist([ value[0], varname,
joinfields(value[1], self.separator) ])
self.vars[varname] = value
self.seek(place)
def __delitem__(self, varname):
# delete *every* instance...
self.rewind()
while self.findnextline('^\S*[' + self.separators + ']+' + varname):
self.deleteline()
del self.vars[varname]
def keys(self):
# It is rather important to return the keys in order here,
# in order to maintain a consistent presentation in apps.
place=self.tell()
self.rewind()
keys = []
while self.findnextcodeline():
# initialize dictionary of variable/name pairs
var = self.getfields()
if len(var) > 1:
keys.append(var[1])
self.nextline()
self.seek(place)
return keys
class ConfEResolv(Conf):
# /etc/resolv.conf
def __init__(self):
Conf.__init__(self, '/etc/resolv.conf', '#', '\t ', ' ')
def read(self):
Conf.read(self)
self.initvars()
def initvars(self):
self.vars = {}
self.rewind()
while self.findnextcodeline():
var = self.getfields()
if var[0] == 'nameserver':
if self.vars.has_key('nameservers'):
self.vars['nameservers'].append(var[1])
else:
self.vars['nameservers'] = [ var[1] ]
else:
self.vars[var[0]] = var[1:]
self.nextline()
self.rewind()
def __getitem__(self, varname):
if self.vars.has_key(varname):
return self.vars[varname]
else:
return []
def __setitem__(self, varname, value):
# set first (should be only) instance to values in list value
place=self.tell()
self.rewind()
if varname == 'nameservers':
if self.findnextline('^nameserver[' + self.separators + ']+'):
# if there is a nameserver line, save the place,
# remove all nameserver lines, then put in new ones in order
placename=self.tell()
while self.findnextline('^nameserver['+self.separators+']+'):
self.deleteline()
self.seek(placename)
for nameserver in value:
self.insertline('nameserver' + self.separator + nameserver)
self.nextline()
self.seek(place)
else:
# no nameservers entries so far
self.seek(place)
for nameserver in value:
self.insertline('nameserver' + self.separator + nameserver)
else:
# not a nameserver, so all items on one line...
if self.findnextline('^' + varname + '[' + self.separators + ']+'):
self.deleteline()
self.insertlinelist([ varname,
joinfields(value, self.separator) ])
self.seek(place)
else:
self.seek(place)
self.insertlinelist([ varname,
joinfields(value, self.separator) ])
# no matter what, update our idea of the variable...
self.vars[varname] = value
def __delitem__(self, varname):
# delete *every* instance...
self.rewind()
while self.findnextline('^[' + self.separators + ']*' + varname):
self.deleteline()
del self.vars[varname]
def write(self):
# Need to make sure __setitem__ is called for each item to
# maintain consistancy, in case some did something like
# resolv['nameservers'].append('123.123.123.123')
# or
# resolv['search'].append('another.domain')
for key in self.vars.keys():
self[key] = self.vars[key]
if self.filename != '/etc/resolv.conf':
Conf.write(self)
else:
# bug 125712: /etc/resolv.conf modifiers MUST use
# change_resolv_conf function to change resolv.conf
import tempfile
self.filename = tempfile.mktemp('','/tmp/')
Conf.write(self)
import commands
commands.getstatusoutput("/bin/bash -c '. /etc/sysconfig/network-scripts/network-functions; change_resolv_conf "+self.filename+"'")
self.filename="/etc/resolv.conf"
def keys(self):
# no need to return list in order here, I think.
return self.vars.keys()
def has_key(self, key):
return self.vars.has_key(key)
# ConfESStaticRoutes(Conf):
# Yet another dictionary, this one for /etc/sysconfig/static-routes
# This file has a syntax similar to that of /etc/gateways;
# the interface name is added and active/passive is deleted:
# <interface> net <netaddr> netmask <netmask> gw <gateway>
# The key is the interface, the value is a list of
# [<netaddr>, <netmask>, <gateway>] lists
class ConfESStaticRoutes(Conf):
def __init__(self):
Conf.__init__(self, '/etc/sysconfig/static-routes', '#', '\t ', ' ')
def read(self):
Conf.read(self)
self.initvars()
def initvars(self):
self.vars = {}
self.rewind()
while self.findnextcodeline():
var = self.getfields()
if len(var) == 7:
if not self.vars.has_key(var[0]):
self.vars[var[0]] = [[var[2], var[4], var[6]]]
else:
self.vars[var[0]].append([var[2], var[4], var[6]])
elif len(var) == 5:
if not self.vars.has_key(var[0]):
self.vars[var[0]] = [[var[2], var[4], '']]
else:
self.vars[var[0]].append([var[2], var[4], ''])
self.nextline()
self.rewind()
def __getitem__(self, varname):
if self.vars.has_key(varname):
return self.vars[varname]
else:
return [[]]
def __setitem__(self, varname, value):
raise WrongMethod, 'Delete or call addroute instead'
def __delitem__(self, varname):
# since we re-write the file completely on close, we don't
# need to alter it piecemeal here.
del self.vars[varname]
def delroute(self, device, route):
# deletes a route from a device if the route exists,
# and if it is the only route for the device, removes
# the device from the dictionary
# Note: This could normally be optimized considerably,
# except that our input may have come from the file,
# which others may have hand-edited, and this makes it
# possible for us to deal with hand-inserted multiple
# identical routes in a reasonably correct way.
if self.vars.has_key(device):
for i in range(len(self.vars[device])):
if i < len(self.vars[device]) and \
not cmp(self.vars[device][i], route):
# need first comparison because list shrinks
self.vars[device][i:i+1] = []
if len(self.vars[device]) == 0:
del self.vars[device]
def addroute(self, device, route):
# adds a route to a device, deleteing it first to avoid dups
self.delroute(device, route)
if self.vars.has_key(device):
self.vars[device].append(route)
else:
self.vars[device] = [route]
def write(self):
# forget current version of file
self.rewind()
self.lines = []
for device in self.vars.keys():
for route in self.vars[device]:
if len(route) == 3:
if len(route[2]):
self.insertlinelist((device, 'net', route[0],
'netmask', route[1],
'gw', route[2]))
else:
self.insertlinelist((device, 'net', route[0],
'netmask', route[1]))
Conf.write(self)
def keys(self):
# no need to return list in order here, I think.
return self.vars.keys()
def has_key(self, key):
return self.vars.has_key(key)
# ConfChat(Conf):
# Not a dictionary!
# This reads chat files, and writes a subset of chat files that
# has all items enclosed in '' and has one expect/send pair on
# each line.
# Uses a list of two-element tuples.
class ConfChat(Conf):
def __init__(self, filename):
Conf.__init__(self, filename, '', '\t ', ' ')
def read(self):
Conf.read(self)
self.initlist()
def initlist(self):
self.list = []
i = 0
hastick = 0
s = ''
chatlist = []
for line in self.lines:
s = s + line + ' '
while i < len(s) and s[i] in " \t":
i = i + 1
while i < len(s):
str = ''
# here i points to a new entry
if s[i] in "'":
hastick = 1
i = i + 1
while i < len(s) and s[i] not in "'":
if s[i] in '\\':
if not s[i+1] in " \t'":
str = str + '\\'
i = i + 1
str = str + s[i]
i = i + 1
# eat up the ending '
i = i + 1
else:
while i < len(s) and s[i] not in " \t":
str = str + s[i]
i = i + 1
chatlist.append(str)
# eat whitespace between strings
while i < len(s) and s[i] in ' \t':
i = i + 1
# now form self.list from chatlist
if len(chatlist) % 2:
chatlist.append('')
while chatlist:
self.list.append((chatlist[0], chatlist[1]))
chatlist[0:2] = []
def getlist(self):
return self.list
def putlist(self, list):
self.list = list
def write(self):
# create self.lines for Conf.write...
self.lines = []
for (p,q) in self.list:
p = re.sub("'", "\\'", p)
q = re.sub("'", "\\'", q)
self.lines.append("'"+p+"' '"+q+"'")
Conf.write(self)
# ConfChatFile(ConfChat):
# This class is a ConfChat which it interprets as a netcfg-written
# chat file with a certain amount of structure. It interprets it
# relative to information in an "ifcfg-" file (devconf) and has a
# set of abortstrings that can be turned on and off.
# It exports the following data items:
# abortstrings list of standard strings on which to abort
# abortlist list of alternative strings on which to abort
# defabort boolean: use the default abort strings or not
# dialcmd string containing dial command (ATDT, for instance)
# phonenum string containing phone number
# chatlist list containing chat script after CONNECT
# chatfile ConfChat instance
class ConfChatFile(ConfChat):
def __init__(self, filename, devconf, abortstrings=None):
ConfChat.__init__(self, filename)
self.abortstrings = abortstrings
self.devconf = devconf
self._initlist()
def _initlist(self):
self.abortlist = []
self.defabort = 1
self.dialcmd = ''
self.phonenum = ''
self.chatlist = []
dialexp = re.compile('^ATD[TP]?[-0-9,. #*()+]+')
if self.list:
for (p,q) in self.list:
if not cmp(p, 'ABORT'):
if not q in self.abortstrings:
self.abortlist.append([p,q])
elif not cmp(q, self.devconf['INITSTRING']):
# ignore INITSTRING
pass
elif not self.dialcmd and dialexp.search(q):
#elif not self.dialcmd and tempmatch:
# First instance of something that looks like a dial
# command and a phone number we take as such.
tmp = re.search('[-0-9,. #*()+]+', q)
index=tmp.group(1)
self.dialcmd = q[:index]
self.phonenum = q[index:]
elif not cmp(p, 'CONNECT'):
# ignore dial command
pass
else:
self.chatlist.append([p,q])
def _makelist(self):
self.list = []
if self.defabort:
for string in self.abortstrings:
self.list.append(('ABORT', string))
for string in self.abortlist:
self.list.append(('ABORT', string))
self.list.append(('', self.devconf['INITSTRING']))
self.list.append(('OK', self.dialcmd+self.phonenum))
self.list.append(('CONNECT', ''))
for pair in self.chatlist:
self.list.append(pair)
def write(self):
self._makelist()
ConfChat.write(self)
# ConfChatFileClone(ConfChatFile):
# Creates a chatfile, then removes it if it is identical to the chat
# file it clones.
class ConfChatFileClone(ConfChatFile):
def __init__(self, cloneInstance, filename, devconf, abortstrings=None):
self.ci = cloneInstance
ConfChatFile.__init__(self, filename, devconf, abortstrings)
if not self.list:
self.list = []
for item in self.ci.list:
self.list.append(item)
self._initlist()
def write(self):
self._makelist()
if len(self.list) == len(self.ci.list):
for i in range(len(self.list)):
if cmp(self.list[i], self.ci.list[i]):
# some element differs, so they are different
ConfChatFile.write(self)
return
# the loop completed, so they are the same
if os.path.isfile(self.filename): os.unlink(self.filename)
else:
# lists are different lengths, so they are different
ConfChatFile.write(self)
# ConfDIP:
# This reads chat files, and writes a dip file based on that chat script.
# Takes three arguments:
# o The chatfile
# o The name of the dipfile
# o The ConfSHellVar instance from which to take variables in the dipfile
class ConfDIP:
def __init__(self, chatfile, dipfilename, configfile):
self.dipfilename = dipfilename
self.chatfile = chatfile
self.cf = configfile
def write(self):
self.file = open(self.dipfilename, 'w', -1)
os.chmod(self.dipfilename, 0600)
self.file.write('# dip script for interface '+self.cf['DEVICE']+'\n' +
'# DO NOT HAND-EDIT; ALL CHANGES *WILL* BE LOST BY THE netcfg PROGRAM\n' +
'# This file is created automatically from several other files by netcfg\n' +
'# Re-run netcfg to modify this file\n\n' +
'main:\n' +
' get $local '+self.cf['IPADDR']+'\n' +
' get $remote '+self.cf['REMIP']+'\n' +
' port '+self.cf['MODEMPORT']+'\n' +
' speed '+self.cf['LINESPEED']+'\n')
if self.cf['MTU']:
self.file.write(' get $mtu '+self.cf['MTU']+'\n')
for pair in self.chatfile.list:
if cmp(pair[0], 'ABORT') and cmp(pair[0], 'TIMEOUT'):
if pair[0]:
self.file.write(' wait '+pair[0]+' 30\n' +
' if $errlvl != 0 goto error\n')
self.file.write(' send '+pair[1]+'\\r\\n\n' +
' if $errlvl != 0 goto error\n')
if not cmp(self.cf['DEFROUTE'], 'yes'):
self.file.write(' default\n')
self.file.write(' mode '+self.cf['MODE']+'\n' +
' exit\n' +
'error:\n' +
' print connection to $remote failed.\n')
self.file.close()
class odict(UserDict):
def __init__(self, dict = None):
self._keys = []
UserDict.__init__(self, dict)
def __delitem__(self, key):
UserDict.__delitem__(self, key)
self._keys.remove(key)
def __setitem__(self, key, item):
#print "[%s] = %s" % (str(key), str(item))
UserDict.__setitem__(self, key, item)
if key not in self._keys: self._keys.append(key)
def clear(self):
UserDict.clear(self)
self._keys = []
def copy(self):
dict = UserDict.copy(self)
dict._keys = self._keys[:]
return dict
def items(self):
return zip(self._keys, self.values())
def keys(self):
return self._keys
def popitem(self):
try:
key = self._keys[-1]
except IndexError:
raise KeyError('dictionary is empty')
val = self[key]
del self[key]
return (key, val)
def setdefault(self, key, failobj = None):
UserDict.setdefault(self, key, failobj)
if key not in self._keys: self._keys.append(key)
def update(self, dict):
UserDict.update(self, dict)
for key in dict.keys():
if key not in self._keys: self._keys.append(key)
def values(self):
return map(self.get, self._keys)
# ConfModules(Conf)
# This reads /etc/modprobe.conf into a dictionary keyed on device type,
# holding dictionaries: cm['eth0']['alias'] --> 'smc-ultra'
# cm['eth0']['options'] --> {'io':'0x300', 'irq':'10'}
# cm['eth0']['post-install'] --> ['/bin/foo','arg1','arg2']
# path[*] entries are ignored (but not removed)
# New entries are added at the end to make sure that they
# come after any path[*] entries.
# Comments are delimited by initial '#'
class ConfModules(Conf):
def __init__(self, filename = '/etc/modprobe.conf'):
Conf.__init__(self, filename, '#', '\t ', ' ')
def read(self):
Conf.read(self)
self.initvars()
def initvars(self):
self.vars = odict()
keys = ('alias', 'options', 'install', 'remove')
self.rewind()
while self.findnextcodeline():
var = self.getfields()
# assume no -k field
if len(var) > 2 and var[0] in keys:
if not self.vars.has_key(var[1]):
self.vars[var[1]] = odict({'alias':'', 'options':odict(), 'install':[], 'remove':[]})
if not cmp(var[0], 'alias'):
self.vars[var[1]]['alias'] = var[2]
elif not cmp(var[0], 'options'):
self.vars[var[1]]['options'] = self.splitoptlist(var[2:])
elif not cmp(var[0], 'install'):
self.vars[var[1]]['install'] = var[2:]
elif not cmp(var[0], 'remove'):
self.vars[var[1]]['remove'] = var[2:]
self.nextline()
self.rewind()
def splitoptlist(self, optlist):
dict = odict()
for opt in optlist:
optup = self.splitopt(opt)
if optup:
dict[optup[0]] = optup[1]
return dict
def splitopt(self, opt):
eq = find(opt, '=')
if eq > 0:
return (opt[:eq], opt[eq+1:])
else:
return ()
def joinoptlist(self, dict):
optstring = ''
for key in dict.keys():
optstring = optstring + key + '=' + dict[key] + ' '
return optstring
def __getitem__(self, varname):
if self.vars.has_key(varname):
return self.vars[varname]
else:
return odict()
def __quote(self, s):
s = s.replace('\\', '\\\\')
s = s.replace('*', '\\*')
s = s.replace('?', '\\?')
s = s.replace('.', '\\.')
s = s.replace('(', '\\(')
s = s.replace(')', '\\)')
s = s.replace('^', '\\^')
s = s.replace('$', '\\$')
return s
def __setitem__(self, varname, value):
# set *every* instance (should only be one, but...) to avoid surprises
place=self.tell()
self.vars[varname] = value
for key in value.keys():
self.rewind()
missing=1
findexp = '^[\t ]*' + self.__quote(key) + '[\t ]+' + self.__quote(varname) + '[\t ]+'
if not cmp(key, 'alias'):
endofline = value[key]
replace = key + ' ' + varname + ' ' + endofline
elif not cmp(key, 'options'):
endofline = self.joinoptlist(value[key])
replace = key + ' ' + varname + ' ' + endofline
elif not cmp(key, 'install'):
endofline = joinfields(value[key], ' ')
replace = key + ' ' + varname + ' ' + endofline
elif not cmp(key, 'remove'):
endofline = joinfields(value[key], ' ')
replace = key + ' ' + varname + ' ' + endofline
else:
# some idiot apparantly put an unrecognized key in
# the dictionary; ignore it...
continue
# FIXED: [146291] GUI adds trailing spaces to "options" lines
# in /etc/modprobe.conf when adding/deleting wireless devices
replace = replace.rstrip()
if endofline:
# there's something to write...
while self.findnextline(findexp):
cl = split(self.getline(), '#')
if len(cl) >= 2:
comment = join(cl[1:], '#')
replace += ' #' + comment
self.setline(replace)
missing=0
self.nextline()
if missing:
self.fsf()
self.insertline(replace)
else:
# delete any instances of this if they exist.
while self.findnextline(findexp):
self.deleteline()
self.seek(place)
def __delitem__(self, varname):
# delete *every* instance...
place=self.tell()
for key in self.vars[varname].keys():
self.rewind()
while self.findnextline('^[\t ]*' + key + '([\t ]-k)?[\t ]+' + varname):
self.deleteline()
del self.vars[varname]
self.seek(place)
def write(self):
# need to make sure everything is set, because program above may
# well have done cm['eth0']['post-install'] = ['/bin/foo', '-f', '/tmp/bar']
# which is completely reasonable, but won't invoke __setitem__
for key in self.vars.keys():
self[key] = self.vars[key]
Conf.write(self)
def keys(self):
return self.vars.keys()
def has_key(self, key):
return self.vars.has_key(key)
# ConfModInfo(Conf)
# This READ-ONLY class reads /boot/module-info.
# The first line of /boot/module-info is "Version <version>";
# this class reads versions 0 and 1 module-info files.
class ConfModInfo(Conf):
def __init__(self, filename = '/boot/module-info'):
Conf.__init__(self, filename, '#', '\t ', ' ', create_if_missing=0)
def read(self):
Conf.read(self)
self.initvars()
def initvars(self):
self.vars = {}
self.rewind()
device = 0
modtype = 1
description = 2
arguments = 3
lookingfor = device
version = self.getfields()
self.nextline()
if not cmp(version[1], '0'):
# Version 0 file format
while self.findnextcodeline():
line = self.getline()
if not line[0] in self.separators:
curdev = line
self.vars[curdev] = {}
lookingfor = modtype
elif lookingfor == modtype:
fields = self.getfields()
# first "field" is null (before separators)
self.vars[curdev]['type'] = fields[1]
if len(fields) > 2:
self.vars[curdev]['typealias'] = fields[2]
lookingfor = description
elif lookingfor == description:
self.vars[curdev]['description'] = re.sub(
'^"', '', re.sub(
'^['+self.separators+']', '', re.sub(
'"['+self.separators+']*$', '', line)))
lookingfor = arguments
elif lookingfor == arguments:
if not self.vars[curdev].has_key('arguments'):
self.vars[curdev]['arguments'] = {}
# get argument name (first "field" is null again)
thislist = []
# point at first character of argument description
p = find(line, '"')
while p != -1 and p < len(line):
q = find(line[p+1:], '"')
# deal with escaped quotes (\")
while q != -1 and not cmp(line[p+q-1], '\\'):
q = find(line[p+q+1:], '"')
if q == -1:
break
thislist.append(line[p+1:p+q+1])
# advance to beginning of next string, if any
r = find(line[p+q+2:], '"')
if r >= 0:
p = p+q+2+r
else:
# end of the line
p = r
self.vars[curdev]['arguments'][self.getfields()[1]] = thislist
self.nextline()
elif not cmp(version[1], '1'):
# Version 1 file format
# Version 1 format uses ' ' and ':' characters as field separators
# but only uses ' ' in one place, where we explicitly look for it.
self.separators = ':'
while self.findnextcodeline():
line = self.getline()
fields = self.getfields()
# pull out module and linetype from the first field...
(module, linetype) = re.split('[ \t]+', fields[0])
if not cmp(linetype, 'type'):
pass
elif not cmp(linetype, 'alias'):
pass
elif not cmp(linetype, 'desc'):
pass
elif not cmp(linetype, 'argument'):
pass
elif not cmp(linetype, 'supports'):
pass
elif not cmp(linetype, 'arch'):
pass
elif not cmp(linetype, 'pcimagic'):
pass
else:
# error: unknown flag...
raise BadFile, 'unknown flag' + linetype
else:
print 'Only versions 0 and 1 module-info files are supported'
raise VersionMismatch, 'Only versions 0 and 1 module-info files are supported'
self.rewind()
def __getitem__(self, varname):
if self.vars.has_key(varname):
return self.vars[varname]
else:
return {}
def keys(self):
return self.vars.keys()
def has_key(self, key):
return self.vars.has_key(key)
def write(self):
pass
# ConfPw(Conf)
# This class implements a dictionary based on a :-separated file.
# It takes as arguments the filename and the field number to key on;
# The data provided is a list including all fields including the key.
# Has its own write method to keep files sane.
class ConfPw(Conf):
def __init__(self, filename, keyfield, numfields):
self.keyfield = keyfield
self.numfields = numfields
Conf.__init__(self, filename, '', ':', ':', 0)
def read(self):
Conf.read(self)
self.initvars()
def initvars(self):
self.vars = {}
# need to be able to return the keys in order to keep
# things consistent...
self.ordered_keys = []
self.rewind()
while self.findnextcodeline():
fields = self.getfields()
self.vars[fields[self.keyfield]] = fields
self.ordered_keys.append(fields[self.keyfield])
self.nextline()
self.rewind()
def __setitem__(self, key, value):
if not self.findlinewithfield(self.keyfield, key):
self.fsf()
self.ordered_keys.append(key)
self.setfields(value)
self.vars[key] = value
def __getitem__(self, key):
if self.vars.has_key(key):
return self.vars[key]
return []
def __delitem__(self, key):
place = self.tell()
self.rewind()
if self.findlinewithfield(self.keyfield, key):
self.deleteline()
if self.vars.has_key(key):
del self.vars[key]
for i in range(len(self.ordered_keys)):
if key in self.ordered_keys[i:i+1]:
self.ordered_keys[i:i+1] = []
break
self.seek(place)
def keys(self):
return self.ordered_keys
def has_key(self, key):
return self.vars.has_key(key)
def write(self):
self.file = open(self.filename + '.new', 'w', -1)
# change the mode of the new file to that of the old one
if os.path.isfile(self.filename) and self.mode == -1:
os.chmod(self.filename + '.new', os.stat(self.filename)[0])
if self.mode >= 0:
os.chmod(self.filename + '.new', self.mode)
# add newlines while writing
for index in range(len(self.lines)):
self.file.write(self.lines[index] + '\n')
self.file.close()
os.rename(self.filename + '.new', self.filename)
def changefield(self, key, fieldno, fieldtext):
self.rewind()
self.findlinewithfield(self.keyfield, key)
Conf.changefield(self, fieldno, fieldtext)
self.vars[key][fieldno:fieldno+1] = [fieldtext]
# ConfPwO
# This class presents a data-oriented meta-class for making
# changes to ConfPw-managed files. Applications should not
# instantiate this class directly.
class ConfPwO(ConfPw):
def __init__(self, filename, keyfield, numfields, reflector):
ConfPw.__init__(self, filename, keyfield, numfields)
self.reflector = reflector
def __getitem__(self, key):
if self.vars.has_key(key):
return self.reflector(self, key)
else:
return None
def __setitem__(self, key):
# items are objects which the higher-level code can't touch
raise AttributeError, 'Object ' + self + ' is immutable'
# __delitem__ is inherited from ConfPw
# Do *not* use setitem for this; adding an entry should be
# a much different action than accessing an entry or changing
# fields in an entry.
def addentry(self, key, list):
if self.vars.has_key(key):
raise AttributeError, key + ' exists'
ConfPw.__setitem__(self, key, list)
def getfreeid(self, fieldnum):
freeid = 500
# first, we try not to re-use id's that have already been assigned.
for item in self.vars.keys():
id = atoi(self.vars[item][fieldnum])
if id >= freeid and id < 65533: # ignore nobody on some systems
freeid = id + 1
if freeid > 65533:
# if that didn't work, we go back and find any free id over 500
ids = {}
for item in self.vars.keys():
ids[atoi(self.vars[item][fieldnum])] = 1
i = 500
while i < 65535 and ids.has_key(i):
i = i + 1
if freeid > 65533:
raise SystemFull, 'No IDs available'
return freeid
# ConfPasswd(ConfPwO)
# This class presents a data-oriented class for making changes
# to the /etc/passwd file.
class _passwd_reflector:
# first, we need a helper class...
def __init__(self, pw, user):
self.pw = pw
self.user = user
def setgecos(self, oldgecos, fieldnum, value):
gecosfields = split(oldgecos, ',')
# make sure that we have enough gecos fields
for i in range(5-len(gecosfields)):
gecosfields.append('')
gecosfields[fieldnum] = value
return join(gecosfields[0:5], ',')
def getgecos(self, oldgecos, fieldnum):
gecosfields = split(oldgecos, ',')
# make sure that we have enough gecos fields
for i in range(5-len(gecosfields)):
gecosfields.append('')
return gecosfields[fieldnum]
def __getitem__(self, name):
return self.__getattr__(name)
def __setitem__(self, name, value):
return self.__setattr__(name, value)
def __getattr__(self, name):
if not self.pw.has_key(self.user):
raise AttributeError, self.user + ' has been deleted'
if not cmp(name,'username'):
return self.pw.vars[self.user][0]
elif not cmp(name,'password'):
return self.pw.vars[self.user][1]
elif not cmp(name,'uid'):
return self.pw.vars[self.user][2]
elif not cmp(name,'gid'):
return self.pw.vars[self.user][3]
elif not cmp(name,'gecos'):
return self.pw.vars[self.user][4]
elif not cmp(name,'fullname'):
return self.getgecos(self.pw.vars[self.user][4], 0)
elif not cmp(name,'office'):
return self.getgecos(self.pw.vars[self.user][4], 1)
elif not cmp(name,'officephone'):
return self.getgecos(self.pw.vars[self.user][4], 2)
elif not cmp(name,'homephone'):
return self.getgecos(self.pw.vars[self.user][4], 3)
elif not cmp(name,'homedir'):
return self.pw.vars[self.user][5]
elif not cmp(name,'shell'):
return self.pw.vars[self.user][6]
else:
raise AttributeError, name
def __setattr__(self, name, value):
if not cmp(name, 'pw') or not cmp(name, 'user') \
or not cmp(name, 'setgecos') \
or not cmp(name, 'getgecos'):
self.__dict__[name] = value
return None
if not self.pw.has_key(self.user):
raise AttributeError, self.user + ' has been deleted'
if not cmp(name,'username'):
# username is not an lvalue...
raise AttributeError, name + ': key is immutable'
elif not cmp(name,'password'):
self.pw.changefield(self.user, 1, value)
elif not cmp(name,'uid'):
self.pw.changefield(self.user, 2, str(value))
elif not cmp(name,'gid'):
self.pw.changefield(self.user, 3, str(value))
elif not cmp(name,'gecos'):
self.pw.changefield(self.user, 4, value)
elif not cmp(name,'fullname'):
self.pw.changefield(self.user, 4,
self.setgecos(self.pw.vars[self.user][4], 0, value))
elif not cmp(name,'office'):
self.pw.changefield(self.user, 4,
self.setgecos(self.pw.vars[self.user][4], 1, value))
elif not cmp(name,'officephone'):
self.pw.changefield(self.user, 4,
self.setgecos(self.pw.vars[self.user][4], 2, value))
elif not cmp(name,'homephone'):
self.pw.changefield(self.user, 4,
self.setgecos(self.pw.vars[self.user][4], 3, value))
elif not cmp(name,'homedir'):
self.pw.changefield(self.user, 5, value)
elif not cmp(name,'shell'):
self.pw.changefield(self.user, 6, value)
else:
raise AttributeError, name
class ConfPasswd(ConfPwO):
def __init__(self):
ConfPwO.__init__(self, '/etc/passwd', 0, 7, _passwd_reflector)
def addentry(self, username, password, uid, gid, gecos, homedir, shell):
ConfPwO.addentry(self, username, [username, password, uid, gid, gecos, homedir, shell])
def addfullentry(self, username, password, uid, gid, fullname, office,
officephone, homephone, homedir, shell):
self.addentry(username, password, uid, gid, join([fullname,
office, officephone, homephone, ''], ','), homedir, shell)
def getfreeuid(self):
try:
return self.getfreeid(2)
except:
raise SystemFull, 'No UIDs available'
# ConfShadow(ConfPwO)
# This class presents a data-oriented class for making changes
# to the /etc/shadow file.
class _shadow_reflector:
# first, we need a helper class...
def __init__(self, pw, user):
self.pw = pw
self.user = user
def _readstr(self, fieldno):
return self.pw.vars[self.user][fieldno]
def _readint(self, fieldno):
retval = self.pw.vars[self.user][fieldno]
if len(retval): return atoi(retval)
return -1
def __getitem__(self, name):
return self.__getattr__(name)
def __setitem__(self, name, value):
return self.__setattr__(name, value)
def __getattr__(self, name):
if not self.pw.has_key(self.user):
raise AttributeError, self.user + ' has been deleted'
if not cmp(name,'username'):
return self._readstr(0)
elif not cmp(name,'password'):
return self._readstr(1)
elif not cmp(name,'lastchanged'):
return self._readint(2)
elif not cmp(name,'mindays'):
return self._readint(3)
elif not cmp(name,'maxdays'):
return self._readint(4)
elif not cmp(name,'warndays'):
return self._readint(5)
elif not cmp(name,'gracedays'):
return self._readint(6)
elif not cmp(name,'expires'):
return self._readint(7)
else:
raise AttributeError, name
def __setattr__(self, name, value):
if not cmp(name, 'pw') or not cmp(name, 'user'):
self.__dict__[name] = value
return None
if not self.pw.has_key(self.user):
raise AttributeError, self.user + ' has been deleted'
if not cmp(name,'username'):
# username is not an lvalue...
raise AttributeError, name + ': key is immutable'
elif not cmp(name,'password'):
self.pw.changefield(self.user, 1, value)
elif not cmp(name,'lastchanged'):
if not len(str(value)) or value == -1:
raise AttributeError, 'illegal value for lastchanged'
self.pw.changefield(self.user, 2, str(value))
elif not cmp(name,'mindays'):
if not len(str(value)) or value == -1:
value = ''
self.pw.changefield(self.user, 3, str(value))
elif not cmp(name,'maxdays'):
if not len(str(value)) or value == -1:
value = ''
self.pw.changefield(self.user, 4, str(value))
elif not cmp(name,'warndays'):
if not len(str(value)) or value == -1:
value = ''
self.pw.changefield(self.user, 5, str(value))
elif not cmp(name,'gracedays'):
if not len(str(value)) or value == -1:
value = ''
self.pw.changefield(self.user, 6, str(value))
elif not cmp(name,'expires'):
if not len(str(value)) or value == -1:
value = ''
self.pw.changefield(self.user, 7, str(value))
else:
raise AttributeError, name
class ConfShadow(ConfPwO):
def __init__(self):
ConfPwO.__init__(self, '/etc/shadow', 0, 9, _shadow_reflector)
def addentry(self, username, password, lastchanged, mindays, maxdays, warndays, gracedays, expires):
# we need that final '' so that the final : (delimited the
# "reserved field" is preserved by ConfPwO.addentry())
ConfPwO.addentry(self, username,
[username, password, self._intfield(lastchanged),
self._intfield(mindays), self._intfield(maxdays),
self._intfield(warndays), self._intfield(gracedays),
self._intfield(expires), ''])
def _intfield(self, value):
try:
atoi(value)
return value
except:
if value == -1:
return ''
else:
return str(value)
# ConfGroup(ConfPwO)
# This class presents a data-oriented class for making changes
# to the /etc/group file.
# May be replaced by a pwdb-based module, we hope.
class _group_reflector:
# first, we need a helper class...
def __init__(self, pw, group):
self.pw = pw
self.group = group
def __getitem__(self, name):
return self.__getattr__(name)
def __setitem__(self, name, value):
return self.__setattr__(name, value)
def __getattr__(self, name):
if not self.pw.has_key(self.group):
raise AttributeError, self.group + ' has been deleted'
if not cmp(name,'name'):
return self.pw.vars[self.group][0]
elif not cmp(name,'password'):
return self.pw.vars[self.group][1]
elif not cmp(name,'gid'):
return self.pw.vars[self.group][2]
elif not cmp(name,'userlist'):
return self.pw.vars[self.group][3]
else:
raise AttributeError. name
def __setattr__(self, name, value):
if not cmp(name, 'pw') or not cmp(name, 'group'):
self.__dict__[name] = value
return None
if not self.pw.has_key(self.group):
raise AttributeError, self.group + ' has been deleted'
if not cmp(name,'name'):
# username is not an lvalue...
raise AttributeError, name + ': key is immutable'
elif not cmp(name,'password'):
self.pw.changefield(self.group, 1, value)
elif not cmp(name,'gid'):
self.pw.changefield(self.group, 2, str(value))
elif not cmp(name,'userlist'):
self.pw.changefield(self.group, 3, value)
else:
raise AttributeError, name
class ConfGroup(ConfPwO):
def __init__(self):
ConfPwO.__init__(self, '/etc/group', 0, 4, _group_reflector)
def addentry(self, group, password, gid, userlist):
ConfPwO.addentry(self, group, [group, password, gid, userlist])
def getfreegid(self):
try:
return self.getfreeid(2)
except:
raise SystemFull, 'No GIDs available'
def nameofgid(self, gid):
try: gid = atoi(gid)
except: return ''
for group in self.vars.keys():
id = atoi(self.vars[group][2])
if id == gid:
return self.vars[group][0]
return ''
# ConfUnix()
# This class presents a data-oriented class which uses the ConfPasswd
# and ConfShadow classes (if /etc/shadow exists) to hold data.
# Designed to be replaced by a pwdb module eventually, we hope.
class _unix_reflector:
# first, we need a helper class...
def __init__(self, pw, user):
self.pw = pw
self.user = user
def __getitem__(self, name):
return self.__getattr__(name)
def __setitem__(self, name, value):
return self.__setattr__(name, value)
def __getattr__(self, name):
if not self.pw.passwd.has_key(self.user):
raise AttributeError, self.user + ' has been deleted'
if not cmp(name,'username'):
if self.pw.shadow:
return self.pw.shadow[self.user].username
else:
return self.pw.passwd[self.user].username
elif not cmp(name,'password'):
if self.pw.shadow:
return self.pw.shadow[self.user].password
else:
return self.pw.passwd[self.user].password
elif not cmp(name,'uid'):
return self.pw.passwd[self.user].uid
elif not cmp(name,'gid'):
return self.pw.passwd[self.user].gid
elif not cmp(name,'gecos'):
return self.pw.passwd[self.user].gecos
elif not cmp(name,'fullname'):
return self.pw.passwd[self.user].fullname
elif not cmp(name,'office'):
return self.pw.passwd[self.user].office
elif not cmp(name,'officephone'):
return self.pw.passwd[self.user].officephone
elif not cmp(name,'homephone'):
return self.pw.passwd[self.user].homephone
elif not cmp(name,'homedir'):
return self.pw.passwd[self.user].homedir
elif not cmp(name,'shell'):
return self.pw.passwd[self.user].shell
elif not cmp(name,'lastchanged'):
if self.pw.shadowexists():
return self.pw.shadow[self.user].lastchanged
else:
return -1
elif not cmp(name,'mindays'):
if self.pw.shadowexists():
return self.pw.shadow[self.user].mindays
else:
return -1
elif not cmp(name,'maxdays'):
if self.pw.shadowexists():
return self.pw.shadow[self.user].maxdays
else:
return -1
elif not cmp(name,'warndays'):
if self.pw.shadowexists():
return self.pw.shadow[self.user].warndays
else:
return -1
elif not cmp(name,'gracedays'):
if self.pw.shadowexists():
return self.pw.shadow[self.user].gracedays
else:
return -1
elif not cmp(name,'expires'):
if self.pw.shadowexists():
return self.pw.shadow[self.user].expires
else:
return -1
else:
raise AttributeError, name
def __setattr__(self, name, value):
if not cmp(name, 'pw') or not cmp(name, 'user'):
self.__dict__[name] = value
return None
if not self.pw.passwd.has_key(self.user):
raise AttributeError, self.user + ' has been deleted'
if not cmp(name,'username'):
# username is not an lvalue...
raise AttributeError, name + ': key is immutable'
elif not cmp(name,'password'):
if self.pw.shadow:
self.pw.shadow[self.user].password = value
else:
self.pw.passwd[self.user].password = value
elif not cmp(name,'uid'):
self.pw.passwd[self.user].uid = value
elif not cmp(name,'gid'):
self.pw.passwd[self.user].gid = value
elif not cmp(name,'gecos'):
self.pw.passwd[self.user].gecos = value
elif not cmp(name,'fullname'):
self.pw.passwd[self.user].fullname = value
elif not cmp(name,'office'):
self.pw.passwd[self.user].office = value
elif not cmp(name,'officephone'):
self.pw.passwd[self.user].officephone = value
elif not cmp(name,'homephone'):
self.pw.passwd[self.user].homephone = value
elif not cmp(name,'homedir'):
self.pw.passwd[self.user].homedir = value
elif not cmp(name,'shell'):
self.pw.passwd[self.user].shell = value
elif not cmp(name,'lastchanged'):
if self.pw.shadowexists():
self.pw.shadow[self.user].lastchanged = value
elif not cmp(name,'mindays'):
if self.pw.shadowexists():
self.pw.shadow[self.user].mindays = value
elif not cmp(name,'maxdays'):
if self.pw.shadowexists():
self.pw.shadow[self.user].maxdays = value
elif not cmp(name,'warndays'):
if self.pw.shadowexists():
self.pw.shadow[self.user].warndays = value
elif not cmp(name,'gracedays'):
if self.pw.shadowexists():
self.pw.shadow[self.user].gracedays = value
elif not cmp(name,'expires'):
if self.pw.shadowexists():
self.pw.shadow[self.user].expires = value
else:
raise AttributeError, name
class ConfSysctl(Conf):
def __init__(self, filename):
Conf.__init__(self, filename, commenttype='#',
separators='=', separator='=')
def read(self):
Conf.read(self)
Conf.sedline(self, '\n', '')
Conf.sedline(self, ' ', ' ')
self.initvars()
def initvars(self):
self.vars = {}
self.rewind()
while self.findnextcodeline():
var = self.getfields()
# fields 1..n are False matches on "=" character in string,
# which is messed up, but try to deal with it
var[1] = joinfields(var[1:len(var)], '=')
# snip off leading and trailing spaces, which are legal (it's
# how sysctl(1) prints them) but can be confusing, and tend to
# screw up Python's dictionaries
var[0] = strip(var[0])
var[1] = strip(var[1])
if self.vars.has_key(var[0]):
self.deleteline()
self.vars[var[0]] = var[1]
else:
self.vars[var[0]] = var[1]
self.line = self.line + 1
self.rewind()
def __setitem__(self, varname, value):
# set it in the line list
self.rewind()
foundit = 0
while self.findnextcodeline():
var = self.getfields()
# snip off leading and trailing spaces, which are legal (it's
# how sysctl(1) prints them) but can be confusing, and tend to
# screw up Python's dictionaries
if(strip(var[0]) == varname):
while(strip(var[0]) == varname):
self.deleteline()
var = self.getfields()
for part in split(value, '\n'):
self.insertline(varname + ' = ' + part)
self.line = self.line + 1
foundit = 1
self.line = self.line + 1
if(foundit == 0):
for part in split(value, '\n'):
self.lines.append(varname + ' = ' + part)
self.rewind()
# re-read the file, sort of
self.initvars()
def __getitem__(self, varname):
if self.vars.has_key(varname):
return self.vars[varname]
else:
return ''
def write(self):
self.file = open(self.filename, 'w', -1)
if self.mode >= 0:
os.chmod(self.filename, self.mode)
# add newlines
for index in range(len(self.lines)):
self.file.write(self.lines[index] + '\n');
self.file.close()