Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(151)

Unified Diff: third_party/psutil/psutil/_psposix.py

Issue 6246123: Moving psutil to third_party. This is first step for Media Performance test project. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: modification based on code review's comments Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/psutil/psutil/_psosx.py ('k') | third_party/psutil/psutil/_psutil_bsd.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: third_party/psutil/psutil/_psposix.py
diff --git a/third_party/psutil/psutil/_psposix.py b/third_party/psutil/psutil/_psposix.py
new file mode 100644
index 0000000000000000000000000000000000000000..cd860a5ff554ecfabccd7e79d85f05039d0cf022
--- /dev/null
+++ b/third_party/psutil/psutil/_psposix.py
@@ -0,0 +1,240 @@
+#!/usr/bin/env python
+#
+# $Id: _psposix.py 800 2010-11-12 21:51:25Z g.rodola $
+#
+
+"""Routines common to all posix systems."""
+
+import os
+import errno
+import subprocess
+import psutil
+import socket
+import re
+import sys
+import warnings
+
+try:
+ from collections import namedtuple
+except ImportError:
+ from psutil.compat import namedtuple # python < 2.6
+
+from psutil.error import AccessDenied, NoSuchProcess
+
+
+def pid_exists(pid):
+ """Check whether pid exists in the current process table."""
+ if pid < 0:
+ return False
+ try:
+ os.kill(pid, 0)
+ except OSError, e:
+ return e.errno == errno.EPERM
+ else:
+ return True
+
+
+class LsofParser:
+ """A wrapper for lsof command line utility.
+ Executes lsof in subprocess and parses its output.
+ """
+ socket_table = {'TCP' : socket.SOCK_STREAM,
+ 'UDP' : socket.SOCK_DGRAM,
+ 'IPv4' : socket.AF_INET,
+ 'IPv6' : socket.AF_INET6}
+ _openfile_ntuple = namedtuple('openfile', 'path fd')
+ _connection_ntuple = namedtuple('connection', 'fd family type local_address '
+ 'remote_address status')
+
+ def __init__(self, pid, name):
+ self.pid = pid
+ self.process_name = name
+
+ def get_process_open_files(self):
+ """Return files opened by process by parsing lsof output."""
+ # Options:
+ # -i == network files only
+ # -a == ANDing of all options
+ # -p == process with given PID only
+ # -n == do not resolve IP addresses
+ # -P == do not resolve port numbers
+ # -w == suppresses warnings
+ # -F0nPt == (0) separate lines with "\x00"
+ # (n) file name
+ # (t) file type
+ # (f) file descriptr
+ cmd = "lsof -a -p %s -n -P -F0ftn" % self.pid
+ stdout = self.runcmd(cmd)
+ if not stdout:
+ return []
+ files = []
+ lines = stdout.split("\n")
+ del lines[0] # first line contains the PID
+ for line in lines:
+ if not line:
+ continue
+ line = line.strip("\x00")
+ fields = {}
+ for field in line.split("\x00"):
+ key, value = field[0], field[1:]
+ fields[key] = value
+ if not 't' in fields:
+ continue
+ _type = fields['t']
+ fd = fields['f']
+ name = fields['n']
+ if 'REG' in _type and fd.isdigit():
+ if not os.path.isfile(os.path.realpath(name)):
+ continue
+ ntuple = self._openfile_ntuple(name, int(fd))
+ files.append(ntuple)
+ return files
+
+ def get_process_connections(self):
+ """Return connections opened by a process by parsing lsof output."""
+ # Options:
+ # -i == network files only
+ # -a == ANDing of all options
+ # -p == process with given PID only
+ # -n == do not resolve IP addresses
+ # -P == do not resolve port numbers
+ # -w == suppresses warnings
+ # -F0nPt == (0) separate lines with "\x00"
+ # (n) and show internet addresses only
+ # (P) protocol type (TCP, UPD, Unix)
+ # (t) socket family (IPv4, IPv6)
+ # (T) connection status
+ # (f) file descriptors
+ cmd = "lsof -p %s -i -a -F0nPtTf -n -P" % self.pid
+ stdout = self.runcmd(cmd)
+ if not stdout:
+ return []
+ connections = []
+ lines = stdout.split()
+ del lines[0] # first line contains the PID
+ for line in lines:
+ line = line.strip("\x00")
+ fields = {}
+ for field in line.split("\x00"):
+ if field.startswith('T'):
+ key, value = field.split('=')
+ else:
+ key, value = field[0], field[1:]
+ fields[key] = value
+
+ # XXX - might trow execption; needs "continue on unsupported
+ # family or type" (e.g. unix sockets)
+ # we consider TCP and UDP sockets only
+ stype = fields['P']
+ if stype not in self.socket_table:
+ continue
+ else:
+ _type = self.socket_table[fields['P']]
+ family = self.socket_table[fields['t']]
+ peers = fields['n']
+ fd = int(fields['f'])
+ if _type == socket.SOCK_STREAM:
+ status = fields['TST']
+ # OS X shows "CLOSED" instead of "CLOSE" so translate them
+ if status == "CLOSED":
+ status = "CLOSE"
+ else:
+ status = ""
+ if not '->' in peers:
+ local_addr = self._normaddress(peers, family)
+ remote_addr = ()
+ # OS X processes e.g. SystemUIServer can return *:* for local
+ # address, so we return 0 and move on
+ if local_addr == 0:
+ continue
+ else:
+ local_addr, remote_addr = peers.split("->")
+ local_addr = self._normaddress(local_addr, family)
+ remote_addr = self._normaddress(remote_addr, family)
+
+ conn = self._connection_ntuple(fd, family, _type, local_addr,
+ remote_addr, status)
+ connections.append(conn)
+
+ return connections
+
+ def runcmd(self, cmd):
+ """Expects an lsof-related command line, execute it in a
+ subprocess and return its output.
+ If something goes bad stderr is parsed and proper exceptions
+ raised as necessary.
+ """
+ p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, stderr = p.communicate()
+ if sys.version_info >= (3,):
+ stdout, stderr = map(lambda x: x.decode(sys.stdout.encoding),
+ (stdout, stderr))
+ if stderr:
+ utility = cmd.split(' ')[0]
+ if self._which(utility) is None:
+ msg = "this functionnality requires %s command line utility " \
+ "to be installed on the system" % utility
+ raise NotImplementedError(msg)
+ elif "permission denied" in stderr.lower():
+ # "permission denied" can be found also in case of zombie
+ # processes;
+ p = psutil.Process(self.pid)
+ if not p.is_running():
+ raise NoSuchProcess(self.pid, self.process_name)
+ raise AccessDenied(self.pid, self.process_name)
+ elif "lsof: warning:" in stderr.lower():
+ # usually appears when lsof is run for the first time and
+ # complains about missing cache file in user home
+ warnings.warn(stderr, RuntimeWarning)
+ else:
+ # this must be considered an application bug
+ raise RuntimeError(stderr)
+ if not stdout:
+ p = psutil.Process(self.pid)
+ if not p.is_running():
+ raise NoSuchProcess(self.pid, self.process_name)
+ return ""
+ return stdout
+
+ @staticmethod
+ def _which(program):
+ """Same as UNIX which command. Return None on command not found."""
+ def is_exe(fpath):
+ return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+
+ fpath, fname = os.path.split(program)
+ if fpath:
+ if is_exe(program):
+ return program
+ else:
+ for path in os.environ["PATH"].split(os.pathsep):
+ exe_file = os.path.join(path, program)
+ if is_exe(exe_file):
+ return exe_file
+ return None
+
+ @staticmethod
+ def _normaddress(addr, family):
+ """Normalize an IP address."""
+ assert family in (socket.AF_INET, socket.AF_INET6), "unsupported family"
+ if family == socket.AF_INET:
+ ip, port = addr.split(':')
+ else:
+ if "]" in addr:
+ ip, port = re.findall('\[([^]]+)\]:([0-9]+)', addr)[0]
+ else:
+ ip, port = addr.split(':')
+ if ip == '*':
+ if family == socket.AF_INET:
+ ip = "0.0.0.0"
+ elif family == socket.AF_INET6:
+ ip = "::"
+ # OS X can have some procs e.g. SystemUIServer listening on *:*
+ else:
+ raise ValueError("invalid IP %s" %addr)
+ if port == "*":
+ return 0
+ return (ip, int(port))
+
+
« no previous file with comments | « third_party/psutil/psutil/_psosx.py ('k') | third_party/psutil/psutil/_psutil_bsd.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698