How Can I get the result of child process of a command executed in subprocess? - python-3.x

I want run Valgrind in a jail that created before and copyied required file in Jail. We know Valgrind generate two files XML and TXT files. I want to run python script that can cache the results of Valgrind files (XML and TXT file) and carry them to out of Jail. For example we have a function that run Valgrind in the Jail. Below code show it:
import os
def run_valgrind_in_jail(chroot_path, command):
os.chdir(chroot_path)
os.chroot(chroot_path)
return subprocess.run(['valgrind', '--xml=yes','--leak-check=full', '--verbose',
'--xml-file={}_valgrind.xml'.format(command),
'--log-file={}_valgrind.txt'.format(command),command],
stderr=subprocess.PIPE, stdout=subprocess.PIPE)
Valgrind generate two file XML and txt and I want to carry them to out of chroot (jail).
How can I get the output process of Valgrind and carry out to out of Jail.

You're putting your whole program in jail, not just the subprocess. Use a preexec_fn so only the subprocess is in the jail, not the rest of your Python program, and then you'll find your output files in the chroot_path directory:
import os, subprocess
class Jailer(object):
def __init__(self, chroot_path):
self.chroot_path = chroot_path
def __call__(self):
os.chdir(self.chroot_path)
os.chroot(self.chroot_path)
def run_valgrind_in_jail(chroot_path, command):
proc = subprocess.run(['valgrind', '--xml=yes','--leak-check=full', '--verbose',
f'--xml-file={command}_valgrind.xml',
f'--log-file={command}_valgrind.txt',
command],
stderr=subprocess.PIPE, stdout=subprocess.PIPE,
preexec_fn=Jailer(chroot_path))
xml_file = open(os.path.join(chroot_path, f'{command}_valgrind.xml'))
log_file = open(os.path.join(chroot_path, f'{command}_valgrind.txt'))
return (proc, xml_file, log_file)

Related

how to repeatedly send argv inputs to an running .exe in python

Suppose I run a .exe program within python whatever os or subprocess, the .exe program is designed to pop up some different results with different arguments, my steps are the following:
In python run .exe first(keep it alive, it will have communication
with hardware and do initialization)
send different arguments to
this .exe and collect the different outputs.
I tried the following code:
hello.py
import sys
for arg in sys.argv:
print(arg)
print("Hello World!")
test.py
import subprocess
command='./exe_example/output/hello/hello.exe a b'.split()
result = subprocess.run(command, stdout=subprocess.PIPE, text=True)
print(result.stdout)
the output is:
a b Hello World!
but how to change the input argv and get the result without running the whole .exe command again?
UPDATES:
I changed the hello.py as follows:
import sys
while True:
a = input()
print('response = ',a)
after compiling to .exe, I could manually run it in the dos window
hello.exe
a
response = a
b
response = b
c
response = c
but I still don't know how to run it in python
finally, I figured out, first from this post, I added flush()
cmd = "E:/exe_example/TestCl.exe"
p = Popen(cmd, stdin=PIPE,stdout=PIPE, bufsize=0)
p.stdin.write('getall\n'.encode())
p.stdin.flush()
for i in range(48):
print(p.stdout.readline())
then, very important, if I use read(), because the .exe is always listening to the input, so it will hang up forever and never output, in this case, readline() is very important

Running a string command using exec with popen

I have a simple cmd_str containing a set of lines. Using exec, I can run those lines juts fine. However, running those lines in a separate process when shell=True is failing. Is this dues to missing quotes? what is happening under the hood?
import subprocess
cmd_str = """
import sys
for r in range(10):
print('rob')
"""
exec(cmd_str) # works ok
full_cmd = f'python3 -c "exec( "{cmd_str}" )"'
process = subprocess.Popen([full_cmd],
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
(output, error) = process.communicate()
exit_code = process.wait()
output_msg = output.decode("utf-8", 'ignore')
error_msg = error.decode("utf-8", 'ignore').strip()
Your approach is slightly inaccurate. I believe the problem you're having has to do with the subprocess usage. The first thing you must realise is that exec
is a way to send and execute python code to and from the interpreter directly. This is why it works inside python programs(and it is generally not a good approach). Subprocesses on the other hand handle command like they are being called directly from the terminal or shell. This means that you no longer need to include exec cause you are already interacting with the python interpreter when you call python -c.
To get this to run in a subprocess environment all you need to do is
full_cmd = f'python3 -c "{cmd_str}"'
process = subprocess.Popen(full_cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
Also, notice the absence of square brackets when calling subprocess.Popen, this is because that particular approach works slightly different and if you want to use the square brackets your command will have to be
full_cmd = ['python3', '-c', f'{cmd_str}']
process = subprocess.Popen(full_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
And with these few changes, everything should work OK

Program ran from subprocess.run() in python3, cannot create files

I have a program that is supposed to create a text file. When called from subprocess.run() in python3, the program runs but it does not create the text file. The program works as expected when called from the terminal.
import subprocess as subp
...
comm=[os.getcwd()+'/test/myprogram.bin','arg1','arg2']
compl_proc = subp.run(comm,
capture_output=True,
text=True,
check=True)
The file was in the python script directory, because I never told subprocess.run() what is the current working directory of the subprocess. So cwd='...' is added.
import subprocess as subp
import os
...
comm=[os.getcwd()+'/test/myprogram.bin','arg1','arg2']
compl_proc = subp.run(comm,
cwd=os.getcwd()+'/test/',
capture_output=True,
text=True,
check=True)

Is there a way to store the output of a linux command into a variable in python network programming?

I am trying to build a system where a list of the available wifi networks would be stored for some specific purpose. Now the problem is that executing a system command with os.system() in a variable 'res' only stores the return value of the command which is useless to me at this point.
I know of no approach that provide me the desired result.
import os
res = os.system('nmcli dev wifi')
The variable res must store all the desired result into it rather than the return value. Even if it stores result, it will do the work.
You can do this using the Popen method from the subprocess module
from subprocess import Popen, PIPE
#First argument is the program name.
arguments = ['ls', '-l', '-a']
#Run the program ls as subprocess.
process = Popen(arguments, stdout=PIPE, stderr=PIPE)
#Get the output or any errors. Be aware, they are going to be
#in bytes!!!
stdout, stderr = process.communicate()
#Print the output of the ls command.
print(bytes.decode(stdout))

Unable to get send sudo password to subprocess.Popen() successfully in Python for bash

I'm attempting to create a python script to compile github surface kernel using their recommended steps.
https://github.com/dmhacker/arch-linux-surface
So far I'm stuck at a couple of sections.
Per the instructions for compiling the setup.sh must be run using sudo.
I've tried sending in the password before calling process using
preproc = subprocess.Popen(password, shell=True, stdout=subprocess.PIPE)
process = subprocess.Popen(["sudo", 'sh setup.sh'], shell=True, stdin=preproc.stdout, encoding='utf8')
I've tried sudo -S which doesn't seem to work at all. I've also tried lowercase -s.
I've tried changing subprocess.Popen to subprocess.call
password = getpass.getpass()
process = subprocess.Popen(["sudo", 'sh setup.sh'], shell=True,
stdin=subprocess.PIPE, encoding='utf8')
print(process.communicate(password + "\n"))
process.wait()
I expected the shell to be run at sudo level but it's not.
I'm not exactly sure what the difference is as I've since gone through many iterations, but finally got it to work and simplified. Hope this helps someone in the future.
import getpass
from subprocess import Popen, PIPE
password = getpass.getpass()
command = "./setup.sh"
process = Popen(['sudo', '-S', command], stdout=PIPE, encoding='utf8')
process.communicate(password)

Resources