Search code examples
cerror-handlingexitexecvp

execvp() - exit() return value in function


I have been fighting with the following concept lately and I am still unable to understand it. I have this block of code

int foo(int f){
    int fail = 10;  //some random initialization value
    int status;
    pid_t child_pid;
    child_pid = fork();

    if(child_pid == 0) {
        /* This is done by the child process. */

        if (execvp(tokens2[0], tokens2)<0){
            fail =1;
            perror(tokens2[0]); 
            exit(1);
        }
    }else if(child_pid<0){
        perror("Fork failed");
        exit(1);
    } else {
        waitpid(child_pid, &status, WUNTRACED);
    }

    //handle execvp error return value
    if (fail == 1){
        return -1;
    }else{
        return 0;
    }
    
}

It does not make a lot of sense (don't mind tokens2[] array, it is declared properly and it works just fine) because it is on an abstract form in order for it to be audible and easy to understand. The question is: what is the output of function foo? This is what I have come to get so far:

1)If execvp succeeds, it does not return any value. If it fails it returns -1 (I think this return value does not have to do anything with my foo function).

2)exit(1) kills the child process and returns the control flow to the parent.

In my understanding, if execvp succeeds, the foo should return -1(according to variable fail), if it fails it should return 0, but that is not what my printf checks on the main function show. Actually the outcome is always the opposite of what I expect.

PS: I found something about execvp error handling using the good old shelf-pipe trick but it is too noisy for me. I want a simpler way to handle the error.


Solution

  • The question is: what is the output of function foo?

    You seem to be asking what is the return value of foo(). "Output" usually refers to data written to the terminal or an external file. But the question remains: in which process? Supposing that the fork() succeeds, you then have two virtually identical processes, both executing foo().

    1)If execvp succeeds, it does not return any value.
    

    If execvp() succeeds, it does not return at all.

    If it fails it returns -1 (I think this return value does not have to do anything with my foo function).

    Yes. Only your child process executes execvp(), however, and in the event that it returns, the process ends up calling exit().

    2)exit(1) kills the child process and returns the control flow to the parent.
    

    That terminates the process before it ever returns from foo(), so in the child process foo() never returns, whether execvp succeeds or not. Control does not return to the parent. Forking a process is not at all the same as calling a function. The parent can learn about the child's exit code via the waitpid() call it makes.

    In the parent, if the fork() fails then that process, too, calls exit() and therefore does not return from foo(). Supposing that the fork() succeeds, on the other hand, the parent waits until the child terminates. The child is a separate process, with its own copy of all the variables, so whatever it may have done to its copy of fail has no effect on the parent. That is, forking a child process is not like launching a thread in the same process, either.

    Since the parent does not itself modify fail, it still has its initial value, 10, if it reaches

        if (fail == 1){
    

    10 != 1, so if foo() does return then it returns 0.