commit fab872725d791e8a9ca20f28f6eb5c5358aff87b Author: Damian Johnson atagar@torproject.org Date: Thu Nov 10 09:30:06 2011 -0800
Function for querying a process' pwd
Implementing and testing a stem.util.system.get_pwd(pid) function. This will be needed for correcting the relative cookie paths mentioned in... https://trac.torproject.org/projects/tor/ticket/1101 --- stem/util/system.py | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ test/integ/system.py | 11 +++++++ 2 files changed, 83 insertions(+), 0 deletions(-)
diff --git a/stem/util/system.py b/stem/util/system.py index b63974d..467787c 100644 --- a/stem/util/system.py +++ b/stem/util/system.py @@ -9,6 +9,8 @@ import time import logging import subprocess
+import stem.util.proc + LOGGER = logging.getLogger("stem")
# Mapping of commands to if they're available or not. This isn't always @@ -241,6 +243,76 @@ def get_pid(process_name, process_port = None):
return None
+def get_pwd(pid): + """ + Provices the working directory of the given process. + + Arguments: + pid (int) - process id of the process to be queried + + Returns: + str with the absolute path for the process' present working directory + + Raises: + IOError if it can't be determined + """ + + # try fetching via the proc contents if it's available + if stem.util.proc.is_available(): + try: return stem.util.proc.get_pwd(pid) + except IOError: pass + + # Fall back to a pwdx query. This isn't available on BSD. If we attempt this + # lookup then it trumps lsof when reporting an exception at the end since + # it's the better lookup method for this information. + + exc_msg = None + + if is_available("pwdx"): + # pwdx results are of the form: + # 3799: /home/atagar + # 5839: No such process + + try: + results = call("pwdx %s" % pid) + + if not results: + exc_msg = "pwdx didn't return any results" + elif results[0].endswith("No such process"): + exc_msg = "pwdx reported no process for pid %s" % pid + elif len(results) != 1 or results[0].count(" ") != 1: + exc_msg = "we got unexpected output from pwdx: %s" % results + else: + return results[0].split(" ", 1)[1].strip() + except OSError, exc: + exc_msg = "pwdx query for %s failed: %s" % (pid, exc) + + # Use lsof as the final fallback. This is available on both Linux and is the + # only lookup method here that works for BSD... + # https://trac.torproject.org/projects/tor/ticket/4236 + # + # ~$ lsof -a -p 75717 -d cwd -Fn + # p75717 + # n/Users/atagar/tor/src/or + + try: + results = call("lsof -a -p %s -d cwd -Fn" % pid) + + if results and len(results) == 2 and results[1].startswith("n/"): + return results[1][1:].strip() + elif not exc_msg: + exc_msg = "we got unexpected output from lsof: %s" % results + except OSError, exc: + if not exc_msg: + exc_msg = "lsof query for the pwd of %s failed: %s" % (pid, exc) + + if not exc_msg: + # shouldn't happen, somehow we never registered a failure... + exc_msg = "unable to query pwdx or lsof" + + # we failed all lookups, raise + raise IOError(exc_msg) + def get_bsd_jail_id(pid): """ Get the FreeBSD jail id for a process. diff --git a/test/integ/system.py b/test/integ/system.py index dc5b24c..6e3370e 100644 --- a/test/integ/system.py +++ b/test/integ/system.py @@ -2,6 +2,7 @@ Unit tests for the util.system functions in the context of a tor process. """
+import os import unittest
import test.runner @@ -40,6 +41,16 @@ class TestSystemFunctions(unittest.TestCase): self.assertEquals(runner.get_pid(), system.get_pid("tor", runner.get_control_port())) self.assertEquals(None, system.get_pid("blarg_and_stuff"))
+ def test_get_pwd(self): + """ + Checks the util.system.get_pwd function. + """ + + # tor's pwd will match our process since we started it + runner = test.runner.get_runner() + self.assertEquals(os.getcwd(), system.get_pwd(runner.get_pid())) + self.assertRaises(IOError, system.get_pwd, 99999) + def test_get_bsd_jail_id(self): """ Exercises the util.system.get_bsd_jail_id function, running through the