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