OLD | NEW |
| (Empty) |
1 #!/usr/bin/env python | |
2 # | |
3 # $Id: _pslinux.py 1142 2011-10-05 18:45:49Z g.rodola $ | |
4 # | |
5 # Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved. | |
6 # Use of this source code is governed by a BSD-style license that can be | |
7 # found in the LICENSE file. | |
8 | |
9 """Linux platform implementation.""" | |
10 | |
11 import os | |
12 import errno | |
13 import socket | |
14 import struct | |
15 import sys | |
16 import base64 | |
17 import re | |
18 | |
19 import _psutil_posix | |
20 import _psutil_linux | |
21 from psutil import _psposix | |
22 from psutil.error import AccessDenied, NoSuchProcess, TimeoutExpired | |
23 from psutil._common import * | |
24 | |
25 __extra__all__ = [ | |
26 "IOPRIO_CLASS_NONE", "IOPRIO_CLASS_RT", "IOPRIO_CLASS_BE", | |
27 "IOPRIO_CLASS_IDLE", | |
28 "phymem_buffers", "cached_phymem"] | |
29 | |
30 | |
31 def _get_boot_time(): | |
32 """Return system boot time (epoch in seconds)""" | |
33 f = open('/proc/stat', 'r') | |
34 try: | |
35 for line in f: | |
36 if line.startswith('btime'): | |
37 return float(line.strip().split()[1]) | |
38 raise RuntimeError("line not found") | |
39 finally: | |
40 f.close() | |
41 | |
42 def _get_num_cpus(): | |
43 """Return the number of CPUs on the system""" | |
44 num = 0 | |
45 f = open('/proc/cpuinfo', 'r') | |
46 try: | |
47 lines = f.readlines() | |
48 finally: | |
49 f.close() | |
50 for line in lines: | |
51 if line.lower().startswith('processor'): | |
52 num += 1 | |
53 | |
54 # unknown format (e.g. amrel/sparc architectures), see: | |
55 # http://code.google.com/p/psutil/issues/detail?id=200 | |
56 if num == 0: | |
57 f = open('/proc/stat', 'r') | |
58 try: | |
59 lines = f.readlines() | |
60 finally: | |
61 f.close() | |
62 search = re.compile('cpu\d') | |
63 for line in lines: | |
64 line = line.split(' ')[0] | |
65 if search.match(line): | |
66 num += 1 | |
67 | |
68 if num == 0: | |
69 raise RuntimeError("can't determine number of CPUs") | |
70 return num | |
71 | |
72 | |
73 # Number of clock ticks per second | |
74 _CLOCK_TICKS = os.sysconf(os.sysconf_names["SC_CLK_TCK"]) | |
75 _TERMINAL_MAP = _psposix._get_terminal_map() | |
76 BOOT_TIME = _get_boot_time() | |
77 NUM_CPUS = _get_num_cpus() | |
78 # ioprio_* constants http://linux.die.net/man/2/ioprio_get | |
79 IOPRIO_CLASS_NONE = 0 | |
80 IOPRIO_CLASS_RT = 1 | |
81 IOPRIO_CLASS_BE = 2 | |
82 IOPRIO_CLASS_IDLE = 3 | |
83 | |
84 # http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h | |
85 _TCP_STATES_TABLE = {"01" : "ESTABLISHED", | |
86 "02" : "SYN_SENT", | |
87 "03" : "SYN_RECV", | |
88 "04" : "FIN_WAIT1", | |
89 "05" : "FIN_WAIT2", | |
90 "06" : "TIME_WAIT", | |
91 "07" : "CLOSE", | |
92 "08" : "CLOSE_WAIT", | |
93 "09" : "LAST_ACK", | |
94 "0A" : "LISTEN", | |
95 "0B" : "CLOSING" | |
96 } | |
97 | |
98 # --- system memory functions | |
99 | |
100 def cached_phymem(): | |
101 """Return the amount of cached memory on the system, in bytes. | |
102 This reflects the "cached" column of free command line utility. | |
103 """ | |
104 f = open('/proc/meminfo', 'r') | |
105 try: | |
106 for line in f: | |
107 if line.startswith('Cached:'): | |
108 return int(line.split()[1]) * 1024 | |
109 raise RuntimeError("line not found") | |
110 finally: | |
111 f.close() | |
112 | |
113 def phymem_buffers(): | |
114 """Return the amount of physical memory buffers used by the | |
115 kernel in bytes. | |
116 This reflects the "buffers" column of free command line utility. | |
117 """ | |
118 f = open('/proc/meminfo', 'r') | |
119 try: | |
120 for line in f: | |
121 if line.startswith('Buffers:'): | |
122 return int(line.split()[1]) * 1024 | |
123 raise RuntimeError("line not found") | |
124 finally: | |
125 f.close() | |
126 | |
127 def phymem_usage(): | |
128 # total, used and free values are matched against free cmdline utility | |
129 # the percentage matches top/htop and gnome-system-monitor | |
130 f = open('/proc/meminfo', 'r') | |
131 try: | |
132 total = free = buffers = cached = None | |
133 for line in f: | |
134 if line.startswith('MemTotal:'): | |
135 total = int(line.split()[1]) * 1024 | |
136 elif line.startswith('MemFree:'): | |
137 free = int(line.split()[1]) * 1024 | |
138 elif line.startswith('Buffers:'): | |
139 buffers = int(line.split()[1]) * 1024 | |
140 elif line.startswith('Cached:'): | |
141 cached = int(line.split()[1]) * 1024 | |
142 break | |
143 used = total - free | |
144 percent = usage_percent(total - (free + buffers + cached), total, | |
145 _round=1) | |
146 return ntuple_sysmeminfo(total, used, free, percent) | |
147 finally: | |
148 f.close() | |
149 | |
150 | |
151 def virtmem_usage(): | |
152 f = open('/proc/meminfo', 'r') | |
153 try: | |
154 total = free = None | |
155 for line in f: | |
156 if line.startswith('SwapTotal:'): | |
157 total = int(line.split()[1]) * 1024 | |
158 elif line.startswith('SwapFree:'): | |
159 free = int(line.split()[1]) * 1024 | |
160 if total is not None and free is not None: | |
161 break | |
162 assert total is not None and free is not None | |
163 used = total - free | |
164 percent = usage_percent(used, total, _round=1) | |
165 return ntuple_sysmeminfo(total, used, free, percent) | |
166 finally: | |
167 f.close() | |
168 | |
169 | |
170 # --- system CPU functions | |
171 | |
172 def get_system_cpu_times(): | |
173 """Return a named tuple representing the following CPU times: | |
174 user, nice, system, idle, iowait, irq, softirq. | |
175 """ | |
176 f = open('/proc/stat', 'r') | |
177 try: | |
178 values = f.readline().split() | |
179 finally: | |
180 f.close() | |
181 | |
182 values = values[1:8] | |
183 values = tuple([float(x) / _CLOCK_TICKS for x in values]) | |
184 return ntuple_sys_cputimes(*values[:7]) | |
185 | |
186 def get_system_per_cpu_times(): | |
187 """Return a list of namedtuple representing the CPU times | |
188 for every CPU available on the system. | |
189 """ | |
190 cpus = [] | |
191 f = open('/proc/stat', 'r') | |
192 # get rid of the first line who refers to system wide CPU stats | |
193 try: | |
194 f.readline() | |
195 for line in f.readlines(): | |
196 if line.startswith('cpu'): | |
197 values = line.split()[1:8] | |
198 values = tuple([float(x) / _CLOCK_TICKS for x in values]) | |
199 entry = ntuple_sys_cputimes(*values[:7]) | |
200 cpus.append(entry) | |
201 return cpus | |
202 finally: | |
203 f.close() | |
204 | |
205 | |
206 # --- system disk functions | |
207 | |
208 def disk_partitions(all=False): | |
209 """Return mounted disk partitions as a list of nameduples""" | |
210 phydevs = [] | |
211 f = open("/proc/filesystems", "r") | |
212 try: | |
213 for line in f: | |
214 if not line.startswith("nodev"): | |
215 phydevs.append(line.strip()) | |
216 finally: | |
217 f.close() | |
218 | |
219 retlist = [] | |
220 partitions = _psutil_linux.get_disk_partitions() | |
221 for partition in partitions: | |
222 device, mountpoint, fstype = partition | |
223 if device == 'none': | |
224 device = '' | |
225 if not all: | |
226 if device == '' or fstype not in phydevs: | |
227 continue | |
228 ntuple = ntuple_partition(device, mountpoint, fstype) | |
229 retlist.append(ntuple) | |
230 return retlist | |
231 | |
232 get_disk_usage = _psposix.get_disk_usage | |
233 | |
234 # --- process functions | |
235 | |
236 def get_pid_list(): | |
237 """Returns a list of PIDs currently running on the system.""" | |
238 pids = [int(x) for x in os.listdir('/proc') if x.isdigit()] | |
239 return pids | |
240 | |
241 def pid_exists(pid): | |
242 """Check For the existence of a unix pid.""" | |
243 return _psposix.pid_exists(pid) | |
244 | |
245 def network_io_counters(): | |
246 """Return network I/O statistics for every network interface | |
247 installed on the system as a dict of raw tuples. | |
248 """ | |
249 f = open("/proc/net/dev", "r") | |
250 try: | |
251 lines = f.readlines() | |
252 finally: | |
253 f.close() | |
254 | |
255 retdict = {} | |
256 for line in lines[2:]: | |
257 fields = line.split() | |
258 name = fields[0][:-1] | |
259 bytes_recv = int(fields[1]) | |
260 packets_recv = int(fields[2]) | |
261 bytes_sent = int(fields[9]) | |
262 packets_sent = int(fields[10]) | |
263 retdict[name] = (bytes_sent, bytes_recv, packets_sent, packets_recv) | |
264 return retdict | |
265 | |
266 def disk_io_counters(): | |
267 """Return disk I/O statistics for every disk installed on the | |
268 system as a dict of raw tuples. | |
269 """ | |
270 # man iostat states that sectors are equivalent with blocks and | |
271 # have a size of 512 bytes since 2.4 kernels. This value is | |
272 # needed to calculate the amount of disk I/O in bytes. | |
273 SECTOR_SIZE = 512 | |
274 | |
275 # determine partitions we want to look for | |
276 partitions = [] | |
277 f = open("/proc/partitions", "r") | |
278 try: | |
279 lines = f.readlines()[2:] | |
280 finally: | |
281 f.close() | |
282 for line in lines: | |
283 _, _, _, name = line.split() | |
284 if name[-1].isdigit(): | |
285 partitions.append(name) | |
286 # | |
287 retdict = {} | |
288 f = open("/proc/diskstats", "r") | |
289 try: | |
290 lines = f.readlines() | |
291 finally: | |
292 f.close() | |
293 for line in lines: | |
294 _, _, name, reads, _, rbytes, rtime, writes, _, wbytes, wtime = \ | |
295 line.split()[:11] | |
296 if name in partitions: | |
297 rbytes = int(rbytes) * SECTOR_SIZE | |
298 wbytes = int(wbytes) * SECTOR_SIZE | |
299 reads = int(reads) | |
300 writes = int(writes) | |
301 # TODO: times are expressed in milliseconds while OSX/BSD has | |
302 # these expressed in nanoseconds; figure this out. | |
303 rtime = int(rtime) | |
304 wtime = int(wtime) | |
305 retdict[name] = (reads, writes, rbytes, wbytes, rtime, wtime) | |
306 return retdict | |
307 | |
308 | |
309 # taken from /fs/proc/array.c | |
310 _status_map = {"R" : STATUS_RUNNING, | |
311 "S" : STATUS_SLEEPING, | |
312 "D" : STATUS_DISK_SLEEP, | |
313 "T" : STATUS_STOPPED, | |
314 "t" : STATUS_TRACING_STOP, | |
315 "Z" : STATUS_ZOMBIE, | |
316 "X" : STATUS_DEAD, | |
317 "x" : STATUS_DEAD, | |
318 "K" : STATUS_WAKE_KILL, | |
319 "W" : STATUS_WAKING} | |
320 | |
321 # --- decorators | |
322 | |
323 def wrap_exceptions(callable): | |
324 """Call callable into a try/except clause and translate ENOENT, | |
325 EACCES and EPERM in NoSuchProcess or AccessDenied exceptions. | |
326 """ | |
327 def wrapper(self, *args, **kwargs): | |
328 try: | |
329 return callable(self, *args, **kwargs) | |
330 except (OSError, IOError), err: | |
331 # ENOENT (no such file or directory) gets raised on open(). | |
332 # ESRCH (no such process) can get raised on read() if | |
333 # process is gone in meantime. | |
334 if err.errno in (errno.ENOENT, errno.ESRCH): | |
335 raise NoSuchProcess(self.pid, self._process_name) | |
336 if err.errno in (errno.EPERM, errno.EACCES): | |
337 raise AccessDenied(self.pid, self._process_name) | |
338 raise | |
339 return wrapper | |
340 | |
341 | |
342 class Process(object): | |
343 """Linux process implementation.""" | |
344 | |
345 __slots__ = ["pid", "_process_name"] | |
346 | |
347 def __init__(self, pid): | |
348 self.pid = pid | |
349 self._process_name = None | |
350 | |
351 @wrap_exceptions | |
352 def get_process_name(self): | |
353 f = open("/proc/%s/stat" % self.pid) | |
354 try: | |
355 name = f.read().split(' ')[1].replace('(', '').replace(')', '') | |
356 finally: | |
357 f.close() | |
358 # XXX - gets changed later and probably needs refactoring | |
359 return name | |
360 | |
361 def get_process_exe(self): | |
362 if self.pid in (0, 2): | |
363 raise AccessDenied(self.pid, self._process_name) | |
364 try: | |
365 exe = os.readlink("/proc/%s/exe" % self.pid) | |
366 except (OSError, IOError), err: | |
367 if err.errno == errno.ENOENT: | |
368 # no such file error; might be raised also if the | |
369 # path actually exists for system processes with | |
370 # low pids (about 0-20) | |
371 if os.path.lexists("/proc/%s/exe" % self.pid): | |
372 return "" | |
373 else: | |
374 # ok, it is a process which has gone away | |
375 raise NoSuchProcess(self.pid, self._process_name) | |
376 if err.errno in (errno.EPERM, errno.EACCES): | |
377 raise AccessDenied(self.pid, self._process_name) | |
378 raise | |
379 | |
380 # readlink() might return paths containing null bytes causing | |
381 # problems when used with other fs-related functions (os.*, | |
382 # open(), ...) | |
383 exe = exe.replace('\x00', '') | |
384 # It seems symlinks can point to a deleted/invalid location | |
385 # (this usually happens with "pulseaudio" process). | |
386 # However, if we had permissions to execute readlink() it's | |
387 # likely that we'll be able to figure out exe from argv[0] | |
388 # later on. | |
389 if exe.endswith(" (deleted)") and not os.path.isfile(exe): | |
390 return "" | |
391 return exe | |
392 | |
393 @wrap_exceptions | |
394 def get_process_cmdline(self): | |
395 f = open("/proc/%s/cmdline" % self.pid) | |
396 try: | |
397 # return the args as a list | |
398 return [x for x in f.read().split('\x00') if x] | |
399 finally: | |
400 f.close() | |
401 | |
402 @wrap_exceptions | |
403 def get_process_terminal(self): | |
404 f = open("/proc/%s/stat" % self.pid) | |
405 try: | |
406 tty_nr = int(f.read().split(' ')[6]) | |
407 finally: | |
408 f.close() | |
409 try: | |
410 return _TERMINAL_MAP[tty_nr] | |
411 except KeyError: | |
412 return None | |
413 | |
414 @wrap_exceptions | |
415 def get_process_io_counters(self): | |
416 f = open("/proc/%s/io" % self.pid) | |
417 try: | |
418 for line in f: | |
419 if line.startswith("rchar"): | |
420 read_count = int(line.split()[1]) | |
421 elif line.startswith("wchar"): | |
422 write_count = int(line.split()[1]) | |
423 elif line.startswith("read_bytes"): | |
424 read_bytes = int(line.split()[1]) | |
425 elif line.startswith("write_bytes"): | |
426 write_bytes = int(line.split()[1]) | |
427 return ntuple_io(read_count, write_count, read_bytes, write_bytes) | |
428 finally: | |
429 f.close() | |
430 | |
431 @wrap_exceptions | |
432 def get_cpu_times(self): | |
433 f = open("/proc/%s/stat" % self.pid) | |
434 try: | |
435 st = f.read().strip() | |
436 finally: | |
437 f.close() | |
438 # ignore the first two values ("pid (exe)") | |
439 st = st[st.find(')') + 2:] | |
440 values = st.split(' ') | |
441 utime = float(values[11]) / _CLOCK_TICKS | |
442 stime = float(values[12]) / _CLOCK_TICKS | |
443 return ntuple_cputimes(utime, stime) | |
444 | |
445 @wrap_exceptions | |
446 def process_wait(self, timeout=None): | |
447 try: | |
448 return _psposix.wait_pid(self.pid, timeout) | |
449 except TimeoutExpired: | |
450 raise TimeoutExpired(self.pid, self._process_name) | |
451 | |
452 @wrap_exceptions | |
453 def get_process_create_time(self): | |
454 f = open("/proc/%s/stat" % self.pid) | |
455 try: | |
456 st = f.read().strip() | |
457 finally: | |
458 f.close() | |
459 # ignore the first two values ("pid (exe)") | |
460 st = st[st.find(')') + 2:] | |
461 values = st.split(' ') | |
462 # According to documentation, starttime is in field 21 and the | |
463 # unit is jiffies (clock ticks). | |
464 # We first divide it for clock ticks and then add uptime returning | |
465 # seconds since the epoch, in UTC. | |
466 starttime = (float(values[19]) / _CLOCK_TICKS) + BOOT_TIME | |
467 return starttime | |
468 | |
469 @wrap_exceptions | |
470 def get_memory_info(self): | |
471 f = open("/proc/%s/status" % self.pid) | |
472 try: | |
473 virtual_size = 0 | |
474 resident_size = 0 | |
475 _flag = False | |
476 for line in f: | |
477 if (not _flag) and line.startswith("VmSize:"): | |
478 virtual_size = int(line.split()[1]) * 1024 | |
479 _flag = True | |
480 elif line.startswith("VmRSS"): | |
481 resident_size = int(line.split()[1]) * 1024 | |
482 break | |
483 return ntuple_meminfo(resident_size, virtual_size) | |
484 finally: | |
485 f.close() | |
486 | |
487 @wrap_exceptions | |
488 def get_process_cwd(self): | |
489 # readlink() might return paths containing null bytes causing | |
490 # problems when used with other fs-related functions (os.*, | |
491 # open(), ...) | |
492 path = os.readlink("/proc/%s/cwd" % self.pid) | |
493 return path.replace('\x00', '') | |
494 | |
495 @wrap_exceptions | |
496 def get_process_num_threads(self): | |
497 f = open("/proc/%s/status" % self.pid) | |
498 try: | |
499 for line in f: | |
500 if line.startswith("Threads:"): | |
501 return int(line.split()[1]) | |
502 raise RuntimeError("line not found") | |
503 finally: | |
504 f.close() | |
505 | |
506 @wrap_exceptions | |
507 def get_process_threads(self): | |
508 thread_ids = os.listdir("/proc/%s/task" % self.pid) | |
509 thread_ids.sort() | |
510 retlist = [] | |
511 for thread_id in thread_ids: | |
512 try: | |
513 f = open("/proc/%s/task/%s/stat" % (self.pid, thread_id)) | |
514 except (OSError, IOError), err: | |
515 if err.errno == errno.ENOENT: | |
516 # no such file or directory; it means thread | |
517 # disappeared on us | |
518 continue | |
519 raise | |
520 try: | |
521 st = f.read().strip() | |
522 finally: | |
523 f.close() | |
524 # ignore the first two values ("pid (exe)") | |
525 st = st[st.find(')') + 2:] | |
526 values = st.split(' ') | |
527 utime = float(values[11]) / _CLOCK_TICKS | |
528 stime = float(values[12]) / _CLOCK_TICKS | |
529 ntuple = ntuple_thread(int(thread_id), utime, stime) | |
530 retlist.append(ntuple) | |
531 return retlist | |
532 | |
533 @wrap_exceptions | |
534 def get_process_nice(self): | |
535 #f = open('/proc/%s/stat' % self.pid, 'r') | |
536 #try: | |
537 # data = f.read() | |
538 # return int(data.split()[18]) | |
539 #finally: | |
540 # f.close() | |
541 | |
542 # Use C implementation | |
543 return _psutil_posix.getpriority(self.pid) | |
544 | |
545 @wrap_exceptions | |
546 def set_process_nice(self, value): | |
547 return _psutil_posix.setpriority(self.pid, value) | |
548 | |
549 # only starting from kernel 2.6.13 | |
550 if hasattr(_psutil_linux, "ioprio_get"): | |
551 | |
552 @wrap_exceptions | |
553 def get_process_ionice(self): | |
554 ioclass, value = _psutil_linux.ioprio_get(self.pid) | |
555 return ntuple_ionice(ioclass, value) | |
556 | |
557 @wrap_exceptions | |
558 def set_process_ionice(self, ioclass, value): | |
559 if ioclass in (IOPRIO_CLASS_NONE, None): | |
560 if value: | |
561 raise ValueError("can't specify value with IOPRIO_CLASS_NONE
") | |
562 ioclass = IOPRIO_CLASS_NONE | |
563 value = 0 | |
564 if ioclass in (IOPRIO_CLASS_RT, IOPRIO_CLASS_BE): | |
565 if value is None: | |
566 value = 4 | |
567 elif ioclass == IOPRIO_CLASS_IDLE: | |
568 if value: | |
569 raise ValueError("can't specify value with IOPRIO_CLASS_IDLE
") | |
570 value = 0 | |
571 else: | |
572 value = 0 | |
573 if not 0 <= value <= 8: | |
574 raise ValueError("value argument range expected is between 0 and
8") | |
575 return _psutil_linux.ioprio_set(self.pid, ioclass, value) | |
576 | |
577 @wrap_exceptions | |
578 def get_process_status(self): | |
579 f = open("/proc/%s/status" % self.pid) | |
580 try: | |
581 for line in f: | |
582 if line.startswith("State:"): | |
583 letter = line.split()[1] | |
584 if letter in _status_map: | |
585 return _status_map[letter] | |
586 return constant(-1, '?') | |
587 finally: | |
588 f.close() | |
589 | |
590 @wrap_exceptions | |
591 def get_open_files(self): | |
592 retlist = [] | |
593 files = os.listdir("/proc/%s/fd" % self.pid) | |
594 for fd in files: | |
595 file = "/proc/%s/fd/%s" % (self.pid, fd) | |
596 if os.path.islink(file): | |
597 file = os.readlink(file) | |
598 if file.startswith("socket:["): | |
599 continue | |
600 if file.startswith("pipe:["): | |
601 continue | |
602 if file == "[]": | |
603 continue | |
604 if os.path.isfile(file) and not file in retlist: | |
605 ntuple = ntuple_openfile(file, int(fd)) | |
606 retlist.append(ntuple) | |
607 return retlist | |
608 | |
609 @wrap_exceptions | |
610 def get_connections(self): | |
611 inodes = {} | |
612 # os.listdir() is gonna raise a lot of access denied | |
613 # exceptions in case of unprivileged user; that's fine: | |
614 # lsof does the same so it's unlikely that we can to better. | |
615 for fd in os.listdir("/proc/%s/fd" % self.pid): | |
616 try: | |
617 inode = os.readlink("/proc/%s/fd/%s" % (self.pid, fd)) | |
618 except OSError: | |
619 continue | |
620 if inode.startswith('socket:['): | |
621 # the process is using a socket | |
622 inode = inode[8:][:-1] | |
623 inodes[inode] = fd | |
624 | |
625 if not inodes: | |
626 # no connections for this process | |
627 return [] | |
628 | |
629 def process(file, family, _type): | |
630 retlist = [] | |
631 f = open(file) | |
632 try: | |
633 f.readline() # skip the first line | |
634 for line in f: | |
635 _, laddr, raddr, status, _, _, _, _, _, inode = \ | |
636 line.split()[:10] | |
637 if inode in inodes: | |
638 laddr = self._decode_address(laddr, family) | |
639 raddr = self._decode_address(raddr, family) | |
640 if _type == socket.SOCK_STREAM: | |
641 status = _TCP_STATES_TABLE[status] | |
642 else: | |
643 status = "" | |
644 fd = int(inodes[inode]) | |
645 conn = ntuple_connection(fd, family, _type, laddr, | |
646 raddr, status) | |
647 retlist.append(conn) | |
648 return retlist | |
649 finally: | |
650 f.close() | |
651 | |
652 tcp4 = process("/proc/net/tcp", socket.AF_INET, socket.SOCK_STREAM) | |
653 udp4 = process("/proc/net/udp", socket.AF_INET, socket.SOCK_DGRAM) | |
654 try: | |
655 tcp6 = process("/proc/net/tcp6", socket.AF_INET6, socket.SOCK_STREAM
) | |
656 udp6 = process("/proc/net/udp6", socket.AF_INET6, socket.SOCK_DGRAM) | |
657 except IOError, err: | |
658 if err.errno == errno.ENOENT: | |
659 # IPv6 is not supported on this platform | |
660 tcp6 = udp6 = [] | |
661 else: | |
662 raise | |
663 return tcp4 + tcp6 + udp4 + udp6 | |
664 | |
665 # --- lsof implementation | |
666 # | |
667 # def get_connections(self): | |
668 # lsof = _psposix.LsofParser(self.pid, self._process_name) | |
669 # return lsof.get_process_connections() | |
670 | |
671 @wrap_exceptions | |
672 def get_process_ppid(self): | |
673 f = open("/proc/%s/status" % self.pid) | |
674 try: | |
675 for line in f: | |
676 if line.startswith("PPid:"): | |
677 # PPid: nnnn | |
678 return int(line.split()[1]) | |
679 raise RuntimeError("line not found") | |
680 finally: | |
681 f.close() | |
682 | |
683 @wrap_exceptions | |
684 def get_process_uids(self): | |
685 f = open("/proc/%s/status" % self.pid) | |
686 try: | |
687 for line in f: | |
688 if line.startswith('Uid:'): | |
689 _, real, effective, saved, fs = line.split() | |
690 return ntuple_uids(int(real), int(effective), int(saved)) | |
691 raise RuntimeError("line not found") | |
692 finally: | |
693 f.close() | |
694 | |
695 @wrap_exceptions | |
696 def get_process_gids(self): | |
697 f = open("/proc/%s/status" % self.pid) | |
698 try: | |
699 for line in f: | |
700 if line.startswith('Gid:'): | |
701 _, real, effective, saved, fs = line.split() | |
702 return ntuple_gids(int(real), int(effective), int(saved)) | |
703 raise RuntimeError("line not found") | |
704 finally: | |
705 f.close() | |
706 | |
707 @staticmethod | |
708 def _decode_address(addr, family): | |
709 """Accept an "ip:port" address as displayed in /proc/net/* | |
710 and convert it into a human readable form, like: | |
711 | |
712 "0500000A:0016" -> ("10.0.0.5", 22) | |
713 "0000000000000000FFFF00000100007F:9E49" -> ("::ffff:127.0.0.1", 40521) | |
714 | |
715 The IP address portion is a little or big endian four-byte | |
716 hexadecimal number; that is, the least significant byte is listed | |
717 first, so we need to reverse the order of the bytes to convert it | |
718 to an IP address. | |
719 The port is represented as a two-byte hexadecimal number. | |
720 | |
721 Reference: | |
722 http://linuxdevcenter.com/pub/a/linux/2000/11/16/LinuxAdmin.html | |
723 """ | |
724 ip, port = addr.split(':') | |
725 port = int(port, 16) | |
726 if sys.version_info >= (3,): | |
727 ip = ip.encode('ascii') | |
728 # this usually refers to a local socket in listen mode with | |
729 # no end-points connected | |
730 if not port: | |
731 return () | |
732 if family == socket.AF_INET: | |
733 # see: http://code.google.com/p/psutil/issues/detail?id=201 | |
734 if sys.byteorder == 'little': | |
735 ip = socket.inet_ntop(family, base64.b16decode(ip)[::-1]) | |
736 else: | |
737 ip = socket.inet_ntop(family, base64.b16decode(ip)) | |
738 else: # IPv6 | |
739 # old version - let's keep it, just in case... | |
740 #ip = ip.decode('hex') | |
741 #return socket.inet_ntop(socket.AF_INET6, | |
742 # ''.join(ip[i:i+4][::-1] for i in xrange(0, 16, 4))) | |
743 ip = base64.b16decode(ip) | |
744 # see: http://code.google.com/p/psutil/issues/detail?id=201 | |
745 if sys.byteorder == 'little': | |
746 ip = socket.inet_ntop(socket.AF_INET6, | |
747 struct.pack('>4I', *struct.unpack('<4I', ip))) | |
748 else: | |
749 ip = socket.inet_ntop(socket.AF_INET6, | |
750 struct.pack('<4I', *struct.unpack('<4I', ip))) | |
751 return (ip, port) | |
OLD | NEW |