0

I have a python 3 script that accepts input from the user, this input is piped into a subprocess, where a shell has been spawned. Originally I was going to put this code together with a socket, to be able to make my own non-serious remote administration tool, however this proves too hard for my level currently. Code:

import subprocess

p1 = subprocess.Popen(["/bin/sh"], stderr = subprocess.PIPE, stdin = subprocess.PIPE, stdout = subprocess.PIPE, encoding = "utf-8")

command = input("Command: ")

p1.stdin.write(command)

p1.stdout.read()

Problem: Nothing gets printed out. I have searched endless hours online for a reason, over multiple days, but all of them don't seem to work, and/or advise using communicate() which is something I do not want to do. When thinking ahead if I am able to implement this with a socket, I can't have the process closing after each command. I have also tried flushes everywhere, before write, inbetween the read, after the read, pretty much everywhere you can think of. It should be simple enough, without me having to look deep into the io module or the rules of buffering (too late now). I have been struggling with this for days on end.

Andrii Starusiev
  • 7,564
  • 2
  • 28
  • 37
  • Welcome to Stack Overflow! When you post blocks of code, please add four spaces at the start of each line to make it display as a code snippet. For more information on formatting posts, read the [editing help](//stackoverflow.com/editing-help) in the help center. – Andrew Myers Jul 28 '17 at 15:17

1 Answers1

0

You have a couple of issues, I will try to draw the path, I hope I am not misleading you.

First of all, disclaimer: executing user input is inherently unsafe. If that's not an issue, let's keep on your problem.

I would start by doing

p1 = subprocess.Popen(["/bin/sh"], stderr=subprocess.PIPE, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True, bufsize=1)

Having a line-buffered PIPE is a good idea, in this scenario.

Then, remember that you have to press enter after the command, so:

command = input("Command: ") + "\n"

The write is correct,

p1.stdin.write(command)

But the, the read is VERY dangerous and you will trivially become deadlocked. Because the stdout is open (without an EOF or anything like that) you should read conservatively, and still, you will have problems on that.

A first idea would be to read lines:

p1.stdout.readline()

But, if you don't know how many lines you can read... then that's a problem. In fact, that specific problem has already been asked.

If you want to experiment, just open an interactive python interpreter, send a "ls\n" command and perform readline(). It will work, until you read the last line, and then... it will wait forever. That is bad behaviour. So you will need to solve that.

MariusSiuram
  • 3,380
  • 1
  • 21
  • 40