diff --git a/branches/ucs-3.1/ucs-3.1-2/base/univention-config-registry/python/univention/service_info.py b/branches/ucs-3.1/ucs-3.1-2/base/univention-config-registry/python/univention/service_info.py
index d3542ae..316cf78 100644
--- a/branches/ucs-3.1/ucs-3.1-2/base/univention-config-registry/python/univention/service_info.py
+++ b/branches/ucs-3.1/ucs-3.1-2/base/univention-config-registry/python/univention/service_info.py
@@ -31,64 +31,58 @@
# /usr/share/common-licenses/AGPL-3; if not, see
# .
-import locale
import os
import re
-import string
import shlex
import univention.info_tools as uit
-class Service( uit.LocalizedDictionary ):
- def __init__( self ):
- uit.LocalizedDictionary.__init__( self )
+class Service(uit.LocalizedDictionary):
+ def __init__(self):
+ uit.LocalizedDictionary.__init__(self)
self.start_runlevel = []
self.stop_runlevel = []
self.start_code = 0
self.stop_code = 0
self.running = False
- def check( self ):
+ def check(self):
"""Check service entry for validity, returning list of incomplete entries."""
incomplete = []
- for key in ( 'description', 'programs' ):
- if not self.get( key, None ):
+ for key in ('description', 'programs'):
+ if not self.get(key, None):
incomplete.append(key)
return incomplete
-def pidof( name ):
- result = []
- for file in os.listdir( '/proc' ):
- dir = os.path.join( '/proc', file )
- if not os.path.isdir( dir ):
- continue
- if not os.path.isfile( os.path.join( dir, 'stat' ) ):
- continue
- cmdline = os.path.join( dir, 'cmdline' )
- if not os.path.isfile( cmdline ):
+
+def pidof(name):
+ """
+ Return list of process IDs matching name.
+ >>> import os,sys;str(os.getpid()) in pidof(sys.executable)
+ True
+ """
+ cmd = shlex.split(name)
+ for proc in os.listdir('/proc'):
+ cmdline = os.path.join('/proc', proc, 'cmdline')
+ try:
+ with open(cmdline, 'r') as fd:
+ commandline = fd.read()
+ except EnvironmentError:
continue
- fd = open( cmdline )
- cmd = fd.readline()
# kernel thread
- if not cmd:
+ if not commandline:
continue
- if '\x00' in cmd:
- args = cmd.split( '\x00' )
+ if '\x00' in commandline:
+ args = commandline.split('\x00')
else:
- args = cmd.split(' ')
- cmd = shlex.split( name )
+ args = commandline.split(' ')
if cmd[0] in args:
- if len( cmd ) > 1 and len( args ) >= len( cmd ):
- for i in range( 1, len( cmd ) ):
- print cmd[ i ], args[ i ]
- if cmd[ i ] != args[ i ]:
- break
- else:
- result.append( file )
+ if len(args) >= len(cmd) > 1:
+ if all(a == c for a, c in zip(args, cmd)):
+ yield proc
else:
- result.append( file )
+ yield proc
- return result
class ServiceInfo( object ):
BASE_DIR = '/etc/univention/service.info'
@@ -96,8 +90,8 @@ class ServiceInfo( object ):
CUSTOMIZED = '_customized'
FILE_SUFFIX = '.cfg'
- RUNLEVELS = map(str, range(7)) + ['S']
- INIT_SCRIPT_REGEX = re.compile( '(?P[SK])(?P[0-9]+)(?P.*)' )
+ RUNLEVELS = "0123456S"
+ INIT_SCRIPT_REGEX = re.compile('(?P[SK])(?P[0-9]{2})(?P.+)')
def __init__( self, install_mode = False ):
self.services = {}
@@ -106,38 +100,38 @@ class ServiceInfo( object ):
self.update_services()
def sysv_infos( self ):
- global _runlevels, _init_link
-
- for level in _runlevels:
- for link in os.listdir( '/etc/rc%s.d/' % level ):
+ """Read start/stop levels of services."""
+ for level in ServiceInfo.RUNLEVELS:
+ for link in os.listdir('/etc/rc%s.d/' % (level,)):
if not os.path.islink( link ):
continue
- matches = _init_link.match( link )
- if not matches:
+ match = ServiceInfo.INIT_SCRIPT_REGEX.match(link)
+ if not match:
continue
- grp = matches.groupdict()
-
- name = grp.get( 'name', '' )
- if not name or not name in self.services.keys():
+ action, code, name = match.groups()
+ try:
+ service = self.service[name]
+ except LookupError:
continue
- if grp.get( 'action', '' ) == 'S':
- self.services[ name ].start_runlevels.append( level )
- self.services[ name ].start_code = int( grp[ 'code' ] )
- elif grp.get( 'action', '' ) == 'K':
- self.services[ name ].start_runlevels.append( level )
- self.services[ name ].start_code = int( grp[ 'code' ] )
-
- def __update_status( self, name, service ):
- for prog in service[ 'programs' ].split( ',' ):
- if prog and not pidof( prog.strip() ):
+ if action == 'S':
+ service.start_runlevels.append(level)
+ service.start_code = int(code)
+ elif action == 'K':
+ service.stop_runlevels.append(level)
+ service.stop_code = int(code)
+
+ def __update_status(self, name, service):
+ for prog in service['programs'].split(','):
+ if prog and not pidof(prog.strip()):
service.running = False
break
else:
service.running = True
def update_services( self ):
+ """Update the run state of all services."""
for name, serv in self.services.items():
- self.__update_status( name, serv )
+ self.__update_status(name, serv)
def check_services( self ):
"""Return dictionary of incomplete service descriptions."""
@@ -149,11 +143,12 @@ class ServiceInfo( object ):
return incomplete
def write_customized( self ):
+ """Save service cusomization."""
filename = os.path.join( ServiceInfo.BASE_DIR, ServiceInfo.SERVICES,
ServiceInfo.CUSTOMIZED )
try:
- fd = open( filename, 'w' )
- except:
+ fd = open(filename, 'w')
+ except IOError:
return False
cfg = uit.UnicodeConfig()
@@ -176,14 +171,14 @@ class ServiceInfo( object ):
filename = os.path.join( ServiceInfo.BASE_DIR, ServiceInfo.SERVICES,
package + ServiceInfo.FILE_SUFFIX )
cfg = uit.UnicodeConfig()
- cfg.read( filename )
+ cfg.read(filename)
for sec in cfg.sections():
# service already known?
- if not override and sec in self.services.keys():
+ if not override and sec in self.services:
continue
srv = Service()
- for name, value in cfg.items( sec ):
- srv[ name ] = value
+ for name, value in cfg.items(sec):
+ srv[name] = value
for path in srv.get('programs', '').split(','):
# "programs" defines the "/proc/self/cmdline" of the service,
# not the executable, therefore we test for a leading "/":
@@ -191,9 +186,10 @@ class ServiceInfo( object ):
if path.startswith('/') and not os.path.exists(path.split(' ', 1)[0]):
break # ==> do not execute else
else:
- self.services[ sec ] = srv
+ self.services[sec] = srv
def __load_services( self ):
+ """Load definition of all defined services."""
path = os.path.join( ServiceInfo.BASE_DIR, ServiceInfo.SERVICES )
for entry in os.listdir( path ):
# customized service descrptions are read afterwards
@@ -206,6 +202,7 @@ class ServiceInfo( object ):
self.read_customized()
def read_customized( self ):
+ """Read service cusomization."""
custom = os.path.join( ServiceInfo.BASE_DIR, ServiceInfo.SERVICES,
ServiceInfo.CUSTOMIZED )
self.read_services( custom, override = True )
@@ -217,10 +214,15 @@ class ServiceInfo( object ):
def get_service( self, name ):
'''returns a service object associated with the given name or
None if it does not exist'''
- self.services.get( name, None )
+ return self.services.get( name, None )
def add_service( self, name, service ):
'''this methods adds a new service object or overrides an old
entry'''
if not service.check():
self.services[ name ] = service
+
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod()