# Buggy code
def _run(self, cmd, in_data, sudoable=True, checkrc=True):
    """
    Starts the command and communicates with it until it ends.
    """

    display_cmd = list(map(shlex_quote, map(to_text, cmd)))
    display.vvv("SSH: EXEC {0}".format(" ".join(display_cmd)), host=self.host)

    # Start the given command. If we don't need to pipeline data, we can try
    # to use a pseudo-tty (ssh will have been invoked with -tt). If we are
    # pipelining data, or can't create a pty, we fall back to using plain
    # old pipes.

    p = None

    if isinstance(cmd, (text_type, binary_type)):
        cmd = to_bytes(cmd)
    else:
        cmd = list(map(to_bytes, cmd))

    if not in_data:
        try:
            # Make sure stdin is a proper pty to avoid tcgetattr errors
            master, slave = pty.openpty()
            if PY3 and self._play_context.password:
                p = subprocess.Popen(
                    cmd,
                    stdin=slave,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE,
                    pass_fds=self.sshpass_pipe,
                )
            else:
                p = subprocess.Popen(
                    cmd, stdin=slave, stdout=subprocess.PIPE, stderr=subprocess.PIPE
                )
            stdin = os.fdopen(master, "wb", 0)
            os.close(slave)
        except (OSError, IOError):
            p = None

    if not p:
        if PY3 and self._play_context.password:
            p = subprocess.Popen(
                cmd,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                pass_fds=self.sshpass_pipe,
            )
        else:
            p = subprocess.Popen(
                cmd,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
            )
        stdin = p.stdin

    # If we are using SSH password authentication, write the password into
    # the pipe we opened in _build_command.

    if self._play_context.password:
        os.close(self.sshpass_pipe[0])
        try:
            os.write(
                self.sshpass_pipe[1], to_bytes(self._play_context.password) + b"\n"
            )
        except OSError as e:
            # Ignore broken pipe errors if the sshpass process has exited.
            if e.errno != errno.EPIPE or p.poll() is None:
                raise
        os.close(self.sshpass_pipe[1])

    #
    # SSH state machine
    #

    # Now we read and accumulate output from the running process until it
    # exits. Depending on the circumstances, we may also need to write an
    # escalation password and/or pipelined input to the process.

    states = [
        "awaiting_prompt",
        "awaiting_escalation",
        "ready_to_send",
        "awaiting_exit",
    ]

    # Are we requesting privilege escalation? Right now, we may be invoked
    # to execute sftp/scp with sudoable=True, but we can request escalation
    # only when using ssh. Otherwise we can send initial data straightaway.

    state = states.index("ready_to_send")
    if b"ssh" in cmd:
        if self._play_context.prompt:
            # We're requesting escalation with a password, so we have to
            # wait for a password prompt.
            state = states.index("awaiting_prompt")
            display.debug(
                "Initial state: %s: %s" % (states[state], self._play_context.prompt)
            )
        elif self._play_context.become and self._play_context.success_key:
            # We're requesting escalation without a password, so we have to
            # detect success/failure before sending any initial data.
            state = states.index("awaiting_escalation")
            display.debug(
                "Initial state: %s: %s"
                % (states[state], self._play_context.success_key)
            )

    # We store accumulated stdout and stderr output from the process here,
    # but strip any privilege escalation prompt/confirmation lines first.
    # Output is accumulated into tmp_*, complete lines are extracted into
    # an array, then checked and removed or copied to stdout or stderr. We
    # set any flags based on examining the output in self._flags.

    b_stdout = b_stderr = b""
    b_tmp_stdout = b_tmp_stderr = b""

    self._flags = dict(
        become_prompt=False,
        become_success=False,
        become_error=False,
        become_nopasswd_error=False,
    )

    # select timeout should be longer than the connect timeout, otherwise
    # they will race each other when we can't connect, and the connect
    # timeout usually fails
    timeout = 2 + self._play_context.timeout
    rpipes = [p.stdout, p.stderr]
    for fd in rpipes:
        fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)

    # If we can send initial data without waiting for anything, we do so
    # before we call select.

    if states[state] == "ready_to_send" and in_data:
        self._send_initial_data(stdin, in_data)
        state += 1

    while True:
        rfd, wfd, efd = select.select(rpipes, [], [], timeout)

        # We pay attention to timeouts only while negotiating a prompt.

        if not rfd:
            if state <= states.index("awaiting_escalation"):
                # If the process has already exited, then it's not really a
                # timeout; we'll let the normal error handling deal with it.
                if p.poll() is not None:
                    break
                self._terminate_process(p)
                raise AnsibleError(
                    "Timeout (%ds) waiting for privilege escalation prompt: %s"
                    % (timeout, to_native(b_stdout))
                )

        # Read whatever output is available on stdout and stderr, and stop
        # listening to the pipe if it's been closed.

        if p.stdout in rfd:
            b_chunk = p.stdout.read()
            if b_chunk == b"":
                rpipes.remove(p.stdout)
                # When ssh has ControlMaster (+ControlPath/Persist) enabled, the
                # first connection goes into the background and we never see EOF
                # on stderr. If we see EOF on stdout, lower the select timeout
                # to reduce the time wasted selecting on stderr if we observe
                # that the process has not yet existed after this EOF. Otherwise
                # we may spend a long timeout period waiting for an EOF that is
                # not going to arrive until the persisted connection closes.
                timeout = 1
            b_tmp_stdout += b_chunk
            display.debug(
                "stdout chunk (state=%s):\n>>>%s<<<\n" % (state, to_text(b_chunk))
            )

        if p.stderr in rfd:
            b_chunk = p.stderr.read()
            if b_chunk == b"":
                rpipes.remove(p.stderr)
            b_tmp_stderr += b_chunk
            display.debug(
                "stderr chunk (state=%s):\n>>>%s<<<\n" % (state, to_text(b_chunk))
            )

        # We examine the output line-by-line until we have negotiated any
        # privilege escalation prompt and subsequent success/error message.
        # Afterwards, we can accumulate output without looking at it.

        if state < states.index("ready_to_send"):
            if b_tmp_stdout:
                b_output, b_unprocessed = self._examine_output(
                    "stdout", states[state], b_tmp_stdout, sudoable
                )
                b_stdout += b_output
                b_tmp_stdout = b_unprocessed

            if b_tmp_stderr:
                b_output, b_unprocessed = self._examine_output(
                    "stderr", states[state], b_tmp_stderr, sudoable
                )
                b_stderr += b_output
                b_tmp_stderr = b_unprocessed
        else:
            b_stdout += b_tmp_stdout
            b_stderr += b_tmp_stderr
            b_tmp_stdout = b_tmp_stderr = b""

        # If we see a privilege escalation prompt, we send the password.
        # (If we're expecting a prompt but the escalation succeeds, we
        # didn't need the password and can carry on regardless.)

        if states[state] == "awaiting_prompt":
            if self._flags["become_prompt"]:
                display.debug("Sending become_pass in response to prompt")
                stdin.write(to_bytes(self._play_context.become_pass) + b"\n")
                self._flags["become_prompt"] = False
                state += 1
            elif self._flags["become_success"]:
                state += 1

        # We've requested escalation (with or without a password), now we
        # wait for an error message or a successful escalation.

        if states[state] == "awaiting_escalation":
            if self._flags["become_success"]:
                display.debug("Escalation succeeded")
                self._flags["become_success"] = False
                state += 1
            elif self._flags["become_error"]:
                display.debug("Escalation failed")
                self._terminate_process(p)
                self._flags["become_error"] = False
                raise AnsibleError(
                    "Incorrect %s password" % self._play_context.become_method
                )
            elif self._flags["become_nopasswd_error"]:
                display.debug("Escalation requires password")
                self._terminate_process(p)
                self._flags["become_nopasswd_error"] = False
                raise AnsibleError(
                    "Missing %s password" % self._play_context.become_method
                )
            elif self._flags["become_prompt"]:
                # This shouldn't happen, because we should see the "Sorry,
                # try again" message first.
                display.debug("Escalation prompt repeated")
                self._terminate_process(p)
                self._flags["become_prompt"] = False
                raise AnsibleError(
                    "Incorrect %s password" % self._play_context.become_method
                )

        # Once we're sure that the privilege escalation prompt, if any, has
        # been dealt with, we can send any initial data and start waiting
        # for output.

        if states[state] == "ready_to_send":
            if in_data:
                self._send_initial_data(stdin, in_data)
            state += 1

        # Now we're awaiting_exit: has the child process exited? If it has,
        # and we've read all available output from it, we're done.

        if p.poll() is not None:
            if not rpipes or not rfd:
                break
            # We should not see further writes to the stdout/stderr file
            # descriptors after the process has closed, set the select
            # timeout to gather any last writes we may have missed.
            timeout = 0
            continue

        # If the process has not yet exited, but we've already read EOF from
        # its stdout and stderr (and thus removed both from rpipes), we can
        # just wait for it to exit.

        elif not rpipes:
            p.wait()
            break

        # Otherwise there may still be outstanding data to read.

    # close stdin after process is terminated and stdout/stderr are read
    # completely (see also issue #848)
    stdin.close()

    if C.HOST_KEY_CHECKING:
        if cmd[0] == b"sshpass" and p.returncode == 6:
            raise AnsibleError(
                "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host's fingerprint to your known_hosts file to manage this host."
            )

    controlpersisterror = (
        b"Bad configuration option: ControlPersist" in b_stderr
        or b"unknown configuration option: ControlPersist" in b_stderr
    )
    if p.returncode != 0 and controlpersisterror:
        raise AnsibleError(
            'using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ssh_args in [ssh_connection] section of the config file) before running again'
        )

    if p.returncode == 255 and in_data and checkrc:
        raise AnsibleConnectionFailure(
            'SSH Error: data could not be sent to remote host "%s". Make sure this host can be reached over ssh'
            % self.host
        )

    return (p.returncode, b_stdout, b_stderr)


