Example #1
0
def do_export_vars(command):
    """
    Usage: :export_vars
    Export some environment variables on enabled remote shells.
    POLYSH_NR_SHELLS is the total number of enabled shells. POLYSH_RANK uniquely
    identifies each shell with a number between 0 and POLYSH_NR_SHELLS - 1.
    POLYSH_NAME is the hostname as specified on the command line and
    POLYSH_DISPLAY_NAME the hostname as displayed by :list (most of the time the
    same as POLYSH_NAME).
    """
    rank = 0
    for shell in dispatchers.all_instances():
        if shell.enabled:
            environment_variables = {
                'POLYSH_RANK': rank,
                'POLYSH_NAME': shell.hostname,
                'POLYSH_DISPLAY_NAME': shell.display_name,
            }
            for name, value in environment_variables.iteritems():
                value = pipes.quote(str(value))
                shell.dispatch_command('export %s=%s\n' % (name, value))
            rank += 1

    for shell in dispatchers.all_instances():
        if shell.enabled:
            shell.dispatch_command('export POLYSH_NR_SHELLS=%d\n' % rank)
Example #2
0
def do_export_vars(command):
    """
    Usage: :export_vars
    Export some environment variables on enabled remote shells.
    POLYSH_NR_SHELLS is the total number of enabled shells. POLYSH_RANK uniquely
    identifies each shell with a number between 0 and POLYSH_NR_SHELLS - 1.
    POLYSH_NAME is the hostname as specified on the command line and
    POLYSH_DISPLAY_NAME the hostname as displayed by :list (most of the time the
    same as POLYSH_NAME).
    """
    rank = 0
    for shell in dispatchers.all_instances():
        if shell.enabled:
            environment_variables = {
                'POLYSH_RANK': rank,
                'POLYSH_NAME': shell.hostname,
                'POLYSH_DISPLAY_NAME': shell.display_name,
            }
            for name, value in environment_variables.iteritems():
                value = pipes.quote(str(value))
                shell.dispatch_command('export %s=%s\n' % (name, value))
            rank += 1

    for shell in dispatchers.all_instances():
        if shell.enabled:
            shell.dispatch_command('export POLYSH_NR_SHELLS=%d\n' % rank)
Example #3
0
def upload(local_path):
    peers = [i for i in dispatchers.all_instances() if i.enabled]
    if not peers:
        console_output('No other remote shell to replicate files to\n')
        return

    if len(peers) == 1:
        # We wouldn't be able to show the progress indicator with only one
        # destination. We need one remote connection in blocking mode to send
        # the base64 data to. We also need one remote connection in non blocking
        # mode for polysh to display the progress indicator via the main select
        # loop.
        console_output('Uploading to only one remote shell is not supported, '
                       'use scp instead\n')
        return

    def should_print_bw(node, already_chosen=[False]):
        if not node.children and not already_chosen[0]:
            already_chosen[0] = True
            return True
        return False

    tree = file_transfer_tree_node(None,
                                   peers[0],
                                   peers[1:],
                                   0,
                                   should_print_bw,
                                   path=local_path,
                                   is_upload=True)
def complete_shells(line, text, predicate=lambda i: True):
    """Return the shell names to include in the completion"""
    res = [i.display_name + ' ' for i in dispatchers.all_instances() if \
                i.display_name.startswith(text) and \
                predicate(i) and \
                ' ' + i.display_name + ' ' not in line]
    return res
Example #5
0
def complete_shells(line, text, predicate=lambda i: True):
    """Return the shell names to include in the completion"""
    res = [
        i.display_name + ' ' for i in dispatchers.all_instances()
        if i.display_name.startswith(text) and predicate(i) and ' ' +
        i.display_name + ' ' not in line
    ]
    return res
Example #6
0
def kill_all():
    """When polysh quits, we kill all the remote shells we started"""
    for i in dispatchers.all_instances():
        try:
            os.kill(-i.pid, signal.SIGKILL)
        except OSError:
            # The process was already dead, no problem
            pass
Example #7
0
def kill_all():
    """When polysh quits, we kill all the remote shells we started"""
    for i in dispatchers.all_instances():
        try:
            os.kill(-i.pid, signal.SIGKILL)
        except OSError:
            # The process was already dead, no problem
            pass
