From 57cacaf8bcf3a91f2719ad628463f032e6c1bacc Mon Sep 17 00:00:00 2001 From: "Bryn M. Reeves" Date: Sun, 6 Apr 2014 17:15:15 +0100 Subject: Add 'runat' parameter to command output interfaces Add a new 'runat' parameter sos_get_command_output() to specify a directory for the child to switch to before executing the given command and propagate this through the various command output collection interfaces. Signed-off-by: Bryn M. Reeves --- sos/plugins/__init__.py | 34 ++++++++++++++++++++++++---------- sos/utilities.py | 16 ++++++++++++---- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py index f5042b41..052725d0 100644 --- a/sos/plugins/__init__.py +++ b/sos/plugins/__init__.py @@ -441,8 +441,8 @@ class Plugin(object): self.copy_paths.update(copy_paths) self.log_debug("added copyspec '%s'" % copyspec) - def get_command_output(self, prog, timeout=300): - result = sos_get_command_output(prog, timeout) + def get_command_output(self, prog, timeout=300, runat=None): + result = sos_get_command_output(prog, timeout, runat) if result['status'] == 124: self.log_warn("command '%s' timed out after %ds" % (prog, timeout)) @@ -450,12 +450,12 @@ class Plugin(object): self.log_debug("could not run '%s': command not found" % prog) return result - def call_ext_prog(self, prog, timeout=300): + def call_ext_prog(self, prog, timeout=300, runat=None): """Execute a command independantly of the output gathering part of sosreport. """ # pylint: disable-msg = W0612 - return self.get_command_output(prog, timeout) + return self.get_command_output(prog, timeout, runat) def check_ext_prog(self, prog): """Execute a command independently of the output gathering part of @@ -465,9 +465,17 @@ class Plugin(object): return (self.call_ext_prog(prog)['status'] == 0) - def add_cmd_output(self, exe, suggest_filename=None, root_symlink=None, timeout=300): + def add_cmd_output( + self, exe, + suggest_filename=None, + root_symlink=None, + timeout=300, + runat=None + ): """Run a program and collect the output""" - self.collect_cmds.append( (exe, suggest_filename, root_symlink, timeout) ) + self.collect_cmds.append(( + exe, suggest_filename, root_symlink, timeout, runat + )) self.log_debug("added cmd output '%s'" % exe) def get_cmd_output_path(self, name=None, make=True): @@ -515,12 +523,18 @@ class Plugin(object): self.copy_strings.append((content, filename)) self.log_debug("added string '%s' as '%s'" % (content,filename)) - def get_cmd_output_now(self, exe, suggest_filename=None, root_symlink=False, timeout=300): + def get_cmd_output_now( + self, exe, + suggest_filename=None, + root_symlink=False, + timeout=300, + runat=None + ): """Execute a command and save the output to a file for inclusion in the report. """ # pylint: disable-msg = W0612 - result = self.get_command_output(exe, timeout=timeout) + result = self.get_command_output(exe, timeout, runat) if (result['status'] == 127): return None @@ -567,11 +581,11 @@ class Plugin(object): def collect_cmd_output(self): for progs in zip(self.collect_cmds): - prog, suggest_filename, root_symlink, timeout = progs[0] + prog, suggest_filename, root_symlink, timeout, runat = progs[0] self.log_info("collecting output of '%s'" % prog) try: self.get_cmd_output_now(prog, suggest_filename, - root_symlink, timeout) + root_symlink, timeout, runat) except Exception as e: self.log_debug("could not collect output of '%s': %s" % (prog, e)) diff --git a/sos/utilities.py b/sos/utilities.py index e65df349..1bc54879 100644 --- a/sos/utilities.py +++ b/sos/utilities.py @@ -127,9 +127,16 @@ def is_executable(command): candidates = [command] + [os.path.join(p, command) for p in paths] return any(os.access(path, os.X_OK) for path in candidates) -def sos_get_command_output(command, timeout=300): +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) + cmd_env = os.environ # ensure consistent locale for collected command output cmd_env['LC_ALL'] = 'C' @@ -138,7 +145,8 @@ def sos_get_command_output(command, timeout=300): command = "timeout %ds %s" % (timeout, command) p = Popen(command, shell=True, stdout=PIPE, stderr=STDOUT, - bufsize=-1, env = cmd_env, close_fds = True) + bufsize=-1, env = cmd_env, close_fds = True, + preexec_fn=_child_chdir) stdout, stderr = p.communicate() @@ -164,11 +172,11 @@ def import_module(module_fqname, superclasses=None): return modules -def shell_out(cmd): +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)['output'] + return sos_get_command_output(cmd, runat=runat)['output'] class ImporterHelper(object): """Provides a list of modules that can be imported in a package. -- cgit