###############################################################################
#
# pexpect 0.94 is inlined here because it's not in the Python library yet.
-# Some comments have been removed.
+# Some comments have been removed, and the interact() method.
#
"""
Noah Spurrier
-$Revision: 1.7 $
-$Date: 2002/11/22 22:12:43 $
+$Revision: 1.8 $
+$Date: 2002/11/23 02:20:19 $
"""
import os, sys
import select
Currently pexpect is intended for UNIX operating systems (including OS-X)."""
__version__ = '0.94'
-__revision__ = '$Revision: 1.7 $'
+__revision__ = '$Revision: 1.8 $'
__all__ = ['ExceptionPexpect', 'EOF', 'TIMEOUT', 'spawn',
'__version__', '__revision__']
if which(self.command) == None:
raise ExceptionPexpect ('The command was not found or was not executable: %s.' % self.command)
-# I'm no longer using this technique to test if a process is alive.
-# First, it is not portable.
-# Second, it messes up other subsystems that use signals (such as pipes).
-# Third, signals on UNIX suck.
-# # This is necessary for isAlive() to work. Without this there is
-# # no portable way to tell if a child process is a zombie.
-# # Checking waitpid with WNOHANG option does not work and
-# # checking waitpid without it would block if the child is not a zombie.
-# # With this children should exit completely without going into
-# # a zombie state. Note that some UNIX flavors may send the signal
-# # before the child's pty output buffer is empty, while others
-# # may send the signal only when the buffer is empty.
-# # In the later case, isAlive() will always return true until the
-# # output buffer is empty. Use expect_eof() to consume all child output.
-# # This is not the same as the Zombie (waiting to die) problem.
-# #signal.signal(signal.SIGCHLD, signal.SIG_IGN)
try:
self.pid, self.child_fd = pty.fork()
raise ExceptionPexpect('Pexpect: pty.fork() failed: ' + str(e))
if self.pid == 0: # Child
- setwinsize(24, 80)
# Do not allow child to inherit open file descriptors from parent.
max_fd = resource.getrlimit(resource.RLIMIT_NOFILE)[0]
for i in range (3, max_fd):
# Same as os.kill, but the pid is given for you.
os.kill(self.pid, sig)
- def interact(self, escape_character = chr(29)):
- """This gives control of the child process to the interactive user.
- Keystrokes are sent to the child process, and the stdout and stderr
- output of the child process is printed.
- When the user types the escape_character this method will stop.
- The default for escape_character is ^] (ASCII 29).
- This simply echos the child stdout and child stderr to the real
- stdout and it echos the real stdin to the child stdin.
- """
- mode = tty.tcgetattr(self.STDIN_FILENO)
- tty.setraw(self.STDIN_FILENO)
- try:
- self.__interact_copy(escape_character)
- finally:
- tty.tcsetattr(self.STDIN_FILENO, tty.TCSAFLUSH, mode)
-
- def __interact_writen(self, fd, data):
- """This is used by the interact() method.
- """
- while data != '' and self.isalive():
- n = os.write(fd, data)
- data = data[n:]
- def __interact_read(self, fd):
- """This is used by the interact() method.
- """
- return os.read(fd, 1000)
- def __interact_copy(self, escape_character = None):
- """This is used by the interact() method.
- """
- while self.isalive():
- r, w, e = select.select([self.child_fd, self.STDIN_FILENO], [], [])
- if self.child_fd in r:
- data = self.__interact_read(self.child_fd)
- os.write(self.STDOUT_FILENO, data)
- if self.STDIN_FILENO in r:
- data = self.__interact_read(self.STDIN_FILENO)
- self.__interact_writen(self.child_fd, data)
- if escape_character in data:
- break
-
-
def which (filename):
"""This takes a given filename and tries to find it in the
environment path and check if it is executable.
return f
return None
-def setwinsize(r, c):
- """This sets the windowsize of the tty for stdout.
- This does not change the physical window size.
- It changes the size reported to TTY-aware applications like
- vi or curses. In other words, applications that respond to the
- SIGWINCH signal.
- This is used by __spawn to set the tty window size of the child.
- """
- # Check for buggy platforms. Some Pythons on some platforms
- # (notably OSF1 Alpha and RedHat 7.1) truncate the value for
- # termios.TIOCSWINSZ. It is not clear why this happens.
- # These platforms don't seem to handle the signed int very well;
- # yet other platforms like OpenBSD have a large negative value for
- # TIOCSWINSZ and they don't truncate.
- # Newer versions of Linux have totally different values for TIOCSWINSZ.
- # Note, this fix is a hack.
- TIOCSWINSZ = termios.TIOCSWINSZ
- if TIOCSWINSZ == 2148037735L: # L is not required in Python 2.2.
- TIOCSWINSZ = -2146929561 # Same number in binary, but with sign.
-
- # Assume ws_xpixel and ws_ypixel are zero.
- s = struct.pack("HHHH", r, c, 0, 0)
- x = fcntl.ioctl(sys.stdout.fileno(), TIOCSWINSZ, s)
-
-def getwinsize():
- s = struct.pack("HHHH", 0, 0, 0, 0)
- x = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, s)
- return struct.unpack("HHHH", x)
-
def split_command_line(command_line):
"""This splits a command line into a list of arguments.
It splits arguments on spaces, but handles
return self.remote("ssh -l %s %s \"%s\""%(self.user,self.host,command))
def scp(self, src, dst):
return self.remote("scp %s %s@%s:%s" % (src, session.user, session.host, dst))
- def checkfile(self, file):
+ def exists(self, file):
"Retrieve file permissions of specified remote file."
seen = session.ssh("/bin/ls -ld %s" % file)
if string.find(seen, "No such file") > -1:
return None # File doesn't exist
else:
return seen.split()[0] # Return permission field of listing.
- def fixperms(self, file):
+ def fixperms(self, file, checkonly=None):
"Force perms of remote file to user read on, group/other write off."
- perms = session.checkfile(file)
+ perms = session.exists(file)
print "Remote %s permissions are %s" % (file, perms)
if not (perms[1] == 'r' and perms[5] == '-' and perms[8] == '-'):
print "User read should be on, Group and Other write permissions should be off."
- if not check:
+ if not checkonly:
print "Correcting permissions..."
session.ssh("/bin/chmod u+r,g-w,o-w %s" % file)
def forcefile(self, file, command):
"Create file with command if it does not already exist."
- perms = session.checkfile(file)
+ perms = session.exists(file)
if perms is None:
print "Remote %s doesn't exist." % file
if check:
die("Bailing out...")
else:
print "Creating remote %s" % file
- perms = session.checkfile(file)
+ perms = session.exists(file)
else:
print file, "already exists."
return perms
session = ssh_session(login, host, verbose)
# Permissions checks
- session.fixperms("~")
+ session.fixperms("~", check)
session.forcefile("~/.ssh", "mkdir ~/.ssh")
- session.fixperms("~/.ssh")
+ session.fixperms("~/.ssh", check)
# OK, install keys remotely if they don't exist
- if not session.checkfile("~/.ssh/authorized_keys"):
+ if not session.exists("~/.ssh/authorized_keys"):
session.scp(keyfile, "~/.ssh/authorized_keys")
except SystemExit:
pass