child process created using execl is not accepting any input

398 Views Asked by At

I wrote a program which is first replicating the current process (using fork()) and then I m creating a child process using execl().

Now the problem is that the child process is unable to accept any input.

The child.c program :

#include<stdio.h>
#include<unistd.h>

int main(int argc, char *argv[])
{
    int p, pp;
    int a;
    char dummy;
    printf("\n enter value of a \n");
    //fflush(0); // was using to clean STDIN, STDOUT
    //fflush(1);
    scanf("%c",&dummy); // simply using to accept any new line character if present any.
    scanf("%c",&dummy); // simply using to accept any new line character if present any.
    scanf("%d",&a);
    p = getpid();
    pp = getppid();
    printf("\nI m child with pid %d and ppid %d \n", p, pp);
    char *msg = argv[1];
    printf("\n Message from parent is %s \n",msg);
    printf("\n The value of a is %d ",a);
    return 0;
}

I m compiling my child.c with the command: gcc child.c -o child to generate the object file with name child which I m using in my parent.c file

My parent.c program :

#include<stdio.h>
#include<unistd.h>

int main()
{
    int p, pp;
    p = getpid();
    pp = getppid();
    printf("\nI m parent with pid %d and ppid %d \n", p, pp);
    int b = fork();
    if (b == 0)
    {
        sleep(1);// for orphan state
        execl("./child", "child", "hello", 0);
    }
    else
    {
        printf("\nBye\n");
    }
    return 0;
}

I have tried running the program in both the orphan state and zombie state but in both the cases, the input is not getting accepted in the child process.

When I run this ./a.out of parent program the I get the following output:

I m parent with pid 6801 and ppid 4136

Bye [aupadhyay@localhost practice]$ enter value of a

I m child with pid 6802 and ppid 1

Message from parent is hello

The value of a is 0

The console is not accepting any input rather it is printing the default value of a.

Any information/help on how to get input in child process will be appreciated.

1

There are 1 best solutions below

4
On BEST ANSWER

Note: answer significantly overhauled in light of edits and comments by @Gilles.

Although I can duplicate the behavior you describe, I can also feed input to the child via I/O redirection:

./parent <<EOF


12345
EOF

... resulting in:

I m parent with pid 4430 and ppid 2515

Bye

$

enter value of a

I m child with pid 4431 and ppid 1

Message from parent is hello

The value of a is 12345

Note that the data redirected into the parent's standard input are successfully read and echoed by the child, so the problem is not that the child cannot accept input. That under some conditions it does not either wait for or successfully read input, but instead continues past the read attempts, can only be explained by the scanf() calls failing under those conditions.

The most plausible explanation for such failures is that the process group has been moved to the background by the time the reads are attempted. Ordinarily, a background process that attempts to read from its controlling terminal will cause its whole process group to stop (not terminate). In your case, however, the process group is orphaned: no process in the group has a parent inside the session but outside the group. In this and a few other special cases, a background process's read()s from its controlling terminal, such as those underlying your scanf() calls, are required to fail, setting errno to EIO.

In that event, scanf in turn returns EOF to indicate an error, leaving errno set to EIO. Test the return value of scanf and call perror to observe this. The read failures are a sensible behavior, as they facilitate the processes in the orphaned group running to completion and terminating, instead of hanging, or the OS summarily killing them. POSIX's objective here seems to be to provide graceful handling for process groups that are orphaned by termination of a parent that is a job-control shell, leaving no process with the expectation of or responsibility to restart the process group.

Yours is not the case that POSIX seems intent to cater to, but the specifications also support the observed behavior: the shell shifting the foreground process group into the background when its leader dies, yet (it seems) not putting it under job control as a background job. As far as I can determine, POSIX does not mandate that the shell exhibit such behavior, but neither does it require otherwise. The result is an orphaned process group in similar circumstances to those conceived by POSIX, and equally well served by the special provisions for orphaned process groups.

If you want the child to retain full access to the parent's controlling terminal then you should ensure that the parent does not terminate before the child does. If the parent has nothing else to do in the meantime, the appropriate way to ensure that the child terminates first is for the parent to wait() or waitpid() for it:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
    int p, pp;
    p = getpid();
    pp = getppid();
    printf("\nI m parent with pid %d and ppid %d \n", p, pp);
    int b = fork();
    if (b == 0)
    {
        execl("./child", "child", "hello", 0);
    }
    else
    {
        printf("\nBye\n");
        wait(NULL);
    }
    return 0;
}