13

I am running with a user that can make root-level calls without having to supply a password. My user currently does something like this

pr = subprocess.Popen("sudo sleep 100".split())
sleep(5)
pr.kill()

but that leads to this error because the user isn't root so it can't kill a root process

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/subprocess.py", line 1572, in kill
    self.send_signal(signal.SIGKILL)
  File "/usr/lib/python2.7/subprocess.py", line 1562, in send_signal
    os.kill(self.pid, sig)
OSError: [Errno 1] Operation not permitted

so I try to do something like this

pr = subprocess.Popen("sudo sleep 100".split())
sleep(5)
kill_pr = subprocess.Popen("sudo kill {}".format(pr.pid))

but that doesn't kill the process in question. For example, if

>> subprocess.Popen("sudo sleep 100".split()).pid
5000

but

$ pgrep sleep
5001

so it seems that the pid returned from subprocess.Popen("..").pid is one higher than the actual pid of the process running the command that I want to kill

I'm assuming that the pid returned from the Popen call is the parent process, so I try doing something like

sudo kill -- -$PID, where $PID is the one returned from Popen, but that just gives me

kill: sending signal to -2100 failed: No such process

why doesn't the process exist?

Essentially, I just need a way to run a command with sudo using python's subprocess, then be able to kill it when I need to. I'm assuming I need to run some type of sudo kill command with the pid of the process I'm trying to kill or something like that but I'm unable to determine exactly how to do this.

John Allard
  • 3,564
  • 5
  • 23
  • 42

3 Answers3

6

I think I figured it out, the issue was that if I did this

import subprocess, os
pr = subprocess.Popen(["sudo", "sleep", "100"])
print("Process spawned with PID: %s" % pr.pid)
pgid = os.getpgid(pr.pid)
subprocess.check_output("sudo kill {}".format(pgid))

it would kill the process that started the python interpreter

>>> Terminated

so instead, I set the preexec_fn to os.setpgrp

import subprocess, os
pr = subprocess.Popen(["sudo", "sleep", "100"], preexec_fn=os.setpgrp)
print("Process spawned with PID: %s" % pr.pid)
pgid = os.getpgid(pr.pid)
subprocess.check_output("sudo kill {}".format(pgid))

in another shell, if I check

pgrep sleep

nothing shows up, so it is actually killed.

John Allard
  • 3,564
  • 5
  • 23
  • 42
3

When you execute pgrep sleep you are shown the PID of the sleep command, running as a child of the sudo process you created.

As a quick demo, I saved the following as subproc.py:

import subprocess
pr = subprocess.Popen(["sudo", "sleep", "100"])
print("Process spawned with PID: %s" % pr.pid)

When running this script, we can see two processes spawned:

~/$ python subproc.py
Process spawned with PID: 5296

~/$ ps all | grep sleep
    0  5296     1     sudo sleep 100
    0  5297  5296     sleep 100

You'll notice that the PID you know about in your code is the 'parent' sudo process. This is the process you should kill, but you'll need to use sudo to do it:

subprocess.check_call(["sudo", "kill", str(pr.pid)])
#You might want to wait for the process to end:
os.waitpid(pr.pid, 0)
Steve Mayne
  • 22,285
  • 4
  • 49
  • 49
  • 1
    the issue is that I can't call `pr.kill()` because `pr` was started with root privileges and my python process is not. When I try to run `pr.kill()` I get the stack trace shown in the original post. This is why I was trying the fancy stuff with `sudo kill` and what not – John Allard May 31 '18 at 07:18
  • ` Type "help", "copyright", "credits" or "license" for more information. >>> import subprocess >>> pr = subprocess.Popen(["sudo", "sleep", "100"]) >>> print("Process spawned with PID: %s" % pr.pid) Process spawned with PID: 8057 >>> pr.kill() Traceback (most recent call last): File "", line 1, in File "/usr/lib/python2.7/subprocess.py", line 1572, in kill self.send_signal(signal.SIGKILL) File "/usr/lib/python2.7/subprocess.py", line 1562, in send_signal os.kill(self.pid, sig) OSError: [Errno 1] Operation not permitted` – John Allard May 31 '18 at 07:29
  • how could it kill the sudo process without root privileges? My `python` process isn't started as root, the "sudo sleep 100" command runs okay because I have sudo-without-password privileges for my user, but the pr.kill() still fails because I'm not root -- I'm running Ubuntu 16.04 – John Allard May 31 '18 at 07:30
  • @JohnAllard Python 2.x or 3.x? – Steve Mayne May 31 '18 at 07:34
  • hmm, that makes sense but I can't get it to work. running python 2.7 – John Allard May 31 '18 at 07:40
  • that unfortunately does not work - If I run the code that you run I get something like `Process spawned with PID: 25861`, but if I then, in another shell on the same computer, do `pgrep sleep`, I see `25862`, and the `os.waitpid` call never ends. – John Allard May 31 '18 at 17:25
  • If you use `pgrep sudo` what PID do you see in the other shell? – Steve Mayne Jun 01 '18 at 08:15
1

I had the same problem with root subprocess but the answers here and here- Python how to kill root subprocess did not worked for me.

At the end the only thing that worked was:

proc = subprocess.Popen(["sudo", exe_path], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
.
.
.
os.system("sudo pkill -9 -P " + str(proc.pid))

Without the need for- preexec_fn=os.setpgrp

lior.i
  • 573
  • 1
  • 7
  • 20