File: linux_proc.py

package info (click to toggle)
python-ptrace 0.7-1
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd, stretch
  • size: 680 kB
  • ctags: 1,002
  • sloc: python: 6,659; ansic: 263; makefile: 13; sh: 1
file content (229 lines) | stat: -rw-r--r-- 6,285 bytes parent folder | download
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
"""
Functions and variables to access to Linux proc directory.

Constant:

   - PAGE_SIZE: size of a memory page
"""
from __future__ import with_statement
from os import readlink, listdir
from resource import getpagesize
from ptrace.tools import timestampUNIX
from datetime import timedelta

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": "pagging",
    }
    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 (eg. "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, eg. "[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 = timestampUNIX(seconds, True)
            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