# Traceback (ValueError)
2016-01-26 16:41:22,990 p=8627 u=root |  ^[[0;31mAn exception occurred during task execution. The full traceback is:
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/ansible/executor/process/worker.py", line 114, in run
self._shared_loader_obj,
File "/usr/local/lib/python2.7/dist-packages/ansible/executor/task_executor.py", line 91, in run
item_results = self._run_loop(items)
File "/usr/local/lib/python2.7/dist-packages/ansible/executor/task_executor.py", line 241, in _run_loop
res = self._execute(variables=task_vars)
File "/usr/local/lib/python2.7/dist-packages/ansible/executor/task_executor.py", line 401, in _execute
result = self._handler.run(task_vars=variables)
File "/usr/local/lib/python2.7/dist-packages/ansible/plugins/action/normal.py", line 33, in run
results = merge_hash(results, self._execute_module(tmp=tmp, task_vars=task_vars))
File "/usr/local/lib/python2.7/dist-packages/ansible/plugins/action/__init__.py", line 395, in _execute_module
tmp = self._make_tmp_path()
File "/usr/local/lib/python2.7/dist-packages/ansible/plugins/action/__init__.py", line 210, in _make_tmp_path
result = self._low_level_execute_command(cmd, sudoable=False)
File "/usr/local/lib/python2.7/dist-packages/ansible/plugins/action/__init__.py", line 510, in _low_level_execute_command
rc, stdout, stderr = self._connection.exec_command(cmd, in_data=in_data, sudoable=sudoable)
File "/usr/local/lib/python2.7/dist-packages/ansible/plugins/connection/ssh.py", line 600, in exec_command
return_tuple = self._exec_command(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/ansible/plugins/connection/ssh.py", line 577, in _exec_command
(returncode, stdout, stderr) = self._run(cmd, in_data, sudoable=sudoable)
File "/usr/local/lib/python2.7/dist-packages/ansible/plugins/connection/ssh.py", line 417, in _run
rfd, wfd, efd = select.select(rpipes, [], [], timeout)
ValueError: filedescriptor out of range in select()

# Fixed code
def _run(self, cmd, in_data, sudoable=True, checkrc=True):
    """
    Starts the command and communicates with it until it ends.
    """

    display_cmd = list(map(shlex_quote, map(to_text, cmd)))
    display.vvv("SSH: EXEC {0}".format(" ".join(display_cmd)), host=self.host)

    # Start the given command. If we don't need to pipeline data, we can try
    # to use a pseudo-tty (ssh will have been invoked with -tt). If we are
    # pipelining data, or can't create a pty, we fall back to using plain
    # old pipes.

    p = None

    if isinstance(cmd, (text_type, binary_type)):
        cmd = to_bytes(cmd)
    else:
        cmd = list(map(to_bytes, cmd))

    if not in_data:
        try:
            # Make sure stdin is a proper pty to avoid tcgetattr errors
            master, slave = pty.openpty()
            if PY3 and self._play_context.password:
                p = subprocess.Popen(
                    cmd,
                    stdin=slave,
                    stdout=subprocess.PIPE,
                    stderr=subprocess.PIPE,
                    pass_fds=self.sshpass_pipe,
                )
            else:
                p = subprocess.Popen(
                    cmd, stdin=slave, stdout=subprocess.PIPE, stderr=subprocess.PIPE
                )
            stdin = os.fdopen(master, "wb", 0)
            os.close(slave)
        except (OSError, IOError):
            p = None

    if not p:
        if PY3 and self._play_context.password:
            p = subprocess.Popen(
                cmd,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                pass_fds=self.sshpass_pipe,
            )
        else:
            p = subprocess.Popen(
                cmd,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
            )
        stdin = p.stdin

    # If we are using SSH password authentication, write the password into
    # the pipe we opened in _build_command.

    if self._play_context.password:
        os.close(self.sshpass_pipe[0])
        try:
            os.write(
                self.sshpass_pipe[1], to_bytes(self._play_context.password) + b"\n"
            )
        except OSError as e:
            # Ignore broken pipe errors if the sshpass process has exited.
            if e.errno != errno.EPIPE or p.poll() is None:
                raise
        os.close(self.sshpass_pipe[1])

    #
    # SSH state machine
    #

    # Now we read and accumulate output from the running process until it
    # exits. Depending on the circumstances, we may also need to write an
    # escalation password and/or pipelined input to the process.

    states = [
        "awaiting_prompt",
        "awaiting_escalation",
        "ready_to_send",
        "awaiting_exit",
    ]

    # Are we requesting privilege escalation? Right now, we may be invoked
    # to execute sftp/scp with sudoable=True, but we can request escalation
    # only when using ssh. Otherwise we can send initial data straightaway.

    state = states.index("ready_to_send")
    if b"ssh" in cmd:
        if self._play_context.prompt:
            # We're requesting escalation with a password, so we have to
            # wait for a password prompt.
            state = states.index("awaiting_prompt")
            display.debug(
                "Initial state: %s: %s" % (states[state], self._play_context.prompt)
            )
        elif self._play_context.become and self._play_context.success_key:
            # We're requesting escalation without a password, so we have to
            # detect success/failure before sending any initial data.
            state = states.index("awaiting_escalation")
            display.debug(
                "Initial state: %s: %s"
                % (states[state], self._play_context.success_key)
            )

    # We store accumulated stdout and stderr output from the process here,
    # but strip any privilege escalation prompt/confirmation lines first.
    # Output is accumulated into tmp_*, complete lines are extracted into
    # an array, then checked and removed or copied to stdout or stderr. We
    # set any flags based on examining the output in self._flags.

    b_stdout = b_stderr = b""
    b_tmp_stdout = b_tmp_stderr = b""

    self._flags = dict(
        become_prompt=False,
        become_success=False,
        become_error=False,
        become_nopasswd_error=False,
    )

    # select timeout should be longer than the connect timeout, otherwise
    # they will race each other when we can't connect, and the connect
    # timeout usually fails
    timeout = 2 + self._play_context.timeout
    for fd in (p.stdout, p.stderr):
        fcntl.fcntl(fd, fcntl.F_SETFL, fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK)

    ### TODO: bcoca would like to use SelectSelector() when open
    # filehandles is low, then switch to more efficient ones when higher.
    # select is faster when filehandles is low.
    selector = selectors.DefaultSelector()
    selector.register(p.stdout, selectors.EVENT_READ)
    selector.register(p.stderr, selectors.EVENT_READ)

    # If we can send initial data without waiting for anything, we do so
    # before we start polling
    if states[state] == "ready_to_send" and in_data:
        self._send_initial_data(stdin, in_data)
        state += 1

    try:
        while True:
            events = selector.select(timeout)

            # We pay attention to timeouts only while negotiating a prompt.

            if not events:
                # We timed out
                if state <= states.index("awaiting_escalation"):
                    # If the process has already exited, then it's not really a
                    # timeout; we'll let the normal error handling deal with it.
                    if p.poll() is not None:
                        break
                    self._terminate_process(p)
                    raise AnsibleError(
                        "Timeout (%ds) waiting for privilege escalation prompt: %s"
                        % (timeout, to_native(b_stdout))
                    )

            # Read whatever output is available on stdout and stderr, and stop
            # listening to the pipe if it's been closed.

            for key, event in events:
                if key.fileobj == p.stdout:
                    b_chunk = p.stdout.read()
                    if b_chunk == b"":
                        # stdout has been closed, stop watching it
                        selector.unregister(p.stdout)
                        # When ssh has ControlMaster (+ControlPath/Persist) enabled, the
                        # first connection goes into the background and we never see EOF
                        # on stderr. If we see EOF on stdout, lower the select timeout
                        # to reduce the time wasted selecting on stderr if we observe
                        # that the process has not yet existed after this EOF. Otherwise
                        # we may spend a long timeout period waiting for an EOF that is
                        # not going to arrive until the persisted connection closes.
                        timeout = 1
                    b_tmp_stdout += b_chunk
                    display.debug(
                        "stdout chunk (state=%s):\n>>>%s<<<\n"
                        % (state, to_text(b_chunk))
                    )
                elif key.fileobj == p.stderr:
                    b_chunk = p.stderr.read()
                    if b_chunk == b"":
                        # stderr has been closed, stop watching it
                        selector.unregister(p.stderr)
                    b_tmp_stderr += b_chunk
                    display.debug(
                        "stderr chunk (state=%s):\n>>>%s<<<\n"
                        % (state, to_text(b_chunk))
                    )

            # We examine the output line-by-line until we have negotiated any
            # privilege escalation prompt and subsequent success/error message.
            # Afterwards, we can accumulate output without looking at it.

            if state < states.index("ready_to_send"):
                if b_tmp_stdout:
                    b_output, b_unprocessed = self._examine_output(
                        "stdout", states[state], b_tmp_stdout, sudoable
                    )
                    b_stdout += b_output
                    b_tmp_stdout = b_unprocessed

                if b_tmp_stderr:
                    b_output, b_unprocessed = self._examine_output(
                        "stderr", states[state], b_tmp_stderr, sudoable
                    )
                    b_stderr += b_output
                    b_tmp_stderr = b_unprocessed
            else:
                b_stdout += b_tmp_stdout
                b_stderr += b_tmp_stderr
                b_tmp_stdout = b_tmp_stderr = b""

            # If we see a privilege escalation prompt, we send the password.
            # (If we're expecting a prompt but the escalation succeeds, we
            # didn't need the password and can carry on regardless.)

            if states[state] == "awaiting_prompt":
                if self._flags["become_prompt"]:
                    display.debug("Sending become_pass in response to prompt")
                    stdin.write(to_bytes(self._play_context.become_pass) + b"\n")
                    self._flags["become_prompt"] = False
                    state += 1
                elif self._flags["become_success"]:
                    state += 1

            # We've requested escalation (with or without a password), now we
            # wait for an error message or a successful escalation.

            if states[state] == "awaiting_escalation":
                if self._flags["become_success"]:
                    display.debug("Escalation succeeded")
                    self._flags["become_success"] = False
                    state += 1
                elif self._flags["become_error"]:
                    display.debug("Escalation failed")
                    self._terminate_process(p)
                    self._flags["become_error"] = False
                    raise AnsibleError(
                        "Incorrect %s password" % self._play_context.become_method
                    )
                elif self._flags["become_nopasswd_error"]:
                    display.debug("Escalation requires password")
                    self._terminate_process(p)
                    self._flags["become_nopasswd_error"] = False
                    raise AnsibleError(
                        "Missing %s password" % self._play_context.become_method
                    )
                elif self._flags["become_prompt"]:
                    # This shouldn't happen, because we should see the "Sorry,
                    # try again" message first.
                    display.debug("Escalation prompt repeated")
                    self._terminate_process(p)
                    self._flags["become_prompt"] = False
                    raise AnsibleError(
                        "Incorrect %s password" % self._play_context.become_method
                    )

            # Once we're sure that the privilege escalation prompt, if any, has
            # been dealt with, we can send any initial data and start waiting
            # for output.

            if states[state] == "ready_to_send":
                if in_data:
                    self._send_initial_data(stdin, in_data)
                state += 1

            # Now we're awaiting_exit: has the child process exited? If it has,
            # and we've read all available output from it, we're done.

            if p.poll() is not None:
                if not selector.get_map() or not events:
                    break
                # We should not see further writes to the stdout/stderr file
                # descriptors after the process has closed, set the select
                # timeout to gather any last writes we may have missed.
                timeout = 0
                continue

            # If the process has not yet exited, but we've already read EOF from
            # its stdout and stderr (and thus no longer watching any file
            # descriptors), we can just wait for it to exit.

            elif not selector.get_map():
                p.wait()
                break

            # Otherwise there may still be outstanding data to read.
    finally:
        selector.close()
        # close stdin after process is terminated and stdout/stderr are read
        # completely (see also issue #848)
        stdin.close()

    if C.HOST_KEY_CHECKING:
        if cmd[0] == b"sshpass" and p.returncode == 6:
            raise AnsibleError(
                "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this.  Please add this host's fingerprint to your known_hosts file to manage this host."
            )

    controlpersisterror = (
        b"Bad configuration option: ControlPersist" in b_stderr
        or b"unknown configuration option: ControlPersist" in b_stderr
    )
    if p.returncode != 0 and controlpersisterror:
        raise AnsibleError(
            'using -c ssh on certain older ssh versions may not support ControlPersist, set ANSIBLE_SSH_ARGS="" (or ssh_args in [ssh_connection] section of the config file) before running again'
        )

    if p.returncode == 255 and in_data and checkrc:
        raise AnsibleConnectionFailure(
            'SSH Error: data could not be sent to remote host "%s". Make sure this host can be reached over ssh'
            % self.host
        )

    return (p.returncode, b_stdout, b_stderr)