1

I have a class which can start and close a process. However it seems not to close the process.

My python code, there are other methods but they work fine.:

class KismetInstance:
    """Creates a kismet_server instance"""

    def __init__(self, value=False):
        logging.basicConfig(format='%(asctime)-15s::: %(message)s')
        self.logger = logging.getLogger('kismet_instance')
        self.example = value

    def __create_kismet_instance__(self):
        """
        Create a kismet_server subprocess.
        :return:
        """
        shell = ['sudo', '/usr/local/bin/kismet_server']
        self.logger.debug('Attempting to run: %s', " ".join(shell))
        self.kismet = Popen(shell, stdin=PIPE, stdout=PIPE, stderr=PIPE, cwd=r'./logs', preexec_fn=os.setsid)


    def __destroy_kismet_instance__(self):
        """
        Kill the subprocess
        :return:
        """
        os.killpg(os.getpgid(self.kismet.pid), 15)

It can create the subprocess fine. But I get this error when I try to kill (no sudo)

OSError: [Errno 1] Operation not permitted

And if I run with sudo, the process is still running afterwards.

pi@raspberrypi ~/project $ ps -A | grep 'kismet'
 2912 ?        00:00:00 kismet_server
jnd
  • 754
  • 9
  • 20
  • Because the subprocess is created with "sudo" and when you are trying to kill it is not send from "sudo" or "root" user. Try running the program from "root" user and it should work.Or if you can run /usr/local/bin/kismet_server under non-root account, then also it will work. – Nipun Talukdar May 15 '15 at 02:56
  • You could also try `os.killpg(os.getpgid(self.kismet.pid), 2)` for `SIGINT` in case `kismet` is intercepting `SIGTERM`. – Martin Konecny May 15 '15 at 03:06
  • @NipunTalukdar If you read the later half, I have tried running the program as `sudo` and it doesn't kill it. – jnd May 15 '15 at 03:37
  • @MartinKonecny I tried SIGINT and doesn't close either. – jnd May 15 '15 at 03:38
  • You could try Signal `9` `SIGKILL` which the process cannot intercept, but this will cause the program to shutdown uncleanly, and can cause data corruption. You should only do this to test whether your signal is being sent properly. – Martin Konecny May 15 '15 at 03:40
  • @MartinKonecny, no that doesn't seem to kill it either... which makes absolutely no sense – jnd May 15 '15 at 04:09
  • Can you compare the pid before and after you kill it? Is it possible it is respawning? Also won't hurt to try `os.kill(self.kismet.pid, 9)` – Martin Konecny May 15 '15 at 04:16
  • @MartinKonecny I tried just os.kill and seeing the PID. and they aren't the same.. – jnd May 15 '15 at 05:13
  • So there's your problem. You are successfully killing the process, but it's coming back. – Martin Konecny May 15 '15 at 05:14
  • So how can I kill it.... – jnd May 15 '15 at 05:19
  • I see two issues that are solved successfully: 1. permission error 2. killing of the initial subprocess -- update your question to reflect it. Remaining issues are `kismet_server`-specific: does it daemonize itself? Does it spawn an independent supervisor process that restarts it if it is killed? Meta: your questions can be more useful if you limit them to a single issue per question (you may always provide a link for context). – jfs May 16 '15 at 17:15

1 Answers1

1

I managed to fix this. Turns out the subprocess was respawning itself creating something weird which prevented python from keeping track of it.

So I had to do this to fix it, However this is not the most elegant solution, and rather dangerouddangerous.

Be careful if you use this, because if you enter a term more broad than mine ('kismet') then you could kill a lot of processes on your system.

def __destroy_kismet_instance__(self):
        """
        Kill the subprocess
        :return:
        """
        sig = signal.SIGKILL # What signal to send
        os.killpg(os.getpgid(self.kismet.pid), sig) # Kill one of them
        p_list = subprocess.Popen(['ps', '-A'], stdout=subprocess.PIPE) # Get All processes on system
        out, err = p_list.communicate()
        for line in out.splitlines(): # For each line (or process)
            if 'kismet' in line: # if 'kismet' appears in its name
                pid = int(line.split(None, 1)[0]) # Get the process ID
                self.logger.debug("Found: %d", pid)
                os.killpg(os.getpgid(pid), sig) # Kill the process
jnd
  • 754
  • 9
  • 20
  • Instead of nuking any process group that contains a process with executable name that contains `'kismet'` (you could [use `psutil`](http://stackoverflow.com/a/4229404/4279)), consider reading `kismet_server` docs/source to find out whether it has a command-line argument that forces it to run in a foreground (without daemonizing and/or spawning a supervisor process) and thus could be terminated simply using `self.kismet.terminate()` or `os.pgkill(self.kismet.pid, SIGTERM)`. Another alternative: perhaps check that your code calls `.__create_kismet_instance__()` method exactly once per instance. – jfs May 18 '15 at 07:16