aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sos/plugins/__init__.py2
-rw-r--r--sos/utilities.py27
-rw-r--r--tests/utilities_tests.py5
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))