mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			164 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			164 lines
		
	
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
| import os
 | |
| import sys
 | |
| import string
 | |
| from Tkinter import *
 | |
| from ScrolledText import ScrolledText
 | |
| from Dialog import Dialog
 | |
| import signal
 | |
| 
 | |
| TK_READABLE  = 1
 | |
| TK_WRITABLE  = 2
 | |
| TK_EXCEPTION = 4
 | |
| 
 | |
| BUFSIZE = 512
 | |
| 
 | |
| class ShellWindow(ScrolledText):
 | |
| 
 | |
| 	def __init__(self, master = None, cnf = {}):
 | |
| 		try:
 | |
| 			shell = cnf['shell']
 | |
| 			del cnf['shell']
 | |
| 		except KeyError:
 | |
| 			try:
 | |
| 				shell = os.environ['SHELL']
 | |
| 			except KeyError:
 | |
| 				shell = '/bin/sh'
 | |
| 			shell = shell + ' -i'
 | |
| 		args = string.split(shell)
 | |
| 		shell = args[0]
 | |
| 
 | |
| 		ScrolledText.__init__(self, master, cnf)
 | |
| 		self.pos = '1.0'
 | |
| 		self.bind('<Return>', self.inputhandler)
 | |
| 		self.bind('<Control-c>', self.sigint)
 | |
| 		self.bind('<Control-t>', self.sigterm)
 | |
| 		self.bind('<Control-k>', self.sigkill)
 | |
| 		self.bind('<Control-d>', self.sendeof)
 | |
| 
 | |
| 		self.pid, self.fromchild, self.tochild = spawn(shell, args)
 | |
| 		self.tk.createfilehandler(self.fromchild, TK_READABLE,
 | |
| 					  self.outputhandler)
 | |
| 
 | |
| 	def outputhandler(self, file, mask):
 | |
| 		data = os.read(file, BUFSIZE)
 | |
| 		if not data:
 | |
| 			self.tk.deletefilehandler(file)
 | |
| 			pid, sts = os.waitpid(self.pid, 0)
 | |
| 			print 'pid', pid, 'status', sts
 | |
| 			self.pid = None
 | |
| 			detail = sts>>8
 | |
| 			cause = sts & 0xff
 | |
| 			if cause == 0:
 | |
| 				msg = "exit status %d" % detail
 | |
| 			else:
 | |
| 				msg = "killed by signal %d" % (cause & 0x7f)
 | |
| 				if cause & 0x80:
 | |
| 					msg = msg + " -- core dumped"
 | |
| 			Dialog(self.master, {
 | |
| 				'text': msg,
 | |
| 				'title': "Exit status",
 | |
| 				'bitmap': 'warning',
 | |
| 				'default': 0,
 | |
| 				'strings': ('OK',),
 | |
| 			})
 | |
| 			return
 | |
| 		self.insert('end', data)
 | |
| 		self.pos = self.index('end')
 | |
| 		self.yview_pickplace('end')
 | |
| 
 | |
| 	def inputhandler(self, *args):
 | |
| 		if not self.pid:
 | |
| 			Dialog(self.master, {
 | |
| 				'text': "No active process",
 | |
| 				'title': "No process",
 | |
| 				'bitmap': 'error',
 | |
| 				'default': 0,
 | |
| 				'strings': ('OK',),
 | |
| 			})
 | |
| 			return
 | |
| 		self.insert('end', '\n')
 | |
| 		line = self.get(self.pos, 'end')
 | |
| 		self.pos = self.index('end')
 | |
| 		os.write(self.tochild, line)
 | |
| 
 | |
| 	def sendeof(self, *args):
 | |
| 		if not self.pid:
 | |
| 			Dialog(self.master, {
 | |
| 				'text': "No active process",
 | |
| 				'title': "No process",
 | |
| 				'bitmap': 'error',
 | |
| 				'default': 0,
 | |
| 				'strings': ('OK',),
 | |
| 			})
 | |
| 			return
 | |
| 		os.close(self.tochild)
 | |
| 
 | |
| 	def sendsig(self, sig):
 | |
| 		if not self.pid:
 | |
| 			Dialog(self.master, {
 | |
| 				'text': "No active process",
 | |
| 				'title': "No process",
 | |
| 				'bitmap': 'error',
 | |
| 				'default': 0,
 | |
| 				'strings': ('OK',),
 | |
| 			})
 | |
| 			return
 | |
| 		os.kill(self.pid, sig)
 | |
| 
 | |
| 	def sigint(self, *args):
 | |
| 		self.sendsig(signal.SIGINT)
 | |
| 
 | |
| 	def sigquit(self, *args):
 | |
| 		self.sendsig(signal.SIGQUIT)
 | |
| 
 | |
| 	def sigterm(self, *args):
 | |
| 		self.sendsig(signal.SIGTERM)
 | |
| 
 | |
| 	def sigkill(self, *args):
 | |
| 		self.sendsig(signal.SIGKILL)
 | |
| 
 | |
| MAXFD = 100	# Max number of file descriptors (os.getdtablesize()???)
 | |
| 
 | |
| def spawn(prog, args):
 | |
| 	p2cread, p2cwrite = os.pipe()
 | |
| 	c2pread, c2pwrite = os.pipe()
 | |
| 	pid = os.fork()
 | |
| 	if pid == 0:
 | |
| 		# Child
 | |
| 		os.close(0)
 | |
| 		os.close(1)
 | |
| 		os.close(2)
 | |
| 		if os.dup(p2cread) <> 0:
 | |
| 			sys.stderr.write('popen2: bad read dup\n')
 | |
| 		if os.dup(c2pwrite) <> 1:
 | |
| 			sys.stderr.write('popen2: bad write dup\n')
 | |
| 		if os.dup(c2pwrite) <> 2:
 | |
| 			sys.stderr.write('popen2: bad write dup\n')
 | |
| 		for i in range(3, MAXFD):
 | |
| 			try:
 | |
| 				os.close(i)
 | |
| 			except:
 | |
| 				pass
 | |
| 		try:
 | |
| 			os.execvp(prog, args)
 | |
| 		finally:
 | |
| 			print 'execvp failed'
 | |
| 			os._exit(1)
 | |
| 	os.close(p2cread)
 | |
| 	os.close(c2pwrite)
 | |
| 	return pid, c2pread, p2cwrite
 | |
| 
 | |
| def test():
 | |
| 	shell = string.join(sys.argv[1:])
 | |
| 	cnf = {}
 | |
| 	if shell:
 | |
| 		cnf['shell'] = shell
 | |
| 	root = Tk()
 | |
| 	root.minsize(1, 1)
 | |
| 	w = ShellWindow(root, cnf)
 | |
| 	w.pack({'expand': 1, 'fill': 'both'})
 | |
| 	w.focus_set()
 | |
| 	w.tk.mainloop()
 | |
| 
 | |
| if __name__ == '__main__':
 | |
| 	test()
 | 
