diff options
-rw-r--r-- | schemas/pathentry.xsd | 3 | ||||
-rw-r--r-- | schemas/rules.xsd | 13 | ||||
-rw-r--r-- | schemas/types.xsd | 2 | ||||
-rw-r--r-- | src/lib/Client/Tools/POSIX.py | 101 | ||||
-rw-r--r-- | src/lib/Server/Plugins/POSIXCompat.py | 16 |
5 files changed, 112 insertions, 23 deletions
diff --git a/schemas/pathentry.xsd b/schemas/pathentry.xsd index 5e129fa75..7be0e37e2 100644 --- a/schemas/pathentry.xsd +++ b/schemas/pathentry.xsd @@ -8,10 +8,7 @@ </xsd:documentation> </xsd:annotation> - <xsd:include schemaLocation="types.xsd"/> - <xsd:complexType name='PathEntry'> <xsd:attribute type='xsd:string' name='name' use='required'/> - <xsd:attribute name='type' use='required' type='PathTypeEnum' /> </xsd:complexType> </xsd:schema> diff --git a/schemas/rules.xsd b/schemas/rules.xsd index 0baa1e25f..d9b99d63d 100644 --- a/schemas/rules.xsd +++ b/schemas/rules.xsd @@ -33,6 +33,18 @@ <xsd:attribute type='xsd:string' name='to' use='required'/> </xsd:complexType> + <xsd:complexType name='PathType'> + <xsd:attribute type='PathTypeEnum' name='type' use='required'/> + <xsd:attribute type='xsd:string' name='name' use='required'/> + <xsd:attribute type='xsd:string' name='dev_type'/> + <xsd:attribute type='xsd:string' name='major'/> + <xsd:attribute type='xsd:string' name='minor'/> + <xsd:attribute type='xsd:string' name='mode'/> + <xsd:attribute type='xsd:string' name='perms'/> + <xsd:attribute type='xsd:string' name='owner'/> + <xsd:attribute type='xsd:string' name='group'/> + </xsd:complexType> + <xsd:complexType name='PermissionsType'> <xsd:attribute type='xsd:string' name='name' use='required'/> <xsd:attribute type='xsd:string' name='perms' use='required'/> @@ -63,6 +75,7 @@ <xsd:element name='Directory' type='DirectoryType'/> <xsd:element name='SymLink' type='SymLinkType'/> <xsd:element name='Package' type='PackageType'/> + <xsd:element name='Path' type='PathType'/> <xsd:element name='Permissions' type='PermissionsType'/> <xsd:element name='Action' type='ActionType'/> <xsd:element name='Group' type='RContainerType'/> diff --git a/schemas/types.xsd b/schemas/types.xsd index db85bbaab..f04c3140f 100644 --- a/schemas/types.xsd +++ b/schemas/types.xsd @@ -24,7 +24,7 @@ <xsd:simpleType name='PathTypeEnum'> <xsd:restriction base='xsd:string'> <xsd:enumeration value='ConfigFile' /> - <xsd:enumeration value='Device' /> + <xsd:enumeration value='device' /> <xsd:enumeration value='Directory' /> <xsd:enumeration value='HardLink' /> <xsd:enumeration value='Perms' /> diff --git a/src/lib/Client/Tools/POSIX.py b/src/lib/Client/Tools/POSIX.py index d956abf3a..917dc6620 100644 --- a/src/lib/Client/Tools/POSIX.py +++ b/src/lib/Client/Tools/POSIX.py @@ -12,11 +12,20 @@ import logging import os import pwd import shutil +import stat import string import time import Bcfg2.Client.Tools import Bcfg2.Options +log = logging.getLogger('posix') + +# map between dev_type attribute and stat constants +device_map = {'block': stat.S_IFBLK, + 'char': stat.S_IFCHR, + 'fifo': stat.S_IFIFO} + + def calcPerms(initial, perms): '''This compares ondisk permissions with specified ones''' pdisp = [{1:S_ISVTX, 2:S_ISGID, 4:S_ISUID}, @@ -33,8 +42,6 @@ def calcPerms(initial, perms): tempperms |= perm return tempperms -log = logging.getLogger('posix') - def normUid(entry): ''' This takes a user name or uid and @@ -82,7 +89,7 @@ class POSIX(Bcfg2.Client.Tools.Tool): __handles__ = [('ConfigFile', None), ('Directory', None), ('Path', 'ConfigFile'), - ('Path', 'Device'), + ('Path', 'device'), ('Path', 'Directory'), ('Path', 'HardLink'), ('Path', 'Perms'), @@ -140,10 +147,11 @@ class POSIX(Bcfg2.Client.Tools.Tool): fmode = os.lstat(entry.get('name'))[ST_MODE] if S_ISREG(fmode) or S_ISLNK(fmode): self.logger.debug("Non-directory entry already exists at " - "%s. Unlinking entry." % (entry.get('name'))) + "%s. Unlinking entry." % \ + (entry.get('name'))) os.unlink(entry.get('name')) elif S_ISDIR(fmode): - self.logger.debug("Directory entry already exists at %s" % \ + self.logger.debug("Directory entry already exists at %s" %\ (entry.get('name'))) self.cmd.run("mv %s/ %s.bak" % \ (entry.get('name'), @@ -158,12 +166,6 @@ class POSIX(Bcfg2.Client.Tools.Tool): except OSError: return False - def VerifyDevice(self, entry, _): - return False - - def InstallDevice(self, entry): - return False - def VerifyDirectory(self, entry, modlist): '''Verify Directory Entry''' while len(entry.get('perms', '')) < 4: @@ -254,7 +256,6 @@ class POSIX(Bcfg2.Client.Tools.Tool): entry.set('qtext', nnqtext) return pTrue and pruneTrue - def InstallDirectory(self, entry): '''Install Directory Entry''' self.logger.info("Installing Directory %s" % (entry.get('name'))) @@ -382,6 +383,82 @@ class POSIX(Bcfg2.Client.Tools.Tool): (entry.get('name'))) return False + def Verifydevice(self, entry, _): + '''Verify device entry''' + try: + # check for file existence + filestat = os.stat(entry.get('name')) + except OSError: + entry.set('current_exists', 'false') + self.logger.debug("%s %s does not exist" % + (entry.tag, entry.get('name'))) + return False + + try: + # attempt to verify device properties as specified in config + dev_type = entry.get('dev_type') + mode = calcPerms(device_map[dev_type], + entry.get('mode', '0600')) + owner = entry.get('owner') + group = entry.get('group') + if dev_type in ['block', 'char']: + major = int(entry.get('major')) + minor = int(entry.get('minor')) + if major == os.major(filestat.st_rdev) and \ + minor == os.minor(filestat.st_rdev) and \ + mode == filestat.st_mode and \ + owner == filestat.st_uid and \ + group == filestat.st_gid: + return True + else: + return False + elif dev_type == 'fifo' and \ + mode == filestat.st_mode and \ + owner == filestat.st_uid and \ + group == filestat.st_gid: + return True + else: + self.logger.info('Device properties for %s incorrect' % \ + entry.get('name')) + return False + except OSError: + self.logger.debug("%s %s failed to verify" % + (entry.tag, entry.get('name'))) + return False + + def Installdevice(self, entry): + '''Install device entries''' + try: + # check for existing paths and remove them + filestat = os.lstat(entry.get('name')) + try: + os.unlink(entry.get('name')) + exists = False + except OSError: + self.logger.info('Failed to unlink %s' % \ + entry.get('name')) + return False + except OSError: + exists = False + + if not exists: + try: + dev_type = entry.get('dev_type') + mode = calcPerms(device_map[dev_type], + entry.get('mode', '0600')) + if dev_type in ['block', 'char']: + major = int(entry.get('major')) + minor = int(entry.get('minor')) + device = os.makedev(major, minor) + os.mknod(entry.get('name'), mode, device) + else: + os.mknod(entry.get('name'), mode) + os.chown(entry.get('name'), normUid(entry), normGid(entry)) + return True + except OSError: + self.logger.error('Failed to install %s' % entry.get('name')) + return False + def Verifynonexistent(self, entry, _): '''Verify nonexistent entry''' # return true if path does _not_ exist diff --git a/src/lib/Server/Plugins/POSIXCompat.py b/src/lib/Server/Plugins/POSIXCompat.py index 00fdbf65c..d2e530407 100644 --- a/src/lib/Server/Plugins/POSIXCompat.py +++ b/src/lib/Server/Plugins/POSIXCompat.py @@ -8,11 +8,12 @@ import Bcfg2.Server.Plugin # FIXME: We will need this mapping if we decide to change the # specification to use lowercase types for new POSIX entry types -#COMPAT_DICT = {'configfile': 'ConfigFile', -# 'device': 'Device', -# 'directory': 'Directory', -# 'permissions': 'Permissions', -# 'symlink': 'SymLink'} +COMPAT_DICT = {'configfile': 'ConfigFile', + 'device': 'device', + 'directory': 'Directory', + 'nonexistent': 'nonexistent', + 'permissions': 'Permissions', + 'symlink': 'SymLink'} class POSIXCompat(Bcfg2.Server.Plugin.Plugin, Bcfg2.Server.Plugin.GoalValidator): @@ -27,9 +28,10 @@ class POSIXCompat(Bcfg2.Server.Plugin.Plugin, def validate_goals(self, metadata, goals): for goal in goals: for entry in goal.getchildren(): - if entry.tag == 'Path' and entry.get('type') != 'nonexistent': + if entry.tag == 'Path' and \ + entry.get('type') not in ['nonexistent', 'device']: oldentry = entry - entry.tag = entry.get('type') + entry.tag = COMPAT_DICT[entry.get('type')] del entry.attrib['type'] # FIXME: use another attribute? old clients only # know about type=None |