12

I am working on some scripts (in the company I work in) that are loaded/unloaded into hypervisors to fire a piece of code when an event occurs. The only way to actually unload a script is to hit Ctrl-C. I am writing a function in Python that automates the process

As soon as it sees the string "done" in the output of the program, it should kill the vprobe. I am using subprocess.Popen to execute the command:

lineList = buff.readlines()
cmd = "vprobe /vprobe/myhello.emt"
p = subprocess.Popen(args = cmd, shell=True,stdout = buff, universal_newlines = True,preexec_fn=os.setsid)
while not re.search("done",lineList[-1]):
        print "waiting"
os.kill(p.pid,signal.CTRL_C_EVENT)

As you can see, I am writing the output in buff file descriptor opened in read+write mode. I check the last line; if it has 'done', I kill it. Unfortunately, the CTRL_C_EVENT is only valid for Windows. What can I do for Linux?

Stefan van den Akker
  • 6,661
  • 7
  • 48
  • 63
Core_Dumped
  • 4,577
  • 11
  • 47
  • 71
  • 3
    FYI: `re.search` with a constant string can be better expressed as `while 'done' not in lineList[-1]: ...` – nneonneo Oct 23 '12 at 06:32

3 Answers3

13

I think you can just send the Linux equivalent, signal.SIGINT (the interrupt signal).

(Edit: I used to have something here discouraging the use of this strategy for controlling subprocesses, but on more careful reading it sounds like you've already decided you need control-C in this specific case... So, SIGINT should do it.)

Andrew Gorcester
  • 19,595
  • 7
  • 57
  • 73
  • hey Andrew. Thanks for the answer. But actually, the SIGINT kills only the subprocess function while the vprobe continues it's execution.Do you have an idea of how to kill that too? Thanks – Core_Dumped Oct 23 '12 at 06:50
  • 1
    Well, if it works on Windows, then hopefully that means the signal is going to the right place. So, try something stronger. Give SIGTERM a try, and if that doesn't work, SIGKLL. If SIGKILL doesn't work, then nothing will -- you'll have to look at different ways of handling the subprocess altogether. – Andrew Gorcester Oct 23 '12 at 06:53
  • Did you try `Popen(['vprobe ', '/vprobe/myhello.emt'], shell=False, ...)`? @Core_Dumped – alk Oct 23 '12 at 07:08
5

Maybe I misunderstand something, but the way you do it it is difficult to get the desired result.

Whatever buff is, you query it first, then use it in the context of Popen() and then you hope that by maciv lineList fills itself up.

What you probably want is something like

logfile = open("mylogfile", "a")
p = subprocess.Popen(['vprobe', '/vprobe/myhello.emt'], stdout=subprocess.PIPE,  buff, universal_newlines=True, preexec_fn=os.setsid)
for line in p.stdout:
    logfile.write(line)
    if re.search("done", line):
        break
    print "waiting"
os.kill(p.pid, signal.CTRL_C_EVENT)

This gives you a pipe end fed by your vprobe script which you can read out linewise and act appropriately upon the found output.

glglgl
  • 89,107
  • 13
  • 149
  • 217
  • This is almost exactly what I want to do,except that I want the output to get printed in some file as well (along with getting into the PIPE for checking purposes). How can I do that? (I hope I am grammatically correct this time :)) – Core_Dumped Oct 23 '12 at 07:46
  • The above code seems well and good but when I use the stdout as an attribute of the object p, it gives me Broken PIPE error. – Core_Dumped Oct 23 '12 at 09:36
  • @Core_Dumped Where exactly do you get that? At the sending side (in `vprobe`), or in your own program? – glglgl Oct 23 '12 at 09:42
  • cmd = "/sbin/vprobe /vprobe/myhello.emt" p = subprocess.Popen(args = cmd, shell = True, stdout=subprocess.PIPE, preexec_fn=os.setsid) print p.stdout gives: ', mode 'rb' at 0xffd36758> vprobe: [Errno 32] Broken pipe – Core_Dumped Oct 23 '12 at 09:46
  • This is clear. You don't read the `p.stdout` as provided in my answer, and when the reading side of the pipe dies, `vprobe` gets a `SIGPIPE`. You should do as written in my answer. – glglgl Oct 23 '12 at 09:49
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/18456/discussion-between-core-dumped-and-glglgl) – Core_Dumped Oct 23 '12 at 09:59
5

In Linux, Ctrl-C keyboard interrupt can be sent programmatically to a process using Popen.send_signal(signal.SIGINT) function. For example

import subprocess
import signal

..
process = subprocess.Popen(..)
..
process.send_signal(signal.SIGINT)
..

Don't use Popen.communicate() for blocking commands..

Asif Hasnain
  • 179
  • 1
  • 1