popen3 and return code - python

I want to get stdout and stderr of a command along with the return code.
Can someone point me to a python function that already accomplishes this?
I modified a function that I found on this site as follows -- but I am not able to grab the return code of the command. In this snippet, sts always seems to be 0.
def Getstatusoutput(cmd):
"""Return (status, output) of executing cmd in a shell."""
import sys
mswindows = (sys.platform == "win32")
import os
if not mswindows:
cmd = '{ ' + cmd + '; }'
fi,fo,fe=os.popen3(cmd)
textOut = fo.read()
textErr = fe.read()
sts = fo.close()
if sts is None: sts = 0
if textOut[-1:] == '\n': textOut = textOut[:-1]
return sts, textOut, textErr

Use the subprocess module. This section shows how to replace os.popen3 calls.

Related

I need help completing my code. Note I am a beginner in Python

I am trying to develop a script which sends an email about checking ping regularly at one hour interval of time. I am using Python to program this script and I cannot create a log file to keep the ping logs which I need to mail. I'm new to using subprocess module and its functions.
import threading
import os
def check_ping():
threading.Timer(5.0, check_ping).start()
hostname = "www.google.com"
response = os.system("ping -c 4 " + hostname)
'''
def trace_route():
threading.Timer(5.0, trace_route).start()
hostname = "www.google.com"
response = os.system("traceroute" + hostname)
'''
check_ping()
#trace_route()
output = check_ping()
file = open("sample.txt","a")
file.write(output)
file.close()
import os, platform
import threading
def check_ping():
threading.Timer(10.0,check_ping).start()
hostname = "www.google.com"
response = os.system("ping " + ("-n 1 " if platform.system().lower()=="windows" else "-c 1 ") + hostname)
# and then check the response...
if response == 0:
pingstatus = "Network Active"
else:
pingstatus = "Network Error"
return pingstatus
pingstatus = check_ping()
This is what I came up with:
using subprocess instead of os.system
added timeout of 8 seconds
writing to csv file instead of txt file
added timestamps to csv file, without which I don't really see the point of logging in the first place
import os
import threading
import time
from subprocess import Popen, PIPE
def check_ping():
threading.Timer(10.0,check_ping).start()
# Get current time
timestamp = int(time.time())
# Build the command
hostname = "www.google.com"
if os.name == 'nt':
command = ['ping', '-n', '1', hostname]
else:
command = ['ping', '-c', '1', hostname]
# Create process
pingProcess = Popen(command, stdout=PIPE, stderr=PIPE)
try:
# Timeout 8 seconds, to avoid overlap with the next ping command
outs, errs = pingProcess.communicate(timeout=8)
except TimeoutExpired:
# If timed out, kill
pingProcess.kill()
outs, errs = pingProcess.communicate()
# Get the return code of the process
response = pingProcess.returncode
# and then check the response...
# These four lines can be removed, they are just to see if the system
# works.
if response == 0:
print("Network Active")
else:
print("Network Error")
# You most likely want a CSV file, as most programs accept this file type,
# including Microsoft Excel and LibreOffice Calc
# Further, I'm sure you want timestamps with the results.
file = open("ping.csv","a")
file.write(str(timestamp) + "," + str(response) + "\n")
file.close()
check_ping()
Here is another version without using the system's ping command, but instead using a python library for pinging. This ensures that the code works on all operating systems:
import threading
import time
from ping3 import ping
def check_ping():
threading.Timer(10.0,check_ping).start()
# Get current time
timestamp = int(time.time())
# Build the command
hostname = "www.google.com"
# Run ping
ping_result = ping(hostname, timeout=8)
ping_success = False if ping_result is None else True
# and then check the response...
# These four lines can be removed, they are just to see if the system
# works.
if ping_success:
print("Network Active (" + str(ping_result) + ")")
else:
print("Network Error")
# You most likely want a CSV file, as most programs accept this file type,
# including Microsoft Excel and LibreOffice Calc
# Further, I'm sure you want timestamps with the results.
file = open("ping.csv", "a")
ping_value_str = str(ping_result) if ping_success else "NaN"
file.write(str(timestamp) + "," + ("0" if ping_success else "1") + "," + ping_value_str + "\n")
file.close()
check_ping()

