| 1 | #!/usr/bin/env python | 
|---|
| 2 |  | 
|---|
| 3 | """ Ajaxterm """ | 
|---|
| 4 |  | 
|---|
| 5 | import array,atexit,cgi,fcntl,glob,hashlib,mimetypes,optparse,os,pty,random,re,signal,select,sys,threading,time,termios,struct,pwd | 
|---|
| 6 |  | 
|---|
| 7 | class Terminal: | 
|---|
| 8 |         def __init__(self,width=80,height=24): | 
|---|
| 9 |                 self.width=width | 
|---|
| 10 |                 self.height=height | 
|---|
| 11 |                 self.init() | 
|---|
| 12 |                 self.reset() | 
|---|
| 13 |         def init(self): | 
|---|
| 14 |                 self.esc_seq={ | 
|---|
| 15 |                         "\x00": None, | 
|---|
| 16 |                         "\x05": self.esc_da, | 
|---|
| 17 |                         "\x07": None, | 
|---|
| 18 |                         "\x08": self.esc_0x08, | 
|---|
| 19 |                         "\x09": self.esc_0x09, | 
|---|
| 20 |                         "\x0a": self.esc_0x0a, | 
|---|
| 21 |                         "\x0b": self.esc_0x0a, | 
|---|
| 22 |                         "\x0c": self.esc_0x0a, | 
|---|
| 23 |                         "\x0d": self.esc_0x0d, | 
|---|
| 24 |                         "\x0e": None, | 
|---|
| 25 |                         "\x0f": None, | 
|---|
| 26 |                         "\x1b#8": None, | 
|---|
| 27 |                         "\x1b=": None, | 
|---|
| 28 |                         "\x1b>": None, | 
|---|
| 29 |                         "\x1b(0": None, | 
|---|
| 30 |                         "\x1b(A": None, | 
|---|
| 31 |                         "\x1b(B": None, | 
|---|
| 32 |                         "\x1b[c": self.esc_da, | 
|---|
| 33 |                         "\x1b[0c": self.esc_da, | 
|---|
| 34 |                         "\x1b]R": None, | 
|---|
| 35 |                         "\x1b7": self.esc_save, | 
|---|
| 36 |                         "\x1b8": self.esc_restore, | 
|---|
| 37 |                         "\x1bD": None, | 
|---|
| 38 |                         "\x1bE": None, | 
|---|
| 39 |                         "\x1bH": None, | 
|---|
| 40 |                         "\x1bM": self.esc_ri, | 
|---|
| 41 |                         "\x1bN": None, | 
|---|
| 42 |                         "\x1bO": None, | 
|---|
| 43 |                         "\x1bZ": self.esc_da, | 
|---|
| 44 |                         "\x1ba": None, | 
|---|
| 45 |                         "\x1bc": self.reset, | 
|---|
| 46 |                         "\x1bn": None, | 
|---|
| 47 |                         "\x1bo": None, | 
|---|
| 48 |                 } | 
|---|
| 49 |                 for k,v in self.esc_seq.items(): | 
|---|
| 50 |                         if v==None: | 
|---|
| 51 |                                 self.esc_seq[k]=self.esc_ignore | 
|---|
| 52 |                 # regex | 
|---|
| 53 |                 d={ | 
|---|
| 54 |                         r'\[\??([0-9;]*)([@ABCDEFGHJKLMPXacdefghlmnqrstu`])' : self.csi_dispatch, | 
|---|
| 55 |                         r'\]([^\x07]+)\x07' : self.esc_ignore, | 
|---|
| 56 |                 } | 
|---|
| 57 |                 self.esc_re=[] | 
|---|
| 58 |                 for k,v in d.items(): | 
|---|
| 59 |                         self.esc_re.append((re.compile('\x1b'+k),v)) | 
|---|
| 60 |                 # define csi sequences | 
|---|
| 61 |                 self.csi_seq={ | 
|---|
| 62 |                         '@': (self.csi_at,[1]), | 
|---|
| 63 |                         '`': (self.csi_G,[1]), | 
|---|
| 64 |                         'J': (self.csi_J,[0]), | 
|---|
| 65 |                         'K': (self.csi_K,[0]), | 
|---|
| 66 |                 } | 
|---|
| 67 |                 for i in [i[4] for i in dir(self) if i.startswith('csi_') and len(i)==5]: | 
|---|
| 68 |                         if not self.csi_seq.has_key(i): | 
|---|
| 69 |                                 self.csi_seq[i]=(getattr(self,'csi_'+i),[1]) | 
|---|
| 70 |                 # Init 0-256 to latin1 and html translation table | 
|---|
| 71 |                 self.trl1="" | 
|---|
| 72 |                 for i in range(256): | 
|---|
| 73 |                         if i<32: | 
|---|
| 74 |                                 self.trl1+=" " | 
|---|
| 75 |                         elif i<127 or i>160: | 
|---|
| 76 |                                 self.trl1+=chr(i) | 
|---|
| 77 |                         else: | 
|---|
| 78 |                                 self.trl1+="?" | 
|---|
| 79 |                 self.trhtml="" | 
|---|
| 80 |                 for i in range(256): | 
|---|
| 81 |                         if i==0x0a or (i>32 and i<127) or i>160: | 
|---|
| 82 |                                 self.trhtml+=chr(i) | 
|---|
| 83 |                         elif i<=32: | 
|---|
| 84 |                                 self.trhtml+="\xa0" | 
|---|
| 85 |                         else: | 
|---|
| 86 |                                 self.trhtml+="?" | 
|---|
| 87 |         def reset(self,s=""): | 
|---|
| 88 |                 self.scr=array.array('i',[0x000700]*(self.width*self.height)) | 
|---|
| 89 |                 self.st=0 | 
|---|
| 90 |                 self.sb=self.height-1 | 
|---|
| 91 |                 self.cx_bak=self.cx=0 | 
|---|
| 92 |                 self.cy_bak=self.cy=0 | 
|---|
| 93 |                 self.cl=0 | 
|---|
| 94 |                 self.sgr=0x000700 | 
|---|
| 95 |                 self.buf="" | 
|---|
| 96 |                 self.outbuf="" | 
|---|
| 97 |         def peek(self,y1,x1,y2,x2): | 
|---|
| 98 |                 return self.scr[self.width*y1+x1:self.width*y2+x2] | 
|---|
| 99 |         def poke(self,y,x,s): | 
|---|
| 100 |                 pos=self.width*y+x | 
|---|
| 101 |                 self.scr[pos:pos+len(s)]=s | 
|---|
| 102 |         def zero(self,y1,x1,y2,x2): | 
|---|
| 103 |                 w=self.width*(y2-y1)+x2-x1+1 | 
|---|
| 104 |                 z=array.array('i',[0x000700]*w) | 
|---|
| 105 |                 self.scr[self.width*y1+x1:self.width*y2+x2+1]=z | 
|---|
| 106 |         def scroll_up(self,y1,y2): | 
|---|
| 107 |                 self.poke(y1,0,self.peek(y1+1,0,y2,self.width)) | 
|---|
| 108 |                 self.zero(y2,0,y2,self.width-1) | 
|---|
| 109 |         def scroll_down(self,y1,y2): | 
|---|
| 110 |                 self.poke(y1+1,0,self.peek(y1,0,y2-1,self.width)) | 
|---|
| 111 |                 self.zero(y1,0,y1,self.width-1) | 
|---|
| 112 |         def scroll_right(self,y,x): | 
|---|
| 113 |                 self.poke(y,x+1,self.peek(y,x,y,self.width)) | 
|---|
| 114 |                 self.zero(y,x,y,x) | 
|---|
| 115 |         def cursor_down(self): | 
|---|
| 116 |                 if self.cy>=self.st and self.cy<=self.sb: | 
|---|
| 117 |                         self.cl=0 | 
|---|
| 118 |                         q,r=divmod(self.cy+1,self.sb+1) | 
|---|
| 119 |                         if q: | 
|---|
| 120 |                                 self.scroll_up(self.st,self.sb) | 
|---|
| 121 |                                 self.cy=self.sb | 
|---|
| 122 |                         else: | 
|---|
| 123 |                                 self.cy=r | 
|---|
| 124 |         def cursor_right(self): | 
|---|
| 125 |                 q,r=divmod(self.cx+1,self.width) | 
|---|
| 126 |                 if q: | 
|---|
| 127 |                         self.cl=1 | 
|---|
| 128 |                 else: | 
|---|
| 129 |                         self.cx=r | 
|---|
| 130 |         def echo(self,c): | 
|---|
| 131 |                 if self.cl: | 
|---|
| 132 |                         self.cursor_down() | 
|---|
| 133 |                         self.cx=0 | 
|---|
| 134 |                 self.scr[(self.cy*self.width)+self.cx]=self.sgr|ord(c) | 
|---|
| 135 |                 self.cursor_right() | 
|---|
| 136 |         def esc_0x08(self,s): | 
|---|
| 137 |                 self.cx=max(0,self.cx-1) | 
|---|
| 138 |         def esc_0x09(self,s): | 
|---|
| 139 |                 x=self.cx+8 | 
|---|
| 140 |                 q,r=divmod(x,8) | 
|---|
| 141 |                 self.cx=(q*8)%self.width | 
|---|
| 142 |         def esc_0x0a(self,s): | 
|---|
| 143 |                 self.cursor_down() | 
|---|
| 144 |         def esc_0x0d(self,s): | 
|---|
| 145 |                 self.cl=0 | 
|---|
| 146 |                 self.cx=0 | 
|---|
| 147 |         def esc_save(self,s): | 
|---|
| 148 |                 self.cx_bak=self.cx | 
|---|
| 149 |                 self.cy_bak=self.cy | 
|---|
| 150 |         def esc_restore(self,s): | 
|---|
| 151 |                 self.cx=self.cx_bak | 
|---|
| 152 |                 self.cy=self.cy_bak | 
|---|
| 153 |                 self.cl=0 | 
|---|
| 154 |         def esc_da(self,s): | 
|---|
| 155 |                 self.outbuf="\x1b[?6c" | 
|---|
| 156 |         def esc_ri(self,s): | 
|---|
| 157 |                 self.cy=max(self.st,self.cy-1) | 
|---|
| 158 |                 if self.cy==self.st: | 
|---|
| 159 |                         self.scroll_down(self.st,self.sb) | 
|---|
| 160 |         def esc_ignore(self,*s): | 
|---|
| 161 |                 pass | 
|---|
| 162 | #               print "term:ignore: %s"%repr(s) | 
|---|
| 163 |         def csi_dispatch(self,seq,mo): | 
|---|
| 164 |         # CSI sequences | 
|---|
| 165 |                 s=mo.group(1) | 
|---|
| 166 |                 c=mo.group(2) | 
|---|
| 167 |                 f=self.csi_seq.get(c,None) | 
|---|
| 168 |                 if f: | 
|---|
| 169 |                         try: | 
|---|
| 170 |                                 l=[min(int(i),1024) for i in s.split(';') if len(i)<4] | 
|---|
| 171 |                         except ValueError: | 
|---|
| 172 |                                 l=[] | 
|---|
| 173 |                         if len(l)==0: | 
|---|
| 174 |                                 l=f[1] | 
|---|
| 175 |                         f[0](l) | 
|---|
| 176 | #               else: | 
|---|
| 177 | #                       print 'csi ignore',c,l | 
|---|
| 178 |         def csi_at(self,l): | 
|---|
| 179 |                 for i in range(l[0]): | 
|---|
| 180 |                         self.scroll_right(self.cy,self.cx) | 
|---|
| 181 |         def csi_A(self,l): | 
|---|
| 182 |                 self.cy=max(self.st,self.cy-l[0]) | 
|---|
| 183 |         def csi_B(self,l): | 
|---|
| 184 |                 self.cy=min(self.sb,self.cy+l[0]) | 
|---|
| 185 |         def csi_C(self,l): | 
|---|
| 186 |                 self.cx=min(self.width-1,self.cx+l[0]) | 
|---|
| 187 |                 self.cl=0 | 
|---|
| 188 |         def csi_D(self,l): | 
|---|
| 189 |                 self.cx=max(0,self.cx-l[0]) | 
|---|
| 190 |                 self.cl=0 | 
|---|
| 191 |         def csi_E(self,l): | 
|---|
| 192 |                 self.csi_B(l) | 
|---|
| 193 |                 self.cx=0 | 
|---|
| 194 |                 self.cl=0 | 
|---|
| 195 |         def csi_F(self,l): | 
|---|
| 196 |                 self.csi_A(l) | 
|---|
| 197 |                 self.cx=0 | 
|---|
| 198 |                 self.cl=0 | 
|---|
| 199 |         def csi_G(self,l): | 
|---|
| 200 |                 self.cx=min(self.width,l[0])-1 | 
|---|
| 201 |         def csi_H(self,l): | 
|---|
| 202 |                 if len(l)<2: l=[1,1] | 
|---|
| 203 |                 self.cx=min(self.width,l[1])-1 | 
|---|
| 204 |                 self.cy=min(self.height,l[0])-1 | 
|---|
| 205 |                 self.cl=0 | 
|---|
| 206 |         def csi_J(self,l): | 
|---|
| 207 |                 if l[0]==0: | 
|---|
| 208 |                         self.zero(self.cy,self.cx,self.height-1,self.width-1) | 
|---|
| 209 |                 elif l[0]==1: | 
|---|
| 210 |                         self.zero(0,0,self.cy,self.cx) | 
|---|
| 211 |                 elif l[0]==2: | 
|---|
| 212 |                         self.zero(0,0,self.height-1,self.width-1) | 
|---|
| 213 |         def csi_K(self,l): | 
|---|
| 214 |                 if l[0]==0: | 
|---|
| 215 |                         self.zero(self.cy,self.cx,self.cy,self.width-1) | 
|---|
| 216 |                 elif l[0]==1: | 
|---|
| 217 |                         self.zero(self.cy,0,self.cy,self.cx) | 
|---|
| 218 |                 elif l[0]==2: | 
|---|
| 219 |                         self.zero(self.cy,0,self.cy,self.width-1) | 
|---|
| 220 |         def csi_L(self,l): | 
|---|
| 221 |                 for i in range(l[0]): | 
|---|
| 222 |                         if self.cy<self.sb: | 
|---|
| 223 |                                 self.scroll_down(self.cy,self.sb) | 
|---|
| 224 |         def csi_M(self,l): | 
|---|
| 225 |                 if self.cy>=self.st and self.cy<=self.sb: | 
|---|
| 226 |                         for i in range(l[0]): | 
|---|
| 227 |                                 self.scroll_up(self.cy,self.sb) | 
|---|
| 228 |         def csi_P(self,l): | 
|---|
| 229 |                 w,cx,cy=self.width,self.cx,self.cy | 
|---|
| 230 |                 end=self.peek(cy,cx,cy,w) | 
|---|
| 231 |                 self.csi_K([0]) | 
|---|
| 232 |                 self.poke(cy,cx,end[l[0]:]) | 
|---|
| 233 |         def csi_X(self,l): | 
|---|
| 234 |                 self.zero(self.cy,self.cx,self.cy,self.cx+l[0]) | 
|---|
| 235 |         def csi_a(self,l): | 
|---|
| 236 |                 self.csi_C(l) | 
|---|
| 237 |         def csi_c(self,l): | 
|---|
| 238 |                 #'\x1b[?0c' 0-8 cursor size | 
|---|
| 239 |                 pass | 
|---|
| 240 |         def csi_d(self,l): | 
|---|
| 241 |                 self.cy=min(self.height,l[0])-1 | 
|---|
| 242 |         def csi_e(self,l): | 
|---|
| 243 |                 self.csi_B(l) | 
|---|
| 244 |         def csi_f(self,l): | 
|---|
| 245 |                 self.csi_H(l) | 
|---|
| 246 |         def csi_h(self,l): | 
|---|
| 247 |                 if l[0]==4: | 
|---|
| 248 |                         pass | 
|---|
| 249 | #                       print "insert on" | 
|---|
| 250 |         def csi_l(self,l): | 
|---|
| 251 |                 if l[0]==4: | 
|---|
| 252 |                         pass | 
|---|
| 253 | #                       print "insert off" | 
|---|
| 254 |         def csi_m(self,l): | 
|---|
| 255 |                 for i in l: | 
|---|
| 256 |                         if i==0 or i==39 or i==49 or i==27: | 
|---|
| 257 |                                 self.sgr=0x000700 | 
|---|
| 258 |                         elif i==1: | 
|---|
| 259 |                                 self.sgr=(self.sgr|0x000800) | 
|---|
| 260 |                         elif i==7: | 
|---|
| 261 |                                 self.sgr=0x070000 | 
|---|
| 262 |                         elif i>=30 and i<=37: | 
|---|
| 263 |                                 c=i-30 | 
|---|
| 264 |                                 self.sgr=(self.sgr&0xff08ff)|(c<<8) | 
|---|
| 265 |                         elif i>=40 and i<=47: | 
|---|
| 266 |                                 c=i-40 | 
|---|
| 267 |                                 self.sgr=(self.sgr&0x00ffff)|(c<<16) | 
|---|
| 268 | #                       else: | 
|---|
| 269 | #                               print "CSI sgr ignore",l,i | 
|---|
| 270 | #               print 'sgr: %r %x'%(l,self.sgr) | 
|---|
| 271 |         def csi_r(self,l): | 
|---|
| 272 |                 if len(l)<2: l=[0,self.height] | 
|---|
| 273 |                 self.st=min(self.height-1,l[0]-1) | 
|---|
| 274 |                 self.sb=min(self.height-1,l[1]-1) | 
|---|
| 275 |                 self.sb=max(self.st,self.sb) | 
|---|
| 276 |         def csi_s(self,l): | 
|---|
| 277 |                 self.esc_save(0) | 
|---|
| 278 |         def csi_u(self,l): | 
|---|
| 279 |                 self.esc_restore(0) | 
|---|
| 280 |         def escape(self): | 
|---|
| 281 |                 e=self.buf | 
|---|
| 282 |                 if len(e)>32: | 
|---|
| 283 | #                       print "error %r"%e | 
|---|
| 284 |                         self.buf="" | 
|---|
| 285 |                 elif e in self.esc_seq: | 
|---|
| 286 |                         self.esc_seq[e](e) | 
|---|
| 287 |                         self.buf="" | 
|---|
| 288 |                 else: | 
|---|
| 289 |                         for r,f in self.esc_re: | 
|---|
| 290 |                                 mo=r.match(e) | 
|---|
| 291 |                                 if mo: | 
|---|
| 292 |                                         f(e,mo) | 
|---|
| 293 |                                         self.buf="" | 
|---|
| 294 |                                         break | 
|---|
| 295 | #               if self.buf=='': print "ESC %r\n"%e | 
|---|
| 296 |         def write(self,s): | 
|---|
| 297 |                 for i in s: | 
|---|
| 298 |                         if len(self.buf) or (i in self.esc_seq): | 
|---|
| 299 |                                 self.buf+=i | 
|---|
| 300 |                                 self.escape() | 
|---|
| 301 |                         elif i == '\x1b': | 
|---|
| 302 |                                 self.buf+=i | 
|---|
| 303 |                         else: | 
|---|
| 304 |                                 self.echo(i) | 
|---|
| 305 |         def read(self): | 
|---|
| 306 |                 b=self.outbuf | 
|---|
| 307 |                 self.outbuf="" | 
|---|
| 308 |                 return b | 
|---|
| 309 |         def dump(self): | 
|---|
| 310 |                 r='' | 
|---|
| 311 |                 for i in self.scr: | 
|---|
| 312 |                         r+=chr(i&255) | 
|---|
| 313 |                 return r | 
|---|
| 314 |         def dumplatin1(self): | 
|---|
| 315 |                 return self.dump().translate(self.trl1) | 
|---|
| 316 |         def dumphtml(self,color=1,last_hash=None): | 
|---|
| 317 |                 h=self.height | 
|---|
| 318 |                 w=self.width | 
|---|
| 319 |                 r="" | 
|---|
| 320 |                 span="" | 
|---|
| 321 |                 span_bg,span_fg=-1,-1 | 
|---|
| 322 |                 for i in range(h*w): | 
|---|
| 323 |                         q,c=divmod(self.scr[i],256) | 
|---|
| 324 |                         if color: | 
|---|
| 325 |                                 bg,fg=divmod(q,256) | 
|---|
| 326 |                         else: | 
|---|
| 327 |                                 bg,fg=0,7 | 
|---|
| 328 |                         if i==self.cy*w+self.cx: | 
|---|
| 329 |                                 bg,fg=1,7 | 
|---|
| 330 |                         if (bg!=span_bg or fg!=span_fg or i==h*w-1): | 
|---|
| 331 |                                 if len(span): | 
|---|
| 332 |                                         r+='<span class="f%d b%d">%s</span>'%(span_fg,span_bg,cgi.escape(span.translate(self.trhtml))) | 
|---|
| 333 |                                 span="" | 
|---|
| 334 |                                 span_bg,span_fg=bg,fg | 
|---|
| 335 |                         span+=chr(c) | 
|---|
| 336 |                         if i%w==w-1: | 
|---|
| 337 |                                 span+='\n' | 
|---|
| 338 |                 hash = hashlib.md5(r).hexdigest() | 
|---|
| 339 |                 r='<?xml version="1.0" encoding="ISO-8859-1"?><pre class="term" id="%s">%s</pre>'% (hash,r) | 
|---|
| 340 |                 if last_hash == hash: | 
|---|
| 341 |                         return '<?xml version="1.0"?><idem></idem>' | 
|---|
| 342 |                 else: | 
|---|
| 343 |                         return r | 
|---|
| 344 |         def __repr__(self): | 
|---|
| 345 |                 d=self.dumplatin1() | 
|---|
| 346 |                 r="" | 
|---|
| 347 |                 for i in range(self.height): | 
|---|
| 348 |                         r+="|%s|\n"%d[self.width*i:self.width*(i+1)] | 
|---|
| 349 |                 return r | 
|---|
| 350 |  | 
|---|
| 351 | class SynchronizedMethod: | 
|---|
| 352 |         def __init__(self,lock,orig): | 
|---|
| 353 |                 self.lock=lock | 
|---|
| 354 |                 self.orig=orig | 
|---|
| 355 |         def __call__(self,*l): | 
|---|
| 356 |                 self.lock.acquire() | 
|---|
| 357 |                 r=self.orig(*l) | 
|---|
| 358 |                 self.lock.release() | 
|---|
| 359 |                 return r | 
|---|
| 360 |  | 
|---|
| 361 | class Multiplex: | 
|---|
| 362 |         def __init__(self): | 
|---|
| 363 |                 self.proc={} | 
|---|
| 364 |                 self.lock=threading.RLock() | 
|---|
| 365 |                 self.thread=threading.Thread(target=self.loop) | 
|---|
| 366 |                 self.thread.daemon=True | 
|---|
| 367 |                 self.alive=1 | 
|---|
| 368 |                 atexit.register(self.die) | 
|---|
| 369 |                 # synchronize methods | 
|---|
| 370 |                 for name in ['create','fds','proc_read','proc_write','dump','die','run']: | 
|---|
| 371 |                         orig=getattr(self,name) | 
|---|
| 372 |                         setattr(self,name,SynchronizedMethod(self.lock,orig)) | 
|---|
| 373 |                 self.thread.start() | 
|---|
| 374 |         def create(self,cmd,w=80,h=25): | 
|---|
| 375 |                 pid,fd=pty.fork() | 
|---|
| 376 |                 if pid==0: | 
|---|
| 377 |                         try: | 
|---|
| 378 |                                 fdl=[int(i) for i in os.listdir('/proc/self/fd')] | 
|---|
| 379 |                         except OSError: | 
|---|
| 380 |                                 fdl=range(256) | 
|---|
| 381 |                         for i in [i for i in fdl if i>2]: | 
|---|
| 382 |                                 try: | 
|---|
| 383 |                                         os.close(i) | 
|---|
| 384 |                                 except OSError: | 
|---|
| 385 |                                         pass | 
|---|
| 386 |                         env={} | 
|---|
| 387 |                         env["COLUMNS"]=str(w) | 
|---|
| 388 |                         env["LINES"]=str(h) | 
|---|
| 389 |                         env["TERM"]="linux" | 
|---|
| 390 |                         env["PATH"]=os.environ['PATH'] | 
|---|
| 391 |                         os.execvpe(cmd[0],cmd,env) | 
|---|
| 392 |                 else: | 
|---|
| 393 |                         fcntl.fcntl(fd, fcntl.F_SETFL, os.O_NONBLOCK) | 
|---|
| 394 |                         # python bug http://python.org/sf/1112949 on amd64 | 
|---|
| 395 |                         fcntl.ioctl(fd, struct.unpack('i',struct.pack('I',termios.TIOCSWINSZ))[0], struct.pack("HHHH",h,w,0,0)) | 
|---|
| 396 |                         self.proc[fd]={'pid':pid,'term':Terminal(w,h),'buf':'','time':time.time()} | 
|---|
| 397 |                         return fd | 
|---|
| 398 |         def die(self): | 
|---|
| 399 |                 self.alive=0 | 
|---|
| 400 |         def run(self): | 
|---|
| 401 |                 return self.alive | 
|---|
| 402 |         def fds(self): | 
|---|
| 403 |                 return self.proc.keys() | 
|---|
| 404 |         def proc_kill(self,fd): | 
|---|
| 405 |                 if fd in self.proc: | 
|---|
| 406 |                         self.proc[fd]['time']=0 | 
|---|
| 407 |                 t=time.time() | 
|---|
| 408 |                 for i in self.proc.keys(): | 
|---|
| 409 |                         t0=self.proc[i]['time'] | 
|---|
| 410 |                         if (t-t0)>120: | 
|---|
| 411 |                                 try: | 
|---|
| 412 |                                         os.close(i) | 
|---|
| 413 |                                         os.kill(self.proc[i]['pid'],signal.SIGTERM) | 
|---|
| 414 |                                 except (IOError,OSError): | 
|---|
| 415 |                                         pass | 
|---|
| 416 |                                 del self.proc[i] | 
|---|
| 417 |         def proc_read(self,fd): | 
|---|
| 418 |                 try: | 
|---|
| 419 |                         t=self.proc[fd]['term'] | 
|---|
| 420 |                         t.write(os.read(fd,65536)) | 
|---|
| 421 |                         reply=t.read() | 
|---|
| 422 |                         if reply: | 
|---|
| 423 |                                 os.write(fd,reply) | 
|---|
| 424 |                         self.proc[fd]['time']=time.time() | 
|---|
| 425 |                 except (KeyError,IOError,OSError): | 
|---|
| 426 |                         self.proc_kill(fd) | 
|---|
| 427 |         def proc_write(self,fd,s): | 
|---|
| 428 |                 try: | 
|---|
| 429 |                         os.write(fd,s) | 
|---|
| 430 |                 except (IOError,OSError): | 
|---|
| 431 |                         self.proc_kill(fd) | 
|---|
| 432 |         def dump(self,fd,color=1,last_hash=None): | 
|---|
| 433 |                 try: | 
|---|
| 434 |                         return self.proc[fd]['term'].dumphtml(color, last_hash) | 
|---|
| 435 |                 except KeyError: | 
|---|
| 436 |                         return False | 
|---|
| 437 |         def loop(self): | 
|---|
| 438 |                 while self.run(): | 
|---|
| 439 |                         fds=self.fds() | 
|---|
| 440 |                         i,o,e=select.select(fds, [], [], 1.0) | 
|---|
| 441 |                         for fd in i: | 
|---|
| 442 |                                 self.proc_read(fd) | 
|---|
| 443 |                         if len(i): | 
|---|
| 444 |                                 time.sleep(0.002) | 
|---|
| 445 |                 for i in self.proc.keys(): | 
|---|
| 446 |                         try: | 
|---|
| 447 |                                 os.close(i) | 
|---|
| 448 |                                 os.kill(self.proc[i]['pid'],signal.SIGTERM) | 
|---|
| 449 |                         except (IOError,OSError): | 
|---|
| 450 |                                 pass | 
|---|