Reputation: 3
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
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