|
Lines 31-94
Link Here
|
| 31 |
# /usr/share/common-licenses/AGPL-3; if not, see |
31 |
# /usr/share/common-licenses/AGPL-3; if not, see |
| 32 |
# <http://www.gnu.org/licenses/>. |
32 |
# <http://www.gnu.org/licenses/>. |
| 33 |
|
33 |
|
| 34 |
import locale |
|
|
| 35 |
import os |
34 |
import os |
| 36 |
import re |
35 |
import re |
| 37 |
import string |
|
|
| 38 |
import shlex |
36 |
import shlex |
| 39 |
|
37 |
|
| 40 |
import univention.info_tools as uit |
38 |
import univention.info_tools as uit |
| 41 |
|
39 |
|
| 42 |
class Service( uit.LocalizedDictionary ): |
40 |
class Service(uit.LocalizedDictionary): |
| 43 |
def __init__( self ): |
41 |
def __init__(self): |
| 44 |
uit.LocalizedDictionary.__init__( self ) |
42 |
uit.LocalizedDictionary.__init__(self) |
| 45 |
self.start_runlevel = [] |
43 |
self.start_runlevel = [] |
| 46 |
self.stop_runlevel = [] |
44 |
self.stop_runlevel = [] |
| 47 |
self.start_code = 0 |
45 |
self.start_code = 0 |
| 48 |
self.stop_code = 0 |
46 |
self.stop_code = 0 |
| 49 |
self.running = False |
47 |
self.running = False |
| 50 |
|
48 |
|
| 51 |
def check( self ): |
49 |
def check(self): |
| 52 |
"""Check service entry for validity, returning list of incomplete entries.""" |
50 |
"""Check service entry for validity, returning list of incomplete entries.""" |
| 53 |
incomplete = [] |
51 |
incomplete = [] |
| 54 |
for key in ( 'description', 'programs' ): |
52 |
for key in ('description', 'programs'): |
| 55 |
if not self.get( key, None ): |
53 |
if not self.get(key, None): |
| 56 |
incomplete.append(key) |
54 |
incomplete.append(key) |
| 57 |
return incomplete |
55 |
return incomplete |
| 58 |
|
56 |
|
| 59 |
def pidof( name ): |
57 |
|
| 60 |
result = [] |
58 |
def pidof(name): |
| 61 |
for file in os.listdir( '/proc' ): |
59 |
""" |
| 62 |
dir = os.path.join( '/proc', file ) |
60 |
Return list of process IDs matching name. |
| 63 |
if not os.path.isdir( dir ): |
61 |
>>> import os,sys;str(os.getpid()) in pidof(sys.executable) |
| 64 |
continue |
62 |
True |
| 65 |
if not os.path.isfile( os.path.join( dir, 'stat' ) ): |
63 |
""" |
| 66 |
continue |
64 |
cmd = shlex.split(name) |
| 67 |
cmdline = os.path.join( dir, 'cmdline' ) |
65 |
for proc in os.listdir('/proc'): |
| 68 |
if not os.path.isfile( cmdline ): |
66 |
cmdline = os.path.join('/proc', proc, 'cmdline') |
|
|
67 |
try: |
| 68 |
with open(cmdline, 'r') as fd: |
| 69 |
commandline = fd.read() |
| 70 |
except EnvironmentError: |
| 69 |
continue |
71 |
continue |
| 70 |
fd = open( cmdline ) |
|
|
| 71 |
cmd = fd.readline() |
| 72 |
# kernel thread |
72 |
# kernel thread |
| 73 |
if not cmd: |
73 |
if not commandline: |
| 74 |
continue |
74 |
continue |
| 75 |
if '\x00' in cmd: |
75 |
if '\x00' in commandline: |
| 76 |
args = cmd.split( '\x00' ) |
76 |
args = commandline.split('\x00') |
| 77 |
else: |
77 |
else: |
| 78 |
args = cmd.split(' ') |
78 |
args = commandline.split(' ') |
| 79 |
cmd = shlex.split( name ) |
|
|
| 80 |
if cmd[0] in args: |
79 |
if cmd[0] in args: |
| 81 |
if len( cmd ) > 1 and len( args ) >= len( cmd ): |
80 |
if len(args) >= len(cmd) > 1: |
| 82 |
for i in range( 1, len( cmd ) ): |
81 |
if all(a == c for a, c in zip(args, cmd)): |
| 83 |
print cmd[ i ], args[ i ] |
82 |
yield proc |
| 84 |
if cmd[ i ] != args[ i ]: |
|
|
| 85 |
break |
| 86 |
else: |
| 87 |
result.append( file ) |
| 88 |
else: |
83 |
else: |
| 89 |
result.append( file ) |
84 |
yield proc |
| 90 |
|
85 |
|
| 91 |
return result |
|
|
| 92 |
|
86 |
|
| 93 |
class ServiceInfo( object ): |
87 |
class ServiceInfo( object ): |
| 94 |
BASE_DIR = '/etc/univention/service.info' |
88 |
BASE_DIR = '/etc/univention/service.info' |
|
Lines 96-103
class ServiceInfo( object ):
Link Here
|
| 96 |
CUSTOMIZED = '_customized' |
90 |
CUSTOMIZED = '_customized' |
| 97 |
FILE_SUFFIX = '.cfg' |
91 |
FILE_SUFFIX = '.cfg' |
| 98 |
|
92 |
|
| 99 |
RUNLEVELS = map(str, range(7)) + ['S'] |
93 |
RUNLEVELS = "0123456S" |
| 100 |
INIT_SCRIPT_REGEX = re.compile( '(?P<action>[SK])(?P<code>[0-9]+)(?P<name>.*)' ) |
94 |
INIT_SCRIPT_REGEX = re.compile('(?P<action>[SK])(?P<code>[0-9]{2})(?P<name>.+)') |
| 101 |
|
95 |
|
| 102 |
def __init__( self, install_mode = False ): |
96 |
def __init__( self, install_mode = False ): |
| 103 |
self.services = {} |
97 |
self.services = {} |
|
Lines 106-143
class ServiceInfo( object ):
Link Here
|
| 106 |
self.update_services() |
100 |
self.update_services() |
| 107 |
|
101 |
|
| 108 |
def sysv_infos( self ): |
102 |
def sysv_infos( self ): |
| 109 |
global _runlevels, _init_link |
103 |
"""Read start/stop levels of services.""" |
| 110 |
|
104 |
for level in ServiceInfo.RUNLEVELS: |
| 111 |
for level in _runlevels: |
105 |
for link in os.listdir('/etc/rc%s.d/' % (level,)): |
| 112 |
for link in os.listdir( '/etc/rc%s.d/' % level ): |
|
|
| 113 |
if not os.path.islink( link ): |
106 |
if not os.path.islink( link ): |
| 114 |
continue |
107 |
continue |
| 115 |
matches = _init_link.match( link ) |
108 |
match = ServiceInfo.INIT_SCRIPT_REGEX.match(link) |
| 116 |
if not matches: |
109 |
if not match: |
| 117 |
continue |
110 |
continue |
| 118 |
grp = matches.groupdict() |
111 |
action, code, name = match.groups() |
| 119 |
|
112 |
try: |
| 120 |
name = grp.get( 'name', '' ) |
113 |
service = self.service[name] |
| 121 |
if not name or not name in self.services.keys(): |
114 |
except LookupError: |
| 122 |
continue |
115 |
continue |
| 123 |
if grp.get( 'action', '' ) == 'S': |
116 |
if action == 'S': |
| 124 |
self.services[ name ].start_runlevels.append( level ) |
117 |
service.start_runlevels.append(level) |
| 125 |
self.services[ name ].start_code = int( grp[ 'code' ] ) |
118 |
service.start_code = int(code) |
| 126 |
elif grp.get( 'action', '' ) == 'K': |
119 |
elif action == 'K': |
| 127 |
self.services[ name ].start_runlevels.append( level ) |
120 |
service.stop_runlevels.append(level) |
| 128 |
self.services[ name ].start_code = int( grp[ 'code' ] ) |
121 |
service.stop_code = int(code) |
| 129 |
|
122 |
|
| 130 |
def __update_status( self, name, service ): |
123 |
def __update_status(self, name, service): |
| 131 |
for prog in service[ 'programs' ].split( ',' ): |
124 |
for prog in service['programs'].split(','): |
| 132 |
if prog and not pidof( prog.strip() ): |
125 |
if prog and not pidof(prog.strip()): |
| 133 |
service.running = False |
126 |
service.running = False |
| 134 |
break |
127 |
break |
| 135 |
else: |
128 |
else: |
| 136 |
service.running = True |
129 |
service.running = True |
| 137 |
|
130 |
|
| 138 |
def update_services( self ): |
131 |
def update_services( self ): |
|
|
132 |
"""Update the run state of all services.""" |
| 139 |
for name, serv in self.services.items(): |
133 |
for name, serv in self.services.items(): |
| 140 |
self.__update_status( name, serv ) |
134 |
self.__update_status(name, serv) |
| 141 |
|
135 |
|
| 142 |
def check_services( self ): |
136 |
def check_services( self ): |
| 143 |
"""Return dictionary of incomplete service descriptions.""" |
137 |
"""Return dictionary of incomplete service descriptions.""" |
|
Lines 149-159
class ServiceInfo( object ):
Link Here
|
| 149 |
return incomplete |
143 |
return incomplete |
| 150 |
|
144 |
|
| 151 |
def write_customized( self ): |
145 |
def write_customized( self ): |
|
|
146 |
"""Save service cusomization.""" |
| 152 |
filename = os.path.join( ServiceInfo.BASE_DIR, ServiceInfo.SERVICES, |
147 |
filename = os.path.join( ServiceInfo.BASE_DIR, ServiceInfo.SERVICES, |
| 153 |
ServiceInfo.CUSTOMIZED ) |
148 |
ServiceInfo.CUSTOMIZED ) |
| 154 |
try: |
149 |
try: |
| 155 |
fd = open( filename, 'w' ) |
150 |
fd = open(filename, 'w') |
| 156 |
except: |
151 |
except IOError: |
| 157 |
return False |
152 |
return False |
| 158 |
|
153 |
|
| 159 |
cfg = uit.UnicodeConfig() |
154 |
cfg = uit.UnicodeConfig() |
|
Lines 176-189
class ServiceInfo( object ):
Link Here
|
| 176 |
filename = os.path.join( ServiceInfo.BASE_DIR, ServiceInfo.SERVICES, |
171 |
filename = os.path.join( ServiceInfo.BASE_DIR, ServiceInfo.SERVICES, |
| 177 |
package + ServiceInfo.FILE_SUFFIX ) |
172 |
package + ServiceInfo.FILE_SUFFIX ) |
| 178 |
cfg = uit.UnicodeConfig() |
173 |
cfg = uit.UnicodeConfig() |
| 179 |
cfg.read( filename ) |
174 |
cfg.read(filename) |
| 180 |
for sec in cfg.sections(): |
175 |
for sec in cfg.sections(): |
| 181 |
# service already known? |
176 |
# service already known? |
| 182 |
if not override and sec in self.services.keys(): |
177 |
if not override and sec in self.services: |
| 183 |
continue |
178 |
continue |
| 184 |
srv = Service() |
179 |
srv = Service() |
| 185 |
for name, value in cfg.items( sec ): |
180 |
for name, value in cfg.items(sec): |
| 186 |
srv[ name ] = value |
181 |
srv[name] = value |
| 187 |
for path in srv.get('programs', '').split(','): |
182 |
for path in srv.get('programs', '').split(','): |
| 188 |
# "programs" defines the "/proc/self/cmdline" of the service, |
183 |
# "programs" defines the "/proc/self/cmdline" of the service, |
| 189 |
# not the executable, therefore we test for a leading "/": |
184 |
# not the executable, therefore we test for a leading "/": |
|
Lines 191-199
class ServiceInfo( object ):
Link Here
|
| 191 |
if path.startswith('/') and not os.path.exists(path.split(' ', 1)[0]): |
186 |
if path.startswith('/') and not os.path.exists(path.split(' ', 1)[0]): |
| 192 |
break # ==> do not execute else |
187 |
break # ==> do not execute else |
| 193 |
else: |
188 |
else: |
| 194 |
self.services[ sec ] = srv |
189 |
self.services[sec] = srv |
| 195 |
|
190 |
|
| 196 |
def __load_services( self ): |
191 |
def __load_services( self ): |
|
|
192 |
"""Load definition of all defined services.""" |
| 197 |
path = os.path.join( ServiceInfo.BASE_DIR, ServiceInfo.SERVICES ) |
193 |
path = os.path.join( ServiceInfo.BASE_DIR, ServiceInfo.SERVICES ) |
| 198 |
for entry in os.listdir( path ): |
194 |
for entry in os.listdir( path ): |
| 199 |
# customized service descrptions are read afterwards |
195 |
# customized service descrptions are read afterwards |
|
Lines 206-211
class ServiceInfo( object ):
Link Here
|
| 206 |
self.read_customized() |
202 |
self.read_customized() |
| 207 |
|
203 |
|
| 208 |
def read_customized( self ): |
204 |
def read_customized( self ): |
|
|
205 |
"""Read service cusomization.""" |
| 209 |
custom = os.path.join( ServiceInfo.BASE_DIR, ServiceInfo.SERVICES, |
206 |
custom = os.path.join( ServiceInfo.BASE_DIR, ServiceInfo.SERVICES, |
| 210 |
ServiceInfo.CUSTOMIZED ) |
207 |
ServiceInfo.CUSTOMIZED ) |
| 211 |
self.read_services( custom, override = True ) |
208 |
self.read_services( custom, override = True ) |
|
Lines 217-226
class ServiceInfo( object ):
Link Here
|
| 217 |
def get_service( self, name ): |
214 |
def get_service( self, name ): |
| 218 |
'''returns a service object associated with the given name or |
215 |
'''returns a service object associated with the given name or |
| 219 |
None if it does not exist''' |
216 |
None if it does not exist''' |
| 220 |
self.services.get( name, None ) |
217 |
return self.services.get( name, None ) |
| 221 |
|
218 |
|
| 222 |
def add_service( self, name, service ): |
219 |
def add_service( self, name, service ): |
| 223 |
'''this methods adds a new service object or overrides an old |
220 |
'''this methods adds a new service object or overrides an old |
| 224 |
entry''' |
221 |
entry''' |
| 225 |
if not service.check(): |
222 |
if not service.check(): |
| 226 |
self.services[ name ] = service |
223 |
self.services[ name ] = service |
|
|
224 |
|
| 225 |
|
| 226 |
if __name__ == '__main__': |
| 227 |
import doctest |
| 228 |
doctest.testmod() |