prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Hardcoded location of the chroot executable
  On Gentoo, chroot is in /usr/bin and not /usr/sbin as ansible assumes.
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `lib/ansible/runner/connection_plugins/chroot.py`
  Content:
  ```
  1 # Based on local.py (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>
  2 # (c) 2013, Maykel Moya <mmoya@speedyrails.com>
  3 #
  4 # This file is part of Ansible
  5 #
  6 # Ansible is free software: you can redistribute it and/or modify
  7 # it under the terms of the GNU General Public License as published by
  8 # the Free Software Foundation, either version 3 of the License, or
  9 # (at your option) any later version.
  10 #
  11 # Ansible is distributed in the hope that it will be useful,
  12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 # GNU General Public License for more details.
  15 #
  16 # You should have received a copy of the GNU General Public License
  17 # along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
  18 
  19 import traceback
  20 import os
  21 import pipes
  22 import shutil
  23 import subprocess
  24 import select
  25 import fcntl
  26 from ansible import errors
  27 from ansible import utils
  28 from ansible.callbacks import vvv
  29 
  30 class Connection(object):
  31     ''' Local chroot based connections '''
  32 
  33     def __init__(self, runner, host, port, *args, **kwargs):
  34         self.chroot = host
  35 
  36         if os.geteuid() != 0:
  37             raise errors.AnsibleError("chroot connection requires running as root")
  38 
  39         # we're running as root on the local system so do some
  40         # trivial checks for ensuring 'host' is actually a chroot'able dir
  41         if not os.path.isdir(self.chroot):
  42             raise errors.AnsibleError("%s is not a directory" % self.chroot)
  43 
  44         chrootsh = os.path.join(self.chroot, 'bin/sh')
  45         if not utils.is_executable(chrootsh):
  46             raise errors.AnsibleError("%s does not look like a chrootable dir (/bin/sh missing)" % self.chroot)
  47 
  48         self.runner = runner
  49         self.host = host
  50         # port is unused, since this is local
  51         self.port = port
  52 
  53     def connect(self, port=None):
  54         ''' connect to the chroot; nothing to do here '''
  55 
  56         vvv("THIS IS A LOCAL CHROOT DIR", host=self.chroot)
  57 
  58         return self
  59 
  60     def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh'):
  61         ''' run a command on the chroot '''
  62 
  63         # We enter chroot as root so sudo stuff can be ignored
  64 
  65         chroot_cmd = '/usr/sbin/chroot'
  66 
  67         if executable:
  68             local_cmd = [chroot_cmd, self.chroot, executable, '-c', cmd]
  69         else:
  70             local_cmd = '%s "%s" %s' % (chroot_cmd, self.chroot, cmd)
  71 
  72         vvv("EXEC %s" % (local_cmd), host=self.chroot)
  73         p = subprocess.Popen(local_cmd, shell=isinstance(local_cmd, basestring),
  74                              cwd=self.runner.basedir,
  75                              stdin=subprocess.PIPE,
  76                              stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  77 
  78         stdout, stderr = p.communicate()
  79         return (p.returncode, '', stdout, stderr)
  80 
  81     def put_file(self, in_path, out_path):
  82         ''' transfer a file from local to chroot '''
  83 
  84         if not out_path.startswith(os.path.sep):
  85             out_path = os.path.join(os.path.sep, out_path)
  86         normpath = os.path.normpath(out_path)
  87         out_path = os.path.join(self.chroot, normpath[1:])
  88 
  89         vvv("PUT %s TO %s" % (in_path, out_path), host=self.chroot)
  90         if not os.path.exists(in_path):
  91             raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path)
  92         try:
  93             shutil.copyfile(in_path, out_path)
  94         except shutil.Error:
  95             traceback.print_exc()
  96             raise errors.AnsibleError("failed to copy: %s and %s are the same" % (in_path, out_path))
  97         except IOError:
  98             traceback.print_exc()
  99             raise errors.AnsibleError("failed to transfer file to %s" % out_path)
  100 
  101     def fetch_file(self, in_path, out_path):
  102         ''' fetch a file from chroot to local '''
  103 
  104         if not in_path.startswith(os.path.sep):
  105             in_path = os.path.join(os.path.sep, in_path)
  106         normpath = os.path.normpath(in_path)
  107         in_path = os.path.join(self.chroot, normpath[1:])
  108 
  109         vvv("FETCH %s TO %s" % (in_path, out_path), host=self.chroot)
  110         if not os.path.exists(in_path):
  111             raise errors.AnsibleFileNotFound("file or module does not exist: %s" % in_path)
  112         try:
  113             shutil.copyfile(in_path, out_path)
  114         except shutil.Error:
  115             traceback.print_exc()
  116             raise errors.AnsibleError("failed to copy: %s and %s are the same" % (in_path, out_path))
  117         except IOError:
  118             traceback.print_exc()
  119             raise errors.AnsibleError("failed to transfer file to %s" % out_path)
  120 
  121     def close(self):
  122         ''' terminate the connection; nothing to do here '''
  123         pass
  124
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/lib/ansible/runner/connection_plugins/chroot.py b/lib/ansible/runner/connection_plugins/chroot.py
  --- a/lib/ansible/runner/connection_plugins/chroot.py
  +++ b/lib/ansible/runner/connection_plugins/chroot.py
  @@ -16,13 +16,11 @@
   # You should have received a copy of the GNU General Public License
   # along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
   
  +import distutils.spawn
   import traceback
   import os
  -import pipes
   import shutil
   import subprocess
  -import select
  -import fcntl
   from ansible import errors
   from ansible import utils
   from ansible.callbacks import vvv
  @@ -45,6 +43,10 @@
           if not utils.is_executable(chrootsh):
               raise errors.AnsibleError("%s does not look like a chrootable dir (/bin/sh missing)" % self.chroot)
   
  +        self.chroot_cmd = distutils.spawn.find_executable('chroot')
  +        if not self.chroot_cmd:
  +            raise errors.AnsibleError("chroot command not found in PATH")
  +
           self.runner = runner
           self.host = host
           # port is unused, since this is local
  @@ -62,12 +64,10 @@
   
           # We enter chroot as root so sudo stuff can be ignored
   
  -        chroot_cmd = '/usr/sbin/chroot'
  -
           if executable:
  -            local_cmd = [chroot_cmd, self.chroot, executable, '-c', cmd]
  +            local_cmd = [self.chroot_cmd, self.chroot, executable, '-c', cmd]
           else:
  -            local_cmd = '%s "%s" %s' % (chroot_cmd, self.chroot, cmd)
  +            local_cmd = '%s "%s" %s' % (self.chroot_cmd, self.chroot, cmd)
   
           vvv("EXEC %s" % (local_cmd), host=self.chroot)
           p = subprocess.Popen(local_cmd, shell=isinstance(local_cmd, basestring),
  
verification_info: {"golden_diff": "diff --git a/lib/ansible/runner/connection_plugins/chroot.py b/lib/ansible/runner/connection_plugins/chroot.py\n--- a/lib/ansible/runner/connection_plugins/chroot.py\n+++ b/lib/ansible/runner/connection_plugins/chroot.py\n@@ -16,13 +16,11 @@\n # You should have received a copy of the GNU General Public License\n # along with Ansible.  If not, see <http://www.gnu.org/licenses/>.\n \n+import distutils.spawn\n import traceback\n import os\n-import pipes\n import shutil\n import subprocess\n-import select\n-import fcntl\n from ansible import errors\n from ansible import utils\n from ansible.callbacks import vvv\n@@ -45,6 +43,10 @@\n         if not utils.is_executable(chrootsh):\n             raise errors.AnsibleError(\"%s does not look like a chrootable dir (/bin/sh missing)\" % self.chroot)\n \n+        self.chroot_cmd = distutils.spawn.find_executable('chroot')\n+        if not self.chroot_cmd:\n+            raise errors.AnsibleError(\"chroot command not found in PATH\")\n+\n         self.runner = runner\n         self.host = host\n         # port is unused, since this is local\n@@ -62,12 +64,10 @@\n \n         # We enter chroot as root so sudo stuff can be ignored\n \n-        chroot_cmd = '/usr/sbin/chroot'\n-\n         if executable:\n-            local_cmd = [chroot_cmd, self.chroot, executable, '-c', cmd]\n+            local_cmd = [self.chroot_cmd, self.chroot, executable, '-c', cmd]\n         else:\n-            local_cmd = '%s \"%s\" %s' % (chroot_cmd, self.chroot, cmd)\n+            local_cmd = '%s \"%s\" %s' % (self.chroot_cmd, self.chroot, cmd)\n \n         vvv(\"EXEC %s\" % (local_cmd), host=self.chroot)\n         p = subprocess.Popen(local_cmd, shell=isinstance(local_cmd, basestring),\n", "issue": "Hardcoded location of the chroot executable\nOn Gentoo, chroot is in /usr/bin and not /usr/sbin as ansible assumes.\n\n", "before_files": [{"content": "# Based on local.py (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>\n# (c) 2013, Maykel Moya <mmoya@speedyrails.com>\n#\n# This file is part of Ansible\n#\n# Ansible is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# Ansible is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.\n\nimport traceback\nimport os\nimport pipes\nimport shutil\nimport subprocess\nimport select\nimport fcntl\nfrom ansible import errors\nfrom ansible import utils\nfrom ansible.callbacks import vvv\n\nclass Connection(object):\n    ''' Local chroot based connections '''\n\n    def __init__(self, runner, host, port, *args, **kwargs):\n        self.chroot = host\n\n        if os.geteuid() != 0:\n            raise errors.AnsibleError(\"chroot connection requires running as root\")\n\n        # we're running as root on the local system so do some\n        # trivial checks for ensuring 'host' is actually a chroot'able dir\n        if not os.path.isdir(self.chroot):\n            raise errors.AnsibleError(\"%s is not a directory\" % self.chroot)\n\n        chrootsh = os.path.join(self.chroot, 'bin/sh')\n        if not utils.is_executable(chrootsh):\n            raise errors.AnsibleError(\"%s does not look like a chrootable dir (/bin/sh missing)\" % self.chroot)\n\n        self.runner = runner\n        self.host = host\n        # port is unused, since this is local\n        self.port = port\n\n    def connect(self, port=None):\n        ''' connect to the chroot; nothing to do here '''\n\n        vvv(\"THIS IS A LOCAL CHROOT DIR\", host=self.chroot)\n\n        return self\n\n    def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh'):\n        ''' run a command on the chroot '''\n\n        # We enter chroot as root so sudo stuff can be ignored\n\n        chroot_cmd = '/usr/sbin/chroot'\n\n        if executable:\n            local_cmd = [chroot_cmd, self.chroot, executable, '-c', cmd]\n        else:\n            local_cmd = '%s \"%s\" %s' % (chroot_cmd, self.chroot, cmd)\n\n        vvv(\"EXEC %s\" % (local_cmd), host=self.chroot)\n        p = subprocess.Popen(local_cmd, shell=isinstance(local_cmd, basestring),\n                             cwd=self.runner.basedir,\n                             stdin=subprocess.PIPE,\n                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n\n        stdout, stderr = p.communicate()\n        return (p.returncode, '', stdout, stderr)\n\n    def put_file(self, in_path, out_path):\n        ''' transfer a file from local to chroot '''\n\n        if not out_path.startswith(os.path.sep):\n            out_path = os.path.join(os.path.sep, out_path)\n        normpath = os.path.normpath(out_path)\n        out_path = os.path.join(self.chroot, normpath[1:])\n\n        vvv(\"PUT %s TO %s\" % (in_path, out_path), host=self.chroot)\n        if not os.path.exists(in_path):\n            raise errors.AnsibleFileNotFound(\"file or module does not exist: %s\" % in_path)\n        try:\n            shutil.copyfile(in_path, out_path)\n        except shutil.Error:\n            traceback.print_exc()\n            raise errors.AnsibleError(\"failed to copy: %s and %s are the same\" % (in_path, out_path))\n        except IOError:\n            traceback.print_exc()\n            raise errors.AnsibleError(\"failed to transfer file to %s\" % out_path)\n\n    def fetch_file(self, in_path, out_path):\n        ''' fetch a file from chroot to local '''\n\n        if not in_path.startswith(os.path.sep):\n            in_path = os.path.join(os.path.sep, in_path)\n        normpath = os.path.normpath(in_path)\n        in_path = os.path.join(self.chroot, normpath[1:])\n\n        vvv(\"FETCH %s TO %s\" % (in_path, out_path), host=self.chroot)\n        if not os.path.exists(in_path):\n            raise errors.AnsibleFileNotFound(\"file or module does not exist: %s\" % in_path)\n        try:\n            shutil.copyfile(in_path, out_path)\n        except shutil.Error:\n            traceback.print_exc()\n            raise errors.AnsibleError(\"failed to copy: %s and %s are the same\" % (in_path, out_path))\n        except IOError:\n            traceback.print_exc()\n            raise errors.AnsibleError(\"failed to transfer file to %s\" % out_path)\n\n    def close(self):\n        ''' terminate the connection; nothing to do here '''\n        pass\n", "path": "lib/ansible/runner/connection_plugins/chroot.py"}], "after_files": [{"content": "# Based on local.py (c) 2012, Michael DeHaan <michael.dehaan@gmail.com>\n# (c) 2013, Maykel Moya <mmoya@speedyrails.com>\n#\n# This file is part of Ansible\n#\n# Ansible is free software: you can redistribute it and/or modify\n# it under the terms of the GNU General Public License as published by\n# the Free Software Foundation, either version 3 of the License, or\n# (at your option) any later version.\n#\n# Ansible is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY; without even the implied warranty of\n# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n# GNU General Public License for more details.\n#\n# You should have received a copy of the GNU General Public License\n# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.\n\nimport distutils.spawn\nimport traceback\nimport os\nimport shutil\nimport subprocess\nfrom ansible import errors\nfrom ansible import utils\nfrom ansible.callbacks import vvv\n\nclass Connection(object):\n    ''' Local chroot based connections '''\n\n    def __init__(self, runner, host, port, *args, **kwargs):\n        self.chroot = host\n\n        if os.geteuid() != 0:\n            raise errors.AnsibleError(\"chroot connection requires running as root\")\n\n        # we're running as root on the local system so do some\n        # trivial checks for ensuring 'host' is actually a chroot'able dir\n        if not os.path.isdir(self.chroot):\n            raise errors.AnsibleError(\"%s is not a directory\" % self.chroot)\n\n        chrootsh = os.path.join(self.chroot, 'bin/sh')\n        if not utils.is_executable(chrootsh):\n            raise errors.AnsibleError(\"%s does not look like a chrootable dir (/bin/sh missing)\" % self.chroot)\n\n        self.chroot_cmd = distutils.spawn.find_executable('chroot')\n        if not self.chroot_cmd:\n            raise errors.AnsibleError(\"chroot command not found in PATH\")\n\n        self.runner = runner\n        self.host = host\n        # port is unused, since this is local\n        self.port = port\n\n    def connect(self, port=None):\n        ''' connect to the chroot; nothing to do here '''\n\n        vvv(\"THIS IS A LOCAL CHROOT DIR\", host=self.chroot)\n\n        return self\n\n    def exec_command(self, cmd, tmp_path, sudo_user, sudoable=False, executable='/bin/sh'):\n        ''' run a command on the chroot '''\n\n        # We enter chroot as root so sudo stuff can be ignored\n\n        if executable:\n            local_cmd = [self.chroot_cmd, self.chroot, executable, '-c', cmd]\n        else:\n            local_cmd = '%s \"%s\" %s' % (self.chroot_cmd, self.chroot, cmd)\n\n        vvv(\"EXEC %s\" % (local_cmd), host=self.chroot)\n        p = subprocess.Popen(local_cmd, shell=isinstance(local_cmd, basestring),\n                             cwd=self.runner.basedir,\n                             stdin=subprocess.PIPE,\n                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n\n        stdout, stderr = p.communicate()\n        return (p.returncode, '', stdout, stderr)\n\n    def put_file(self, in_path, out_path):\n        ''' transfer a file from local to chroot '''\n\n        if not out_path.startswith(os.path.sep):\n            out_path = os.path.join(os.path.sep, out_path)\n        normpath = os.path.normpath(out_path)\n        out_path = os.path.join(self.chroot, normpath[1:])\n\n        vvv(\"PUT %s TO %s\" % (in_path, out_path), host=self.chroot)\n        if not os.path.exists(in_path):\n            raise errors.AnsibleFileNotFound(\"file or module does not exist: %s\" % in_path)\n        try:\n            shutil.copyfile(in_path, out_path)\n        except shutil.Error:\n            traceback.print_exc()\n            raise errors.AnsibleError(\"failed to copy: %s and %s are the same\" % (in_path, out_path))\n        except IOError:\n            traceback.print_exc()\n            raise errors.AnsibleError(\"failed to transfer file to %s\" % out_path)\n\n    def fetch_file(self, in_path, out_path):\n        ''' fetch a file from chroot to local '''\n\n        if not in_path.startswith(os.path.sep):\n            in_path = os.path.join(os.path.sep, in_path)\n        normpath = os.path.normpath(in_path)\n        in_path = os.path.join(self.chroot, normpath[1:])\n\n        vvv(\"FETCH %s TO %s\" % (in_path, out_path), host=self.chroot)\n        if not os.path.exists(in_path):\n            raise errors.AnsibleFileNotFound(\"file or module does not exist: %s\" % in_path)\n        try:\n            shutil.copyfile(in_path, out_path)\n        except shutil.Error:\n            traceback.print_exc()\n            raise errors.AnsibleError(\"failed to copy: %s and %s are the same\" % (in_path, out_path))\n        except IOError:\n            traceback.print_exc()\n            raise errors.AnsibleError(\"failed to transfer file to %s\" % out_path)\n\n    def close(self):\n        ''' terminate the connection; nothing to do here '''\n        pass\n", "path": "lib/ansible/runner/connection_plugins/chroot.py"}]}