digitalosmosis
digitalosmosis

Reputation: 3

Python - Dealing with Input Prompt in a Subprocesses

I'm trying to get a python script on a remotely deployed embedded Linux device to execute an scp command. Executing the command is simple, but if the target server is not listed in the 'known_hosts' file, scp throws a warning that needs to be interacted with. Banging my head against this for days, and I can't solve 2 problems.

First, I can't get nonblocking read of responses from the subprocess to function correctly. In the following code, select always returns ( [ ], [ ], [ ] ), even when I know I can read from stderr (assuming a trusted hosts file warning is generated).

cmdString = 'scp [email protected]:file localFile -i ~/.ssh/id_rsa'

process = subprocess.Popen(shlex.split(cmdString), shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

while(process.poll() is None):
  readable, writable, exceptional = select.select([process.stdout], [], [process.stderr], 1)

  if not (readable or writable or exceptional):
    # Always hits this condition, although adding an "os.read(...)" here
    # will return the error prompt from process.stderr.
    print "timeout condition"
  else:
    # Never makes it here
    for e in exceptional:
      stderr = os.read(process.stderr.fileno(), 256)
      print stderr
    for r in readable:
      stdout = os.read(process.stdout.fileno(), 256)
      print stdout

Second, I can't get the subprocess to advance beyond the warning by feeding input through an input PIPE. The following code reads the warning code from process.stderr but then hangs until I hit {enter} in my terminal. I've tried sending "n", "n\n", and "\n", but none cause the subprocess to continue execution (though all 3 patterns work when entered manually).

cmdString = 'scp [email protected]:file localFile -i ~/.ssh/id_rsa'

process = subprocess.Popen(shlex.split(cmdString), shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

# Correctly grabs warning and displays it
stderr = os.read(process.stderr.fileno(), 256)
print stderr

# Just in case there was some weird race condition or something
time.sleep(0.5)

# Doesn't ever seem to do anything
process.stdin.write('\n')

Finally, does it matter? I originally started investigating subprocess and PIPES because I was running scp using "os.system(cmdString)" which blocked my thread and was forcing me to deal with the issue. Now that I'm using subprocess, is it bad to just fire off the command and let it succeed or fail? Will the failed subprocesses eventually die off, or could I eventually end up where I have dozens or hundreds of hidden scp attempts running, but waiting for user input?

Thanks!

Upvotes: 0

Views: 847

Answers (1)

mweerden
mweerden

Reputation: 14051

The problem is likely that scp doesn't communicate using stdin/stdout/stderr in this case, but directly via the terminal.

You can find a lot of similar questions as well as way to deal with it by searching for something like scp input on stackoverflow.

Started subprocesses will only die when the parents "piped" the output (stdout/stderr) and the subprocess tries to write something. In this case, scp will probably keep running because it is using the terminal. These processes are not really hidden, though; you can easily see them with a tool like ps (and kill them with kill or killall).

EDIT: As you mentioned you have problems with various libraries, perhaps the following approach will help:

import os, pty

pid, fd = pty.fork()
if pid == 0:
  os.execvp('scp', ['scp', '[email protected]:file', ... ])
else:
  while True:
    s = os.read(fd, 1024)
    print repr(s)
    os.write(fd, 'something\n')

Upvotes: 1

Related Questions