Search code examples
clinuxpid

Finding the PID of a process launched by exec() or system() in C program


I need to retrieve the PID of a process started by exec() or system(). I read on the subject and did my research, but I don't understand the suggestion of using fork() to do so.

Let's say I have the following code:

int pid = fork();

if (pid < 0 ) {
exit(1);
} else if (pid == 0 ) {
execlp("ls", "-a", NULL);
} else {
wait(0)
}

How to get the pid of the process started by execlp (or by system() if system was used instead)? I don't need to kill the process, I just need the PID to retrieve stats about it.


Solution

  • The exec* family of functions do not create new processes, instead they replace the execution context of the process they are called from, with the execution context of their target executable. The PID is maintained when this occurs.

    #include <unistd.h>
    #include <stdio.h>
    
    int main(void) {
        /* Normal execution */
        puts("Hello");
    
        /* Our programs contents get "replaced" by ls */
        execlp("ls", "ls", "-l", NULL);
    
        /* We never get here */
        puts("World!");
    }
    

    fork, on the other hand, creates a new child process, which of course has its own PID. This child process carries on executing a copy of the same execution context it was spawned from; you can consider the execution to be "split" as soon as fork is called. fork returns 0 in the child process, and the PID of the child process in the parent (our original process).

    The idea is to fork, and then use exec* to replace the execution context of the child process.

    #include <unistd.h>
    #include <stdio.h>
    
    int main(void) {
        pid_t pid;
        /* Normal execution */
        puts("Hello");
    
        /* execution "splits" */
        pid = fork();
        if (pid == 0) {
            /* Our child's execution context get "replaced" by ls */
            execlp("ls", "ls", "-l", NULL);
        } else {
            /* still in the parent */
            printf("Child PID is: %d\n", (int) pid);
        }
    
        /* We only get here in the parent */
        puts("World!");
    }
    

    system is a wrapper around fork, exec* and and waitpid that blocks the calling process until the child process finishes its execution. The child's PID is not reported, because by the time parent can "act" again, the PID of the child is meaningless.


    Error handling omitted for clarity of examples, but you should handle errors for fork, exec*, and wait* functions.