Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

kill a process started with popen

After opening a pipe to a process with popen, is there a way to kill the process that has been started? (Using pclose is not what I want because that will wait for the process to finish, but I need to kill it.)

like image 482
Sophie Alpert Avatar asked Feb 13 '09 23:02

Sophie Alpert


2 Answers

Don't use popen(), write your own wrapper that does what you'd like.

It's fairly straightforward to fork(), and then replace stdin & stdout by using dup2(), and then calling exec() on your child.

That way, your parent will have the exact child PID, and you can use kill() on that.

Google search for "popen2() implementation" for some sample code on how to implement what popen() is doing. It's only a dozen or so lines long. Taken from dzone.com we can see an example that looks like this:

#define READ 0 #define WRITE 1  pid_t popen2(const char *command, int *infp, int *outfp) {     int p_stdin[2], p_stdout[2];     pid_t pid;      if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)         return -1;      pid = fork();      if (pid < 0)         return pid;     else if (pid == 0)     {         close(p_stdin[WRITE]);         dup2(p_stdin[READ], READ);         close(p_stdout[READ]);         dup2(p_stdout[WRITE], WRITE);          execl("/bin/sh", "sh", "-c", command, NULL);         perror("execl");         exit(1);     }      if (infp == NULL)         close(p_stdin[WRITE]);     else         *infp = p_stdin[WRITE];      if (outfp == NULL)         close(p_stdout[READ]);     else         *outfp = p_stdout[READ];      return pid; } 

NB: Seems like popen2() is what you want, but my distribution doesn't seem to come with this method.

like image 119
slacy Avatar answered Sep 20 '22 23:09

slacy


Here is an improved version of popen2 (credit is due to Sergey L.). The version posted by slacy does not return the PID of the process created in popen2, but the PID assigned to sh.

pid_t popen2(const char **command, int *infp, int *outfp)
{
    int p_stdin[2], p_stdout[2];
    pid_t pid;

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
        return -1;

    pid = fork();

    if (pid < 0)
        return pid;
    else if (pid == 0)
    {
        close(p_stdin[WRITE]);
        dup2(p_stdin[READ], READ);
        close(p_stdout[READ]);
        dup2(p_stdout[WRITE], WRITE);

        execvp(*command, command);
        perror("execvp");
        exit(1);
    }

    if (infp == NULL)
        close(p_stdin[WRITE]);
    else
        *infp = p_stdin[WRITE];

    if (outfp == NULL)
        close(p_stdout[READ]);
    else
        *outfp = p_stdout[READ];

    return pid;
}

The new version is to be called with

char *command[] = {"program", "arg1", "arg2", ..., NULL};
like image 27
chessweb Avatar answered Sep 21 '22 23:09

chessweb