Example #8
0
def do_export_vars(command: str) -> None:
    rank = 0
    for shell in dispatchers.all_instances():
        if shell.enabled:
            environment_variables = {
                'POLYSH_RANK': str(rank),
                'POLYSH_NAME': shell.hostname,
                'POLYSH_DISPLAY_NAME': shell.display_name,
            }
            for name, value in environment_variables.items():
                shell.dispatch_command('export {}={}\n'.format(
                    name, shlex.quote(value)).encode())
            rank += 1

    for shell in dispatchers.all_instances():
        if shell.enabled:
            shell.dispatch_command(
                'export POLYSH_NR_SHELLS={:d}\n'.format(rank).encode())
Example #9
0
def do_rename(command):
    """
    Usage: :rename [NEW_NAME]
    Rename all enabled remote shells with the argument.
    The argument will be shell expanded on the remote processes. With no
    argument, the original hostname will be restored as the displayed name.
    """
    for i in dispatchers.all_instances():
        if i.enabled:
            i.rename(command)
Example #10
0
def do_rename(command):
    """
    Usage: :rename [NEW_NAME]
    Rename all enabled remote shells with the argument.
    The argument will be shell expanded on the remote processes. With no
    argument, the original hostname will be restored as the displayed name.
    """
    for i in dispatchers.all_instances():
        if i.enabled:
            i.rename(command)
def selected_shells(command):
    """Iterator over the shells with names matching the patterns.
    An empty patterns matches all the shells"""
    if not command or command == '*':
        for i in dispatchers.all_instances():
            yield i
        return
    selected = set()
    instance_found = False
    for pattern in command.split():
        found = False
        for expanded_pattern in expand_syntax(pattern):
            for i in dispatchers.all_instances():
                instance_found = True
                if fnmatch(i.display_name, expanded_pattern):
                    found = True
                    if i not in selected:
                        selected.add(i)
                        yield i
        if instance_found and not found:
            console_output('%s not found\n' % pattern)
Example #12
0
def selected_shells(command):
    """Iterator over the shells with names matching the patterns.
    An empty patterns matches all the shells"""
    if not command or command == '*':
        for i in dispatchers.all_instances():
            yield i
        return
    selected = set()
    instance_found = False
    for pattern in command.split():
        found = False
        for expanded_pattern in expand_syntax(pattern):
            for i in dispatchers.all_instances():
                instance_found = True
                if fnmatch(i.display_name, expanded_pattern):
                    found = True
                    if i not in selected:
                        selected.add(i)
                        yield i
        if instance_found and not found:
            console_output('{} not found\n'.format(pattern).encode())
Example #13
0
def do_hide_password(command: str) -> None:
    warned = False
    for i in dispatchers.all_instances():
        if i.enabled and i.debug:
            i.debug = False
            if not warned:
                console_output(b'Debugging disabled to avoid displaying '
                               b'passwords\n')
                warned = True
    stdin.set_echo(False)

    if remote_dispatcher.options.log_file:
        console_output(b'Logging disabled to avoid writing passwords\n')
        remote_dispatcher.options.log_file = None
Example #14
0
def selected_shells(
        command: str) -> Iterator[remote_dispatcher.RemoteDispatcher]:
    """Iterator over the shells with names matching the patterns.
    An empty patterns matches all the shells"""
    if not command or command == '*':
        for i in dispatchers.all_instances():
            yield i
        return
    selected = set()  # type: Set[remote_dispatcher.RemoteDispatcher]
    instance_found = False
    for pattern in command.split():
        found = False
        for expanded_pattern in expand_syntax(pattern):
            for i in dispatchers.all_instances():
                instance_found = True
                if (fnmatch(i.display_name, expanded_pattern) or fnmatch(
                        str(i.last_printed_line), expanded_pattern)):
                    found = True
                    if i not in selected:
                        selected.add(i)
                        yield i
        if instance_found and not found:
            console_output('{} not found\n'.format(pattern).encode())
Example #15
0
def process_input_buffer() -> None:
    """Send the content of the input buffer to all remote processes, this must
    be called in the main thread"""
    from polysh.control_commands_helpers import handle_control_command
    data = the_stdin_thread.input_buffer.get()
    remote_dispatcher.log(b'> ' + data)

    if data.startswith(b':'):
        try:
            handle_control_command(data[1:-1].decode())
        except UnicodeDecodeError as e:
            console_output(b'Could not decode command.')
        return

    if data.startswith(b'!'):
        try:
            retcode = subprocess.call(data[1:], shell=True)
        except OSError as e:
            if e.errno == errno.EINTR:
                console_output(b'Child was interrupted\n')
                retcode = 0
            else:
                raise
        if retcode > 128 and retcode <= 192:
            retcode = 128 - retcode
        if retcode > 0:
            console_output('Child returned {:d}\n'.format(retcode).encode())
        elif retcode < 0:
            console_output('Child was terminated by signal {:d}\n'.format(
                -retcode).encode())
        return

    for r in dispatchers.all_instances():
        try:
            r.dispatch_command(data)
        except asyncore.ExitNow as e:
            raise e
        except Exception as msg:
            raise msg
            console_output('{} for {}, disconnecting\n'.format(
                str(msg), r.display_name).encode())
            r.disconnect()
        else:
            if r.enabled and r.state is remote_dispatcher.STATE_IDLE:
                r.change_state(remote_dispatcher.STATE_RUNNING)
