Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
derv82
GitHub Repository: derv82/wifite2
Path: blob/master/wifite/util/process.py
412 views
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
import time
5
import signal
6
import os
7
8
from subprocess import Popen, PIPE
9
10
from ..util.color import Color
11
from ..config import Configuration
12
13
14
class Process(object):
15
''' Represents a running/ran process '''
16
17
@staticmethod
18
def devnull():
19
''' Helper method for opening devnull '''
20
return open('/dev/null', 'w')
21
22
@staticmethod
23
def call(command, cwd=None, shell=False):
24
'''
25
Calls a command (either string or list of args).
26
Returns tuple:
27
(stdout, stderr)
28
'''
29
if type(command) is not str or ' ' in command or shell:
30
shell = True
31
if Configuration.verbose > 1:
32
Color.pe('\n {C}[?] {W} Executing (Shell): {B}%s{W}' % command)
33
else:
34
shell = False
35
if Configuration.verbose > 1:
36
Color.pe('\n {C}[?]{W} Executing: {B}%s{W}' % command)
37
38
pid = Popen(command, cwd=cwd, stdout=PIPE, stderr=PIPE, shell=shell)
39
pid.wait()
40
(stdout, stderr) = pid.communicate()
41
42
# Python 3 compatibility
43
if type(stdout) is bytes: stdout = stdout.decode('utf-8')
44
if type(stderr) is bytes: stderr = stderr.decode('utf-8')
45
46
47
if Configuration.verbose > 1 and stdout is not None and stdout.strip() != '':
48
Color.pe('{P} [stdout] %s{W}' % '\n [stdout] '.join(stdout.strip().split('\n')))
49
if Configuration.verbose > 1 and stderr is not None and stderr.strip() != '':
50
Color.pe('{P} [stderr] %s{W}' % '\n [stderr] '.join(stderr.strip().split('\n')))
51
52
return (stdout, stderr)
53
54
@staticmethod
55
def exists(program):
56
''' Checks if program is installed on this system '''
57
p = Process(['which', program])
58
stdout = p.stdout().strip()
59
stderr = p.stderr().strip()
60
61
if stdout == '' and stderr == '':
62
return False
63
64
return True
65
66
def __init__(self, command, devnull=False, stdout=PIPE, stderr=PIPE, cwd=None, bufsize=0, stdin=PIPE):
67
''' Starts executing command '''
68
69
if type(command) is str:
70
# Commands have to be a list
71
command = command.split(' ')
72
73
self.command = command
74
75
if Configuration.verbose > 1:
76
Color.pe('\n {C}[?] {W} Executing: {B}%s{W}' % ' '.join(command))
77
78
self.out = None
79
self.err = None
80
if devnull:
81
sout = Process.devnull()
82
serr = Process.devnull()
83
else:
84
sout = stdout
85
serr = stderr
86
87
self.start_time = time.time()
88
89
self.pid = Popen(command, stdout=sout, stderr=serr, stdin=stdin, cwd=cwd, bufsize=bufsize)
90
91
def __del__(self):
92
'''
93
Ran when object is GC'd.
94
If process is still running at this point, it should die.
95
'''
96
try:
97
if self.pid and self.pid.poll() is None:
98
self.interrupt()
99
except AttributeError:
100
pass
101
102
def stdout(self):
103
''' Waits for process to finish, returns stdout output '''
104
self.get_output()
105
if Configuration.verbose > 1 and self.out is not None and self.out.strip() != '':
106
Color.pe('{P} [stdout] %s{W}' % '\n [stdout] '.join(self.out.strip().split('\n')))
107
return self.out
108
109
def stderr(self):
110
''' Waits for process to finish, returns stderr output '''
111
self.get_output()
112
if Configuration.verbose > 1 and self.err is not None and self.err.strip() != '':
113
Color.pe('{P} [stderr] %s{W}' % '\n [stderr] '.join(self.err.strip().split('\n')))
114
return self.err
115
116
def stdoutln(self):
117
return self.pid.stdout.readline()
118
119
def stderrln(self):
120
return self.pid.stderr.readline()
121
122
def stdin(self, text):
123
if self.pid.stdin:
124
self.pid.stdin.write(text.encode('utf-8'))
125
self.pid.stdin.flush()
126
127
def get_output(self):
128
''' Waits for process to finish, sets stdout & stderr '''
129
if self.pid.poll() is None:
130
self.pid.wait()
131
if self.out is None:
132
(self.out, self.err) = self.pid.communicate()
133
134
if type(self.out) is bytes:
135
self.out = self.out.decode('utf-8')
136
137
if type(self.err) is bytes:
138
self.err = self.err.decode('utf-8')
139
140
return (self.out, self.err)
141
142
def poll(self):
143
''' Returns exit code if process is dead, otherwise 'None' '''
144
return self.pid.poll()
145
146
def wait(self):
147
self.pid.wait()
148
149
def running_time(self):
150
''' Returns number of seconds since process was started '''
151
return int(time.time() - self.start_time)
152
153
def interrupt(self, wait_time=2.0):
154
'''
155
Send interrupt to current process.
156
If process fails to exit within `wait_time` seconds, terminates it.
157
'''
158
try:
159
pid = self.pid.pid
160
cmd = self.command
161
if type(cmd) is list:
162
cmd = ' '.join(cmd)
163
164
if Configuration.verbose > 1:
165
Color.pe('\n {C}[?] {W} sending interrupt to PID %d (%s)' % (pid, cmd))
166
167
os.kill(pid, signal.SIGINT)
168
169
start_time = time.time() # Time since Interrupt was sent
170
while self.pid.poll() is None:
171
# Process is still running
172
time.sleep(0.1)
173
if time.time() - start_time > wait_time:
174
# We waited too long for process to die, terminate it.
175
if Configuration.verbose > 1:
176
Color.pe('\n {C}[?] {W} Waited > %0.2f seconds for process to die, killing it' % wait_time)
177
os.kill(pid, signal.SIGTERM)
178
self.pid.terminate()
179
break
180
181
except OSError as e:
182
if 'No such process' in e.__str__():
183
return
184
raise e # process cannot be killed
185
186
187
if __name__ == '__main__':
188
Configuration.initialize(False)
189
p = Process('ls')
190
print(p.stdout())
191
print(p.stderr())
192
p.interrupt()
193
194
# Calling as list of arguments
195
(out, err) = Process.call(['ls', '-lah'])
196
print(out)
197
print(err)
198
199
print('\n---------------------\n')
200
201
# Calling as string
202
(out, err) = Process.call('ls -l | head -2')
203
print(out)
204
print(err)
205
206
print('"reaver" exists: %s' % Process.exists('reaver'))
207
208
# Test on never-ending process
209
p = Process('yes')
210
print('Running yes...')
211
time.sleep(1)
212
print('yes should stop now')
213
# After program loses reference to instance in 'p', process dies.
214
215
216