-
Notifications
You must be signed in to change notification settings - Fork 54
Expand file tree
/
Copy pathlinux_proc.py
More file actions
244 lines (202 loc) · 6.09 KB
/
linux_proc.py
File metadata and controls
244 lines (202 loc) · 6.09 KB
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
"""
Functions and variables to access to Linux proc directory.
Constant:
- PAGE_SIZE: size of a memory page
"""
from os import readlink, listdir
from resource import getpagesize
from datetime import timedelta, datetime
PAGE_SIZE = getpagesize()
class ProcError(Exception):
"""
Linux proc directory error.
"""
pass
def openProc(path):
"""
Open a proc entry in read only mode.
"""
filename = "/proc/%s" % path
try:
return open(filename)
except IOError as err:
raise ProcError("Unable to open %r: %s" % (filename, err))
def readProc(path):
"""
Read the content of a proc entry.
Eg. readProc("stat") to read /proc/stat.
"""
with openProc(path) as procfile:
return procfile.read()
def readProcessProc(pid, key):
"""
Read the content of a process entry in the proc directory.
Eg. readProcessProc(pid, "status") to read /proc/pid/status.
"""
try:
filename = "/proc/%s/%s" % (pid, key)
with open(filename) as proc:
return proc.read()
except IOError as err:
raise ProcError("Process %s doesn't exist: %s" % (pid, err))
class ProcessState(object):
"""
Processus state. Attributes:
- state (str): process status ('R', 'S', 'T', ...)
- program (str): program name
- pid (int): process identifier
- ppid (int): parent process identifier
- pgrp (int): process group
- session (int): session identifier
- tty_nr (int): tty number
- tpgid (int)
- utime (int): user space time (jiffies)
- stime (int): kernel space time (jiffies)
- starttime (int): start time
"""
STATE_NAMES = {
"R": "running",
"S": "sleeping",
"D": "disk",
"Z": "zombie",
"T": "traced",
"W": "paging",
}
def __init__(self, stat):
# pid (program) ... => "pid (program", "..."
part, stat = stat.rsplit(')', 1)
self.pid, self.program = part.split('(', 1)
self.pid = int(self.pid)
# "state ..." => state, "..."
stat = stat.split()
self.state = stat[0]
stat = [int(item) for item in stat[1:]]
# Read next numbers
self.ppid = stat[0]
self.pgrp = stat[1]
self.session = stat[2]
self.tty_nr = stat[3]
self.tpgid = stat[4]
self.utime = stat[10]
self.stime = stat[11]
self.starttime = stat[18]
def readProcessStat(pid):
"""
Read the process state ('stat') as a ProcessState object.
"""
stat = readProcessProc(pid, 'stat')
return ProcessState(stat)
def readProcessStatm(pid):
"""
Read the process memory status ('statm') as a list of integers.
Values are in bytes (and not in pages).
"""
statm = readProcessProc(pid, 'statm')
statm = [int(item) * PAGE_SIZE for item in statm.split()]
return statm
def readProcessProcList(pid, key):
"""
Read a process entry as a list of strings.
"""
data = readProcessProc(pid, key)
if not data:
# Empty file: empty list
return []
data = data.split("\0")
if not data[-1]:
del data[-1]
return data
def readProcessLink(pid, key):
"""
Read a process link.
"""
try:
filename = "/proc/%s/%s" % (pid, key)
return readlink(filename)
except OSError as err:
raise ProcError("Unable to read proc link %r: %s" % (filename, err))
def readProcesses():
"""
Read all processes identifiers. The function is a generator,
use it with: ::
for pid in readProcesses(): ...
"""
for filename in listdir('/proc'):
try:
yield int(filename)
except ValueError:
# Filename is not an integer (e.g. "stat" from /proc/stat)
continue
def readProcessCmdline(pid, escape_stat=True):
"""
Read the process command line. If escape_stat is True, format program name
with "[%s]" if the process has no command line, e.g. "[khelper]".
"""
# Try /proc/42/cmdline
try:
cmdline = readProcessProcList(pid, 'cmdline')
if cmdline:
return cmdline
except ProcError:
pass
# Try /proc/42/stat
try:
stat = readProcessStat(pid)
program = stat.program
if escape_stat:
program = "[%s]" % program
return [program]
except ProcError:
return None
def searchProcessesByName(process_name):
"""
Find all processes matching the program name pattern.
Eg. pattern "ssh" will find the program "/usr/bin/ssh".
This function is a generator yielding the process identifier,
use it with: ::
for pid in searchProcessByName(pattern):
...
"""
suffix = '/' + process_name
for pid in readProcesses():
cmdline = readProcessCmdline(pid)
if not cmdline:
continue
program = cmdline[0]
if program == process_name or program.endswith(suffix):
yield pid
def searchProcessByName(process_name):
"""
Function similar to searchProcessesByName() but only return the identifier
of the first matching process. Raise a ProcError if there is no matching
process.
"""
for pid in searchProcessesByName(process_name):
return pid
raise ProcError("Unable to find process: %r" % process_name)
def getUptime():
"""
Get the system uptime as a datetime.timedelta object.
"""
uptime = readProc('uptime')
uptime = uptime.strip().split()
uptime = float(uptime[0])
return timedelta(seconds=uptime)
def getSystemBoot():
"""
Get the system boot date as a datetime.datetime object.
"""
if getSystemBoot.value is None:
stat_file = openProc('stat')
for line in stat_file:
if not line.startswith("btime "):
continue
seconds = int(line[6:])
btime = datetime.fromtimestamp(seconds)
getSystemBoot.value = btime
break
stat_file.close()
if getSystemBoot.value is None:
raise ProcError("Unable to read system boot time!")
return getSystemBoot.value
getSystemBoot.value = None