commit 032df08a5591afaf810dabdbca9177fcc528a7ee Author: Damian Johnson atagar@torproject.org Date: Mon Sep 2 13:16:00 2013 -0700
Adding stem.util.system.get_name_by_pid()
Function for getting the command running under a given pid. This is the inverse of get_pid_by_name(). --- docs/change_log.rst | 1 + stem/util/system.py | 42 ++++++++++++++++++++++++++++++++++++++++++ test/unit/util/system.py | 23 +++++++++++++++++++++++ 3 files changed, 66 insertions(+)
diff --git a/docs/change_log.rst b/docs/change_log.rst index a368eb0..75a5e81 100644 --- a/docs/change_log.rst +++ b/docs/change_log.rst @@ -60,6 +60,7 @@ The following are only available within stem's `git repository * :func:`~stem.util.system.set_process_name` inserted spaces between characters (:trac:`8631`) * :func:`~stem.util.system.get_pid_by_name` can now pull for all processes with a given name * :func:`~stem.util.system.call` ignored the subprocess' exit status + * Added :func:`stem.util.system.get_name_by_pid` * Added :func:`stem.util.system.get_user` * Added :func:`stem.util.system.get_start_time` * Added :func:`stem.util.system.get_bsd_jail_path` diff --git a/stem/util/system.py b/stem/util/system.py index fcec8d1..01eea06 100644 --- a/stem/util/system.py +++ b/stem/util/system.py @@ -16,6 +16,7 @@ best-effort, providing **None** if the lookup fails.
is_available - determines if a command is available on this system is_running - determines if a given process is running + get_name_by_pid - gets the name for a process by the given pid get_pid_by_name - gets the pid for a process by the given name get_pid_by_port - gets the pid for a process listening to a given port get_pid_by_open_file - gets the pid for the process with an open file @@ -60,6 +61,7 @@ SHELL_COMMANDS = ['ulimit']
IS_RUNNING_PS_LINUX = "ps -A co command" IS_RUNNING_PS_BSD = "ps -ao ucomm=" +GET_NAME_BY_PID_PS = "ps -p %s -o comm" GET_PID_BY_NAME_PGREP = "pgrep -x %s" GET_PID_BY_NAME_PIDOF = "pidof %s" GET_PID_BY_NAME_PS_LINUX = "ps -o pid -C %s" @@ -225,6 +227,46 @@ def is_running(command): return None
+def get_name_by_pid(pid): + """ + Attempts to determine the name a given process is running under (not + including arguments). This uses... + + :: + + 1. Information from /proc + 2. ps -p <pid> -o command + + :param int pid: process id of the process to be queried + + :returns: **str** with the process name, **None** if it can't be determined + """ + + process_name = None + + if stem.util.proc.is_available(): + try: + process_name = stem.util.proc.get_stats(pid, stem.util.proc.Stat.COMMAND)[0] + except IOError: + pass + + # attempts to resolve using ps, failing if: + # - system's ps variant doesn't handle these flags (none known at the moment) + # + # example output: + # atagar@morrigan:~$ ps -p 5767 -o comm + # COMMAND + # vim + + if not process_name: + results = call(GET_NAME_BY_PID_PS % pid) + + if results and len(results) == 2 and results[0] == 'COMMAND': + process_name = results[1].strip() + + return process_name + + def get_pid_by_name(process_name, multiple = False): """ Attempts to determine the process id for a running process, using... diff --git a/test/unit/util/system.py b/test/unit/util/system.py index 628ab71..36204f6 100644 --- a/test/unit/util/system.py +++ b/test/unit/util/system.py @@ -134,6 +134,29 @@ class TestSystem(unittest.TestCase): self.assertEquals(None, system.is_running("irssi"))
@patch('stem.util.system.call') + @patch('stem.util.proc.is_available', Mock(return_value = False)) + @patch('stem.util.system.is_available', Mock(return_value = True)) + def test_get_name_by_pid_ps(self, call_mock): + """ + Tests the get_name_by_pid function with ps responses. + """ + + responses = { + "success": ["COMMAND", "vim"], + "malformed_command_1": ["COMMAND"], + "malformed_command_2": ["foobar"], + "malformed_command_3": ["NOT_COMMAND", "vim"], + "no_results": [], + "command_fails": None, + } + + call_mock.side_effect = mock_call(system.GET_NAME_BY_PID_PS, responses) + + for test_input in responses: + expected_response = "vim" if test_input == "success" else None + self.assertEquals(expected_response, system.get_name_by_pid(test_input)) + + @patch('stem.util.system.call') @patch('stem.util.system.is_available', Mock(return_value = True)) def test_get_pid_by_name_pgrep(self, call_mock): """
tor-commits@lists.torproject.org