forked from anujpathania/HotSniper
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtimeout.py
executable file
·52 lines (44 loc) · 1.68 KB
/
timeout.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import datetime, subprocess, fcntl, time, os, sys, signal
# exception class
class Timeout(Exception): pass
def command(command, timeout, pollinterval = .1, return_stderr = False):
"""call shell-command and either return its output or kill it
if it doesn't normally exit within timeout seconds and return None"""
start = datetime.datetime.now()
process = subprocess.Popen([ 'bash', '-c', command ], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
outtxt = ''; errtxt = ''
outfd = process.stdout.fileno(); fcntl.fcntl(outfd, fcntl.F_SETFL, os.O_NONBLOCK)
errfd = process.stderr.fileno(); fcntl.fcntl(errfd, fcntl.F_SETFL, os.O_NONBLOCK)
while process.poll() is None:
time.sleep(pollinterval)
now = datetime.datetime.now()
if (now - start).seconds > timeout:
try:
os.kill(process.pid, signal.SIGKILL)
os.waitpid(process.pid, os.WNOHANG)
except OSError, e:
pass # ignore [Errno 3] No such process: process may have exited between process.poll() and here
raise Timeout
try: outtxt += os.read(outfd, 4096)
except OSError: pass # ignore EAGAIN (means 'no new data available now' on non-blocking fd)
try: errtxt += os.read(errfd, 4096)
except OSError: pass
while True:
try:
more = os.read(outfd, 4096)
except OSError:
break
if not more: break
outtxt += more
while True:
try:
more = os.read(errfd, 4096)
except OSError:
break
if not more: break
errtxt += more
if return_stderr:
return outtxt, errtxt
else:
if errtxt: sys.stderr.write(errtxt)
return outtxt