Search code examples
processpipeforkexecvsocketpair

Fork doesn't load the program in execv


Below program neither load the program to child process nor prints "before" and "after". However ps aux shows the creation of processes (but without loading args0 program). I am using PIPE defined as socketpair. args0[] holds executable name for the child program, args1[] holds the name of the child program. args2 and args3 are predefined values that doesn't change and should be sent to the children as arguments. you can assume char args2[] = "10" --> user input (digit) and converted to string. I just do not understand why at least printf("before") is not printed. i read about fflush and putting \n at every printf, and i did. so everything in my program is printed correctly up to this point.

I would truly appreciate your responses.

char args2[];
char args3[];
//creating pipe
int forkk(pipes *myPipe, server_message *m, char args0[],char args1[]) {
pid_t cpid;

//pipe passed myPipe[i]
if (PIPE(myPipe->fd) == -1) {
    perror("pipe error\n");
    return -1;
}
 fork();
 cpid=getpid();
if (cpid == -1) {
    perror("fork error\n");
    return -1;
}
if (cpid) {
    close(myPipe->fd[1]);
    return 1;//closing one end of parent

} else {

    for (int i = 3; i <= myPipe->fd[0]; i++) {
        close(i);
    }

    dup2(myPipe->fd[1], 0); //redirecting stdin of child
    dup2(myPipe->fd[1], 1); //redirecting stdout of child
    close(myPipe->fd[1]);
    myPipe->cpid = cpid;
    char *newargs[3];
    newargs[0]=args1;
    newargs[1]=args2;
    newargs[2]=args3;
    printf("before\n");
    //fflush(stdout);
    execv(args0,newargs);
    printf("after execv\n");
    write(myPipe->fd[0], &m, sizeof(server_message));  //send the server_msg immediately (pass an array or msg)

}
    return 2;

}

void main(){
....
scanf("%d %d", &width, &height);
sprintf(args2,"%d",height); //converting into to string
sprintf(args3,"%d",width);
char *args0 = "./prey";
char *args1 = "prey";
int r= forkk(&myPipes[2], &msg, args0,args1);

}

I cannot post the entire code as it is long and need explanation. I am most probably having a problem with pointer assignment that i wrongly think is the correct way. Thanks a lot for any kind of help


Solution

  • (spoiler: your else branch in your poorly named forkk is never taken!)

    Read carefully documentation of execv(3). You should provide a NULL terminated array.

    The execv(), execvp(), and execvpe() functions provide an array of pointers to null-terminated strings that represent the argument list available to the new program. The first argument, by convention, should point to the filename associated with the file being executed. The array of pointers must be terminated by a null pointer.

    So you should at least code:

    char *newargs[4];
    newargs[0]=args1;
    newargs[1]=args2;
    newargs[2]=args3;
    newargs[3] = NULL; // mandatory last NULL pointer
    execv(args0,newargs);
    

    BTW, the first argument should generally be the program name. So you really want:

    char *newargs[5];
    newargs[0] = args0;
    newargs[1]=args1;
    newargs[2]=args2;
    newargs[3]=args3;
    newargs[4] = NULL; // mandatory last NULL pointer
    execv(args0,newargs);
    

    And the documentation also says

    The exec() functions return only if an error has occurred.

    So in most cases, there is no point to continue here since execv won't return if successful. However, you need to catch the failure. I recommend after your execv

    perror(arg0); // or perhaps perror("execv");
    exit(EXIT_FAILURE);
    

    Your write(myPipe->fd[0], &m, sizeof(server_message)); smells very bad. I see no point in doing that (only) when execv fails

    BTW with strace(1) you would probably have caught such an error (missing terminating NULL pointer for execv).

    At last, you always should keep the result of fork(2). See this. So replace:

     fork(); // WRONG
     cpid=getpid(); // always positive!
    

    with cpid = fork();

    Of course, you need to handle the three cases: cpid== -1 (which you forgot to handle!), cpid== 0, cpid> 0.

    Again, read carefully getpid(2):

    getpid() returns the process ID (PID) of the calling process.

    and (about getpid & getppid):

    These functions are always successful

    So getpid never returns 0 (and that is why your else branch in your forkk poorly named function, containing the execvp, never runs). See also credentials(7).

    Your void main() is also wrong. main should return an int. You generally define it as int main(int argc, char**argv) ...

    PS. Take the habit of reading carefully the documentation of every function you are using.

    Your forkk is very poorly named, too similar to the very important fork name.