diff options
-rw-r--r-- | sos/plugins/__init__.py | 2 | ||||
-rw-r--r-- | sos/utilities.py | 27 | ||||
-rw-r--r-- | tests/utilities_tests.py | 5 |
3 files changed, 22 insertions, 12 deletions
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py index 790338bc..137e1a1a 100644 --- a/sos/plugins/__init__.py +++ b/sos/plugins/__init__.py @@ -499,7 +499,7 @@ class Plugin(object): self._log_info("added copyspec '%s'" % copy_paths) def get_command_output(self, prog, timeout=300, runat=None, stderr=True): - result = sos_get_command_output(prog, timeout=timeout, runat=runat, + result = sos_get_command_output(prog, timeout=timeout, chdir=runat, stderr=stderr) if result['status'] == 124: self._log_warn("command '%s' timed out after %ds" diff --git a/sos/utilities.py b/sos/utilities.py index dfe61286..a82ac7c7 100644 --- a/sos/utilities.py +++ b/sos/utilities.py @@ -120,15 +120,20 @@ def is_executable(command): return any(os.access(path, os.X_OK) for path in candidates) -def sos_get_command_output(command, timeout=300, runat=None, stderr=True): - """Execute a command through the system shell. First checks to see if the - requested command is executable. Returns (returncode, stdout, 0)""" - def _child_chdir(): - if(runat): - try: - os.chdir(runat) - except: - self.log_error("failed to chdir to '%s'" % runat) +def sos_get_command_output(command, timeout=300, stderr=False, + chroot=None, chdir=None): + """Execute a command and return a dictionary of status and output, + optionally changing root or current working directory before + executing command. + """ + # Change root or cwd for child only. Exceptions in the prexec_fn + # closure are caught in the parent (chroot and chdir are bound from + # the enclosing scope). + def _child_prep_fn(): + if (chroot): + os.chroot(chroot) + if (chdir): + os.chdir(chdir) cmd_env = os.environ # ensure consistent locale for collected command output @@ -145,7 +150,7 @@ def sos_get_command_output(command, timeout=300, runat=None, stderr=True): p = Popen(args, shell=False, stdout=PIPE, stderr=STDOUT if stderr else PIPE, bufsize=-1, env=cmd_env, close_fds=True, - preexec_fn=_child_chdir) + preexec_fn=_child_prep_fn) except OSError as e: if e.errno == errno.ENOENT: return {'status': 127, 'output': ""} @@ -185,7 +190,7 @@ def shell_out(cmd, timeout=30, runat=None): """Shell out to an external command and return the output or the empty string in case of error. """ - return sos_get_command_output(cmd, timeout=timeout, runat=runat)['output'] + return sos_get_command_output(cmd, timeout=timeout, chdir=runat)['output'] class ImporterHelper(object): diff --git a/tests/utilities_tests.py b/tests/utilities_tests.py index 607056e7..9327b1f9 100644 --- a/tests/utilities_tests.py +++ b/tests/utilities_tests.py @@ -68,6 +68,11 @@ class ExecutableTest(unittest.TestCase): self.assertEquals(result['status'], 127) self.assertEquals(result['output'], "") + def test_output_chdir(self): + result = sos_get_command_output("/usr/bin/pwd", chdir=TEST_DIR) + self.assertEquals(result['status'], 0) + self.assertEquals(result['output'].strip(), TEST_DIR) + def test_shell_out(self): path = os.path.join(TEST_DIR, 'test_exe.py') self.assertEquals("executed\n", shell_out(path)) |