1

I am writing a Linux application. What happens if I call fork() and then run an application that takes console input? Consider the code below:

int process_id = fork();

if (process_id != 0) {
    /* this is the parent process */
    error = execv("../my_other_app", "parameter1", NULL);
    if (error < 0) {
        printf("error!");
    }
} else {
    /* this is the child process. Wait for my_other_app to set up */
    sleep(3);
    /* now continue */
}

printf("########## press ENTER to stop ##########\n");
getchar();

exit(0);

The thing is, my_other_app also has a press ENTER to stop message. So when I do the getchar() call, which application is reading it? The main application or the my_other_app that I launched with execv?

EDIT: It appears through testing that my_other_app takes priority over the console. Does this happen every time? Is there a way to make sure the console is instead owned by the main process?

boltup_im_coding
  • 6,345
  • 6
  • 40
  • 52

3 Answers3

4

Both processes have their stdin connected to the terminal (or whatever the original process's stdin was connected to). This doesn't change when you call execv. If both processes try to read from stdin at the same time, it's unpredictable which one will get the input.

If you want to disconnect the child process from the terminal, you should call setsid() before calling execv to put it in its own session and remove its controlling terminal.

Barmar
  • 741,623
  • 53
  • 500
  • 612
2

fork() calls dup() on every single file descriptor. In effect you get a copy of all the files in the child. Some "processes" (via hooks) may detect the fork() and close some file descriptors, but that's very unlikely. Some files may be opened with a specific flag saying that it should be closed on execv(). stdin is not one of them.

You have two solutions, just close stdin in the child process, but that can cause problems, or replace it with /dev/null.

freopen("/dev/null", "r", stdin);

You can do the same for stdout and stderr.


Adding a 'wait forever' at the end of the program (since you cannot do getchar() anymore):

for(;;) sleep(0x7FFFFFFF); // for(;;) is probably superfluous

That's probably the simplest way, there are many others such as using select() on a file you know will never change...

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
  • Would closing stdout on the child process stop it from dumping output to the console? that would actually be fantastic. – boltup_im_coding Feb 01 '14 at 06:16
  • 1
    Do a `freopen("/dev/null", "w", stdout)` for stdout. Then no more dumping. The problem with just closing is that if you have a `printf("something\n");` then it is not unlikely going to crash because FILE * is now invalid. – Alexis Wilke Feb 01 '14 at 07:43
  • Looks like `freopen("/dev/null", "r", stdin);` does not quite work for me, because when reading from `/dev/null` it signals EOF immediately. My program has a `getchar()` call that will terminate it, and it seems that is executed immediately. How can I have it ignore keyboard input and let me kill it by PID manually? – boltup_im_coding Feb 04 '14 at 18:26
  • I made an update to my answer. A simple sleep() of a number so large that you'd anyway have to reboot your computer or it will die of old age before the process wakes up again. – Alexis Wilke Feb 04 '14 at 18:52
  • Ah, bummer. I cannot modify the behavior of this program. The `getchar()` is expected in other uses to terminate it. – boltup_im_coding Feb 04 '14 at 18:54
  • Oh! I see... In that case you could open stdin using a pipe to which you write nothing. That's a bit more work. `man 2 pipe` should get you the necessary info though. – Alexis Wilke Feb 04 '14 at 19:24
  • This question has an answer explaining how to do that: http://stackoverflow.com/questions/17508626/piping-for-input-output – Alexis Wilke Feb 04 '14 at 19:33
1

I think it APPEARS as though my_other_app has priority since the other child process has sleep(3).

Dinesh
  • 2,194
  • 3
  • 30
  • 52