exit() status does not act accordingly

61 Views Asked by At

So I have a program that calls execvp() as seen below

void ext_com(char* buffer){
    char **command;
    pid_t child_pid;
    command = get_input(buffer);

    child_pid = fork();
    if(child_pid<0){
        perror("failed");
        exit(1);
    }
    if (!child_pid) {
            /* Never returns if the call is successful */
        int ret= execvp(command[0], command);//call ls
        if(ret == -1){
            printf("bad command\n");
            last_exit = ret;
            exit(ret);
        }

    } else {
        int stat_loc;
        run_pid = child_pid;
        waitpid(child_pid, &stat_loc, WUNTRACED) &255;
        last_exit=stat_loc;
    }
    free(command);
}

Which has last_exit as a global int, last_exit status is not 0 when I run the command correctly nor is it -1 when I run a bad command, it also is not 1 when I run some non existent flag such as ls 444. It sometimes does return a number between 1 and 255 however is this behaviour wrong (apart from returning non zero when execvp() is called correctly), and how do I fix it.

Thank you

1

There are 1 best solutions below

0
John Bollinger On

Regarding fork()

Which has last_exit as a global int,

When you fork() a child process, the child gets a copy of its parent's memory. Except to the extent that you leverage a shared-memory mechanism, the child cannot communicate with the parent via variables, no matter their scope or linkage.

In particular, in this code fragment ...

            last_exit = ret;
            exit(ret);

... the assignment to last_exit is useless, because the (only) process it affects terminates immediately afterward.

Regarding execvp()

it also is not 1 when I run some non existent flag such as ls 444.

Whether the program's arguments are valid is a matter that the program itself decides. It doesn't get to the point of making such evaluations unless it is successfully launched.

execvp()'s return value is not associated with the exit status or any other behavior of the program it launches. It does not wait for that program to complete, so that that information is even available to it. execvp() does not return if it is able to launch the specified program at all, and it fails (returning -1) only if it cannot do so. Note that this means you never have to test its return value -- if the function returns at all then you know without checking that the return value was -1. Failures typically are the result of the specified program not being found, not being accessible for read and execution, or not having a recognized executable format.

If you want to know about that program's exit status then the parent process (the one that fork()ed the child in which the execvp() call was performed) must wait() or waitpid() for it, and use the information provided by that function.

Regarding exit() and waitpid()

Although exit() accepts an int argument, the exit status available from the wait() family of functions (or from a shell) conveys only 8 bits of exit-status information. In particular, the argument to exit() is not conveyed in whole to the parent via waitpid(). The exit status available that way (in the event that the program terminates normally) is a number between 0 and 255.

The status code provided by the wait-family functions conveys multiple pieces of information, including

  • whether the process terminated normally, and if so, an 8-bit exit status
  • whether the process was terminated by a signal, and if so, which signal and whether the process dumped core
  • whether the process stopped (as opposed to terminating), and if so, what signal caused it to do so
  • whether (wait returned because) the process was continued from a stopped state

You should use the macros defined for extracting these details from the status code (see the documentation for wait() et al.). If you want to determine the child's exit status then you should first use WIFEXITED(stat_loc) to verify that it terminated normally at all. Supposing that it did, WEXITSTATUS(stat_loc) will give you the exit status, which, again, has only 8 significant bits. If the child terminates by calling exit(-1) then you should expect the status reported via waitpid() to be 255.