Python: Returning 0 in min(list) with no min of 0

I'm creating a command that will take a partial or whole name match of a process and kill its lowest pid - and thus the rest of the processes spawned from it. My code returns a min(list_of_process_ids) of 0, of which there is no min of 0. Please enlighten me as to why this is happening. Thank you.
#!/usr/bin/env python
"""Kill proceses by partial name matching"""
import os, sys
def usage():
return ("pskill.py process_name")
def pids(proc):
""" Find the processes"""
procs = []
procs = os.system("ps -ef|grep -i " + proc + "|grep -v grep|grep -v pfind|awk '{print $2}'")
procs = [int(x) for x in str(procs)]
return procs
def kill(procs):
ppid = min(procs)
os.system("kill " + str(ppid))
return ("Processes Killed...")
def main():
if len(sys.argv) != 2:
print (usage())
else:
proc = sys.argv[1]
pids(proc)
kill(pids(proc))
main()
You aren't grabbing the stdout, so you aren't actually getting anything other that the exist status of the command. Which you can be glad is 0 :-)
Try using the subprocess module. Specifically with the stdout option of piping the result to your python console...

Python: Closing a for loop by reading stdout

import os
dictionaryfile = "/root/john.txt"
pgpencryptedfile = "helloworld.txt.gpg"
array = open(dictionaryfile).readlines()
for x in array:
x = x.rstrip('\n')
newstring = "echo " + x + " | gpg --passphrase-fd 0 " + pgpencryptedfile
os.popen(newstring)
I need to create something inside the for loop that will read gpg's output. When gpg outputs this string gpg: WARNING: message was not integrity protected, I need the loop to close and print Success!
How can I do this, and what is the reasoning behind it?
Thanks Everyone!
import subprocess
def check_file(dictfile, pgpfile):
# Command to run, constructed as a list to prevent shell-escaping accidents
cmd = ["gpg", "--passphrase-fd", "0", pgpfile]
# Launch process, with stdin/stdout wired up to `p.stdout` and `p.stdin`
p = subprocess.Popen(cmd, stdin = subprocess.PIPE, stdout = subprocess.PIPE)
# Read dictfile, and send contents to stdin
passphrase = open(dictfile).read()
p.stdin.write(passphrase)
# Read stdout and check for message
stdout, stderr = p.communicate()
for line in stdout.splitlines():
if line.strip() == "gpg: WARNING: message was not integrity protected":
# Relevant line was found
return True
# Line not found
return False
Then to use:
not_integrity_protected = check_file("/root/john.txt", "helloworld.txt.gpg")
if not_integrity_protected:
print "Success!"
If the "gpg: WARNING:" message is actually on stderr (which I would suspect it is), change the subprocess.Popen line to this:
p = subprocess.Popen(cmd, stdin = subprocess.PIPE, stderr = subprocess.PIPE)
..and the for loop from stdout to stderr, like this:
for line in stderr.splitlines():
Use subprocess.check_output to call gpg and break the loop based on its output.
Something like this (untested since I don't know anything about gpg):
import subprocess
dictionaryfile = "/root/john.txt"
pgpencryptedfile = "helloworld.txt.gpg"
with open(dictionaryfile, 'r') as f:
for line in f:
x = line.rstrip('\n')
cmd = ["echo " + x + " | gpg --passphrase-fd 0 " + pgpencryptedfile]
output = subprocess.check_output(cmd, shell=True)
if 'gpg: WARNING: message was not integrity protected' in output:
break
You could use the subprocess module which allows you to use:
subprocess.call(args, *, stdin, stdout, stderr, shell)
(See the Python Documentation for how to use the parameters.)
This is good because you can easily read in the exit code of whatever program you call.
For example if you change 'newstring' to:
"echo " + x + " | gpg --passphrase-fd 0 " + pgpencryptedfile | grep 'gpg: WARNING: message was not integrity protected'
grep will then return 0 if there is a match and a 1 if not matches are found. (Source)
This exit code from grep will be returned from the subprocess.call() function and you can easily store it in a variable and use an if statement.
Edit: As Matthew Adams mentions below, you could also read the exit code of gpg itself.

Python replace statement

I'm pretty new to Python but need to patch this glitch/exploit in an addon service.
My code looks like this:
#!/usr/bin/env python
import subprocess
import sys
import os
import yaml
from xml.dom import minidom
sys.path.append('/scripts')
import createvhosts
doc = minidom.parse(sys.stdin)
param0taglist = doc.getElementsByTagName('param0')
param1taglist = doc.getElementsByTagName('param1')
param0 = param0taglist[0].childNodes[0].toxml()
param1 = param1taglist[0].childNodes[0].toxml()
domain = param0 + '.' + param1
usertaglist = doc.getElementsByTagName('USER')
user = usertaglist[0].childNodes[0].toxml()
f = open('/var/cpanel/userdata/' + user + '/main')
ydata = yaml.load(f)
f.close()
sublist = ydata['sub_domains']
addondict = ydata['addon_domains']
parkedlist = ydata['parked_domains']
mainlist = ydata['main_domain']
serverip = createvhosts.getmainip()
if len(sublist) != 0:
slcont = 0
while slcont < len(sublist):
domain = sublist[slcont]
docroot, yip, alias = createvhosts.getvars(sublist[slcont])
if yip == serverip:
createvhosts.writeconfshared(user, domain, docroot, yip, alias)
else:
createvhosts.writeconfded(user, domain, docroot, yip, alias)
slcont = slcont + 1
proc = subprocess.Popen("/etc/init.d/nginx restart > /dev/null 2>&1", shell=True)
The issue is when you add a subdomain in CPanel with * it will crash the server because apparently nginx does not seem to allow and accept that. What I need help doing is figuring out how to replace/block * so it does not go in.
Does something like Param0.find( "*" ) !=-1 work?
The construct you're looking for is char in string.
>>> s = 'ab*de'
>>> '*' in s
True
Put this in a conditional and you've got what you want - something like:
if '*' in param0:
raise ValueError("Can't use '*'!")
This, along with a comprehensive list of the methods available on strings to do more involved work, is documented in the official docs, under Built-in Types.

/usr/bin/python: can't find '__main__.py' in '/' when using subprocess.call

I am writing a Python script to do some admin functionality which involves running several other python scripts.
A snipet of my code looks like this:
import subprocess
PYTHON_BIN_DIR = '/usr/bin/python'
SCRIPTS_DIR = '/some/path'
if __name__ == "__main__":
dateparam = "05-Jan-2012"
command = [PYTHON_BIN_DIR]
command.extend(SCRIPTS_DIR + "/myfile1.py")
strparams = " --param1={0} ".format(123)
command.extend(strparams)
command.extend(dateparam)
retcode = subprocess.call(command)
if retcode != 0:
# do something
pass
else:
# do something else
pass
All the scripts I'm calling are using the if __name__ == ""__main__"" check/test. So what's causing the error?
As pointed out in comments you should use append instead of extend. I think your other problem is you've included spaces in your argument. I would split up each parameter, i.e. --param1=123:
import subprocess
import os.path
PYTHON_BIN_DIR = '/usr/bin/python'
SCRIPTS_DIR = '/some/path'
if __name__ == "__main__":
dateparam = "05-Jan-2012"
command = [PYTHON_BIN_DIR, os.path.join(SCRIPTS_DIR, 'myfile1.py'),
'--param1', 123, '--date', dateparam]
retcode = subprocess.call(command)
if retcode != 0:
# do something
pass
else:
# do something else
pass

Categories