From 3b215e5c7a79c588776ba1fe439a6cfa9faa3e0f Mon Sep 17 00:00:00 2001
From: "Bryn M. Reeves" <bmr@redhat.com>
Date: Sun, 25 Jan 2015 14:20:10 +0000
Subject: [PATCH 56/93] [utilities] add chroot support to
sos_get_command_output()
Allow callers of sos_get_command_output() to specify a path to
chroot into before executing command.
Signed-off-by: Bryn M. Reeves <bmr@redhat.com>
---
sos/plugins/__init__.py | 2 +-
sos/utilities.py | 26 +++++++++++++++-----------
tests/utilities_tests.py | 5 +++++
3 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py
index 14136b4..3f8f628 100644
--- a/sos/plugins/__init__.py
+++ b/sos/plugins/__init__.py
@@ -493,7 +493,7 @@ class Plugin(object):
self._log_info("added copyspec '%s'" % copy_paths)
def get_command_output(self, prog, timeout=300, runat=None):
- result = sos_get_command_output(prog, timeout=timeout, runat=runat)
+ result = sos_get_command_output(prog, timeout=timeout, chdir=runat)
if result['status'] == 124:
self._log_warn("command '%s' timed out after %ds"
% (prog, timeout))
diff --git a/sos/utilities.py b/sos/utilities.py
index 51909c6..cc25a8f 100644
--- a/sos/utilities.py
+++ b/sos/utilities.py
@@ -120,15 +120,19 @@ 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):
- """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, 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
@@ -144,7 +148,7 @@ def sos_get_command_output(command, timeout=300, runat=None):
try:
p = Popen(args, shell=False, stdout=PIPE, stderr=STDOUT,
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': ""}
@@ -184,7 +188,7 @@ def shell_out(cmd, 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, runat=runat)['output']
+ return sos_get_command_output(cmd, chdir=runat)['output']
class ImporterHelper(object):
diff --git a/tests/utilities_tests.py b/tests/utilities_tests.py
index 60087c1..def3aed 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))
--
1.9.3