Example #16
0
def loop(interactive):
    histfile = os.path.expanduser("~/.polysh_history")
    init_history(histfile)
    next_signal = None
    last_status = None
    while True:
        try:
            if next_signal:
                current_signal = next_signal
                next_signal = None
                sig2chr = {signal.SIGINT: 'C', signal.SIGTSTP: 'Z'}
                ctrl = sig2chr[current_signal]
                remote_dispatcher.log('> ^{}\n'.format(ctrl).encode())
                control_commands.do_send_ctrl(ctrl)
                console_output(b'')
                stdin.the_stdin_thread.prepend_text = None
            while dispatchers.count_awaited_processes()[0] and \
                    remote_dispatcher.main_loop_iteration(timeout=0.2):
                pass
            # Now it's quiet
            for r in dispatchers.all_instances():
                r.print_unfinished_line()
            current_status = dispatchers.count_awaited_processes()
            if current_status != last_status:
                console_output(b'')
            if remote_dispatcher.options.interactive:
                stdin.the_stdin_thread.want_raw_input()
            last_status = current_status
            if dispatchers.all_terminated():
                # Clear the prompt
                console_output(b'')
                raise asyncore.ExitNow(remote_dispatcher.options.exit_code)
            if not next_signal:
                # possible race here with the signal handler
                remote_dispatcher.main_loop_iteration()
        except KeyboardInterrupt:
            if interactive:
                next_signal = signal.SIGINT
            else:
                kill_all()
                os.kill(0, signal.SIGINT)
        except asyncore.ExitNow as e:
            console_output(b'')
            save_history(histfile)
            sys.exit(e.args[0])
Example #17
0
def replicate(shell, path):
    peers = [i for i in dispatchers.all_instances() if i.enabled]
    if len(peers) <= 1:
        console_output('No other remote shell to replicate files to\n')
        return

    def should_print_bw(node, already_chosen=[False]):
        if not node.children and not already_chosen[0] and not node.is_upload:
            already_chosen[0] = True
            return True
        return False

    sender_index = peers.index(shell)
    destinations = peers[:sender_index] + peers[sender_index+1:]
    tree = file_transfer_tree_node(None,
                                   shell,
                                   destinations,
                                   0,
                                   should_print_bw,
                                   path=path)
Example #18
0
def do_hide_password(command):
    """
    Usage: :hide_password
    Do not echo the next typed line.
    This is useful when entering password. If debugging or logging is enabled,
    it will be disabled to avoid displaying a password. Therefore, you will have
    to reenable logging or debugging afterwards if need be.
    """
    warned = False
    for i in dispatchers.all_instances():
        if i.enabled and i.debug:
            i.debug = False
            if not warned:
                console_output('Debugging disabled to avoid displaying '
                               'passwords\n')
                warned = True
    stdin.set_echo(False)

    if remote_dispatcher.options.log_file:
        console_output('Logging disabled to avoid writing passwords\n')
        remote_dispatcher.options.log_file = None
Example #19
0
def do_hide_password(command):
    """
    Usage: :hide_password
    Do not echo the next typed line.
    This is useful when entering password. If debugging or logging is enabled,
    it will be disabled to avoid displaying a password. Therefore, you will have
    to reenable logging or debugging afterwards if need be.
    """
    warned = False
    for i in dispatchers.all_instances():
        if i.enabled and i.debug:
            i.debug = False
            if not warned:
                console_output('Debugging disabled to avoid displaying '
                               'passwords\n')
                warned = True
    stdin.set_echo(False)

    if remote_dispatcher.options.log_file:
        console_output('Logging disabled to avoid writing passwords\n')
        remote_dispatcher.options.log_file = None
