1 #! /usr/bin/env python 2 # 3 # Safe ``poff''. 4 # 5 # Still, even 'lynx' and 'python' in ps_ignore_programs could use PPP! 6 # Is there another way of seeing which commands are using PPP, rather 7 # than using output from 'ps'? 8 # 9 # HOW ABOUT: ignore programs with PID lower than pppd. 10 # 11 # So-called "installation:" 12 # 1. rename "/usr/bin/poff" to "/usr/bin/poff_drop_connection". 13 # 2. make "/usr/bin/poff" 14 # #!/bin/sh 15 # script=/home/cymbala/bin/rjc_poff.py 16 # echo "Using ${script}..." 17 # python ${script} 18 # 19 # 20 # 'exp' = 'expected' 21 # ----------------------------------------------------------------------------- 22 23 import re 24 import os 25 import popen2 26 import string 27 28 class my_program: 29 def __init__(self): 30 31 self.ps_syntax = 'ps awx' 32 self.real_poff_command = 'poff_drop_connection' 33 34 # Re. expressions 35 self.re_spaces = re.compile('[ ]{2,}') 36 self.re_digits = re.compile('[0-9]+') 37 38 # Stuff before COMMAND 39 self.PID = '[0-9]+' 40 self.TTY = '(\?|ttyS?[0-9]|pts/[0-9])' 41 self.TTY_abstract = '(\?|ttyS?#|pts/#)' 42 self.cc_PSC = '[DRSTZWNL]+' # STAT: ``man ps'' (omitting '<') 43 self.re_PSC = re.compile(' ' + self.cc_PSC + ' ') 44 self.TIME = '[0-9]+[:][0-9]{2}' 45 self.re_P_T_S_T = re.compile('^ *' + self.PID + ' ' + \ self.TTY + ' +' + self.cc_PSC + \ ' +' + self.TIME +' +') 48 self.re_P_T_S_T_abstract = re.compile('^# ' + self.TTY_abstract + \ ' ' + 'PSC' +' #:# ') 50 pass 51 52 def ppp(self, interface): 53 return_code = 0 54 child_stdout = popen2.popen2('ifconfig ' + interface) 55 data = child_stdout[0].read() 56 if string.find(data, 'inet addr:') < 0: 57 return_code = 1 58 return return_code 59 60 def abstract(self, sequence): 61 # Truncate trailing newlines. 62 # Delete leading spaces. 63 # Change multiple white-space to single space. 64 # Change any number of digits to '#'. 65 # Change process state code to 'PSC'. 66 # 67 68 new_sequence = [] 69 for item in sequence: 70 exp_original = item 71 # SPACES 72 while self.re_spaces.search(item): 73 matchobj = self.re_spaces.search(item) 74 item = item[:matchobj.start(0)] + ' ' + item[matchobj.end(0):] 75 pass 76 # DIGITS 77 while self.re_digits.search(item): 78 matchobj = self.re_digits.search(item) 79 item = item[:matchobj.start(0)] + '#' + item[matchobj.end(0):] 80 pass 81 # NEWLINE 82 if item[-1:] == '\n': 83 item = item[:-1] 84 pass 85 if item[:1] == ' ': 86 item = item[1:] 87 pass 88 # PROCESS STATE CODES 89 while self.re_PSC.search(item): 90 matchobj = self.re_PSC.search(item) 91 item = item[:matchobj.start(0)] + ' PSC ' + \ item[matchobj.end(0):] 93 pass 94 95 new_sequence.append(item) 96 pass 97 return new_sequence 98 99 def examine_processes(self): 100 # Expected lines from 'ps awx'. 101 # Depends on computer set-up. 102 103 # Criteria for ps_ignore_programs: 104 # Programs that can have variable arguments, such as lynx browser. 105 # 106 # Only criteria for elements in ps_exp_abstract: 107 # Do _not_ include commands that depend on PPP connection! 108 # For example, 109 # - exim 110 # - fetchmail 111 # - fetchnews 112 113 # ------------------------------------------------------------------- 114 ps_ignore_programs = [] 117 # 118 ps_ignore_programs.append('anacron') 119 ps_ignore_programs.append('bash') 120 ps_ignore_programs.append('bc') 121 ps_ignore_programs.append('cron') 122 ps_ignore_programs.append('CRON') 123 ps_ignore_programs.append('emacs') 124 ps_ignore_programs.append('floppybackup') 125 ps_ignore_programs.append('getty') 126 ps_ignore_programs.append('gzip') 127 ps_ignore_programs.append('identd') 128 ps_ignore_programs.append('ifconfig') # used by this script! 129 ps_ignore_programs.append('info') 130 ps_ignore_programs.append('less') 131 ps_ignore_programs.append('leafnode') # fetchnews uses PPP. 132 ps_ignore_programs.append('man') 133 ps_ignore_programs.append('most') 134 ps_ignore_programs.append('oleo') 135 ps_ignore_programs.append('pager') 136 ps_ignore_programs.append('poff') 137 ps_ignore_programs.append('portmap') 138 ps_ignore_programs.append('pppd') 139 ps_ignore_programs.append('pump') 140 ps_ignore_programs.append('python') 141 ps_ignore_programs.append('rjc_bak.sh') 142 ps_ignore_programs.append('run-parts') 143 ps_ignore_programs.append('sendmail') # Command not in ps_exp_abstract: 144 # ? PSC #:# /usr/sbin/sendmail -i -FCronDaemon -odi -oem root 145 146 ps_ignore_programs.append('lockvc') 147 ps_ignore_programs.append('sh') 148 ps_ignore_programs.append('sleep') 149 ps_ignore_programs.append('sshd') 150 ps_ignore_programs.append('ssh-agent') 151 ps_ignore_programs.append('tar') 152 ps_ignore_programs.append('top') 153 ps_ignore_programs.append('vi') 154 ps_ignore_programs.append('wwwoffled') 155 # 156 # Perhaps truncate '/usr/bin' and '/usr/sbin' too. 157 # 158 # -------------------------------------------------------------------- 159 ps_exp_abstract = [] 160 # 'PSC' is any combination of process state codes (``man ps''). 161 ps_exp_abstract.append('PID TTY STAT TIME COMMAND') 162 ps_exp_abstract.append('# ? PSC #:# init [#]') 163 ps_exp_abstract.append('# ? PSC #:# [kflushd]') 164 ps_exp_abstract.append('# ? PSC #:# [kpiod]') 165 ps_exp_abstract.append('# ? PSC #:# [kswapd]') 166 ps_exp_abstract.append('# ? PSC #:# /sbin/klogd') 167 ps_exp_abstract.append('# ? PSC #:# identd') 168 ps_exp_abstract.append('# ? PSC #:# [klogd]') 169 ps_exp_abstract.append('# ? PSC #:# [kswapd]') 170 ps_exp_abstract.append('# ? PSC #:# [kupdate]') 171 ps_exp_abstract.append('# ? PSC #:# [kupdate]') 172 ps_exp_abstract.append('# ? PSC #:# [portmap]') 173 ps_exp_abstract.append('# ? PSC #:# /sbin/syslogd') 174 ps_exp_abstract.append('# ? PSC #:# [syslogd]') 175 ps_exp_abstract.append('# ? PSC #:# /usr/sbin/cron') 176 ps_exp_abstract.append('# ? PSC #:# /usr/sbin/inetd') 177 ps_exp_abstract.append('# ? PSC #:# [atd]') 178 ps_exp_abstract.append('# ? PSC #:# /usr/sbin/atd') 179 ps_exp_abstract.append('# ? PSC #:# [cardmgr]') 180 ps_exp_abstract.append('# ? PSC #:# [gpm]') 181 ps_exp_abstract.append('# ? PSC #:# /usr/sbin/gpm -m /dev/psaux -t ps2 -Rms3') 182 ps_exp_abstract.append('# ? PSC #:# [inetd]') 183 ps_exp_abstract.append('# ? PSC #:# [ispell]') 184 ps_exp_abstract.append('# ? PSC #:# [junkbuster]') 185 ps_exp_abstract.append('# ? PSC #:# [lockd]') 186 ps_exp_abstract.append('# ? PSC #:# [lpd]') 187 ps_exp_abstract.append('# ? PSC #:# /usr/sbin/lpd') 188 ps_exp_abstract.append('# ? PSC #:# [rpc.statd]') 189 ps_exp_abstract.append('# ? PSC #:# [rpciod]') 190 ps_exp_abstract.append('# tty# PSC #:# -bash') 191 ps_exp_abstract.append('# tty# PSC #:# emacs') 192 ps_exp_abstract.append('# tty## SW #:# [lockvc]') 193 ps_exp_abstract.append('# tty# PSC #:# [bash]') 194 # missing: M-x shell [bash] on pts/ 195 ps_exp_abstract.append('# tty# PSC #:# [getty]') 196 ps_exp_abstract.append('# tty# PSC #:# ps awx') 197 ps_exp_abstract.append('# ? PSC #:# ps awx') 198 ps_exp_abstract.append('# ? PSC #:# /usr/bin/ispell -a -m -B') 199 ps_exp_abstract.append('# tty# PSC #:# sh /usr/bin/poff') 200 ps_exp_abstract.append('# ttyS# PSC #:# /usr/sbin/pppd call provider') 201 ps_exp_abstract.append('# ? PSC #:# /usr/sbin/wwwoffled -c /etc/wwwoffle/wwwoffle.conf') 202 # ------------------------------------------------------------------- 203 204 # Normalize expected list. 205 ps_exp_abstract = self.abstract(ps_exp_abstract) 206 207 # Get what's running 208 commands = os.popen(self.ps_syntax) 209 ps_actual = commands.readlines() 210 commands.close() 211 for command in ps_actual: 212 # 213 # Test expression against all commands. 214 if not self.re_P_T_S_T.match(command): 215 if not command == ' PID TTY STAT TIME COMMAND\n': 216 print self.re_P_T_S_T.pattern 217 raise 'Not matched-' + command + '-' 218 pass 219 pass 220 221 # Get abstract representations. 222 ps_actual = self.abstract(ps_actual) 223 224 # If a running command is not in the expected list, abort. 225 for command_abstract in ps_actual: 226 # 227 # Test expression using all command-abstracts. 228 if not self.re_P_T_S_T_abstract.match(command_abstract): 229 if not command_abstract == 'PID TTY STAT TIME COMMAND': 230 print self.re_P_T_S_T_abstract.pattern 231 raise 'Not matched', command_abstract 232 pass 233 234 if not command_abstract in ps_exp_abstract: 235 # Is it an 'ignore-program'? 236 237 # Where does program information start? 238 matchobj = self.re_P_T_S_T_abstract.match(command_abstract) 239 # Assign executable. 240 executable = command_abstract[matchobj.end(0):] 241 # Discard everything after program name. 242 executable_space = string.find(executable, ' ') 243 if executable_space > -1: 244 executable = executable[:executable_space] 245 pass 246 # Remove surrounding brackets, if any. 247 executable_open_bracket = string.find(executable, '[') 248 if executable_open_bracket > -1: 249 executable = executable[executable_open_bracket+1:] 250 pass 251 # 252 # When closing ']' not after executable: '[lynx <defunct>]' 253 executable_open_bracket = string.find(executable, ']') 254 if executable_open_bracket > -1: 255 executable = executable[:-1] 256 pass 257 # 258 # Remove path. 259 executable = string.split(executable, '/')[-1] 260 # 261 if not executable in ps_ignore_programs: 262 print ps_ignore_programs 263 print executable 264 raise 'Command not in ps_exp_abstract', \ command_abstract 266 267 pass 268 pass 269 270 # As long as ps_exp_abstract does not contain an 271 # entry that depends on PPP connection, it's okay to 272 # use 'poff' to end PPP. 273 # 274 kill_ppp = os.popen(self.real_poff_command) 275 kill_ppp.close() 276 pass 277 278 279 def __call__(self): 280 interface = 'ppp0' 281 if self.ppp(interface) == 0: 282 self.examine_processes() 283 pass 284 else: 285 print 'Interface not up: ' + interface 286 pass 287 pass 288 289 pass 290 # ....................................................... 291 main = my_program() 292 main() 293 294 ### 295 # 296 # Local variables: 297 # py-indent-offset: 4 298 # End: |