Example #20
0
def do_replicate(command):
    """
    Usage: :replicate SHELL:REMOTE_PATH
    Copy a path from one remote shell to all others
    """
    if ':' not in command:
        console_output('Usage: :replicate SHELL:REMOTE_PATH\n')
        return
    shell_name, path = command.strip().split(':', 1)
    if not path:
        console_output('No remote path given\n')
        return
    for shell in dispatchers.all_instances():
        if shell.display_name == shell_name:
            if not shell.enabled:
                console_output('%s is not enabled\n' % shell_name)
                return
            break
    else:
        console_output('%s not found\n' % shell_name)
        return
    file_transfer.replicate(shell, path)
Example #21
0
def do_replicate(command):
    """
    Usage: :replicate SHELL:REMOTE_PATH
    Copy a path from one remote shell to all others
    """
    if ':' not in command:
        console_output('Usage: :replicate SHELL:REMOTE_PATH\n')
        return
    shell_name, path = command.strip().split(':', 1)
    if not path:
        console_output('No remote path given\n')
        return
    for shell in dispatchers.all_instances():
        if shell.display_name == shell_name:
            if not shell.enabled:
                console_output('%s is not enabled\n' % shell_name)
                return
            break
    else:
        console_output('%s not found\n' % shell_name)
        return
    file_transfer.replicate(shell, path)
Example #22
0
def main_loop():
    global next_signal
    last_status = None
    while True:
        try:
            if next_signal:
                current_signal = next_signal
                next_signal = None
                sig2chr = {signal.SIGINT: 'c', signal.SIGTSTP: 'z'}
                ctrl = sig2chr[current_signal]
                remote_dispatcher.log('> ^%c\n' % ctrl.upper())
                control_commands.do_send_ctrl(ctrl)
                console_output('')
                the_stdin_thread.prepend_text = None
            while dispatchers.count_awaited_processes()[0] and \
                  remote_dispatcher.main_loop_iteration(timeout=0.2):
                pass
            # Now it's quiet
            for r in dispatchers.all_instances():
                r.print_unfinished_line()
            current_status = dispatchers.count_awaited_processes()
            if current_status != last_status:
                console_output('')
            if remote_dispatcher.options.interactive:
                the_stdin_thread.want_raw_input()
            last_status = current_status
            if dispatchers.all_terminated():
                # Clear the prompt
                console_output('')
                raise asyncore.ExitNow(remote_dispatcher.options.exit_code)
            if not next_signal:
                # possible race here with the signal handler
                remote_dispatcher.main_loop_iteration()
        except asyncore.ExitNow, e:
            console_output('')
            sys.exit(e.args[0])
Example #23
0
def do_rename(command: str) -> None:
    for i in dispatchers.all_instances():
        if i.enabled:
            i.rename(command.encode())
Example #24
0
            retcode = subprocess.call(data[1:], shell=True)
        except OSError, e:
            if e.errno == errno.EINTR:
                console_output('Child was interrupted\n')
                retcode = 0
            else:
                raise
        if retcode > 128 and retcode <= 192:
            retcode = 128 - retcode
        if retcode > 0:
            console_output('Child returned %d\n' % retcode)
        elif retcode < 0:
            console_output('Child was terminated by signal %d\n' % -retcode)
        return

    for r in dispatchers.all_instances():
        try:
            r.dispatch_command(data)
        except asyncore.ExitNow, e:
            raise e
        except Exception, msg:
            console_output('%s for %s, disconnecting\n' % (msg, r.display_name))
            r.disconnect()
        else:
            if r.enabled and r.state is remote_dispatcher.STATE_IDLE:
                r.change_state(remote_dispatcher.STATE_RUNNING)

# The stdin thread uses a synchronous (with ACK) socket to communicate with the
# main thread, which is most of the time waiting in the poll() loop.
# Socket character protocol:
# d: there is new data to send
Example #25
0
            retcode = subprocess.call(data[1:], shell=True)
        except OSError, e:
            if e.errno == errno.EINTR:
                console_output('Child was interrupted\n')
                retcode = 0
            else:
                raise
        if retcode > 128 and retcode <= 192:
            retcode = 128 - retcode
        if retcode > 0:
            console_output('Child returned %d\n' % retcode)
        elif retcode < 0:
            console_output('Child was terminated by signal %d\n' % -retcode)
        return

    for r in dispatchers.all_instances():
        try:
            r.dispatch_command(data)
        except asyncore.ExitNow, e:
            raise e
        except Exception, msg:
            console_output('%s for %s, disconnecting\n' %
                           (msg, r.display_name))
            r.disconnect()
        else:
            if r.enabled and r.state is remote_dispatcher.STATE_IDLE:
                r.change_state(remote_dispatcher.STATE_RUNNING)


# The stdin thread uses a synchronous (with ACK) socket to communicate with the
# main thread, which is most of the time waiting in the poll() loop.