Question about fork and exec

Whenever, I run this code, ls runs but I have to press the enter key before I get my bash prompt back, any idea what is the reason? How can I make it such that after ls runs, I get my prompt back without having to press the enter key?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
	pid_t retVal = fork();
	char *arguments[] = { "ls", "-l", NULL };

	if ( retVal )
	{
		printf( "Parent PID: %d\n", getpid() );
	}
	else
	{
		printf( "Child PID: %d\n", getpid() );
		execv( "/bin/ls", arguments );
	}

	return 0;
}

Does the problem go away when you use waitpid()?
The way you use fork(), while ultimately correct, can be made clearer with a switch statement:
1
2
3
4
5
6
7
8
9
10
11
12
13
pid_t pid = fork();

switch (pid) {
    case -1:
        /* Handle the error (you can perror("fork") and exit) */
        break;
    case 0:
        /* This is the child process */
        break;
    default:
        /* This is the parent process */
        break;
}


It makes it a lot simpler.
Does the problem go away when you use waitpid()?


The problem goes away when using wait or waitpid so I assume that this problem is caused by the parent terminating first and the child becoming a zombie process? but why is it that when I do
signal( SIGCHLD, SIG_IGN )
the problem still occurs even though the man pages state that:


POSIX.1-2001 specifies that if the disposition of SIGCHLD is set to SIG_IGN or the SA_NOCLDWAIT flag is set for SIGCHLD (see sigaction(2)), then children that terminate do not become zombies and a call to wait() or waitpid() will block until all children have terminated, and then fail with errno set to ECHILD. (The original POSIX standard left the behavior of setting SIGCHLD to SIG_IGN unspecified. Note that even though the default disposition of SIGCHLD is "ignore", explicitly setting the disposition to SIG_IGN results in different treatment of zombie process children.) Linux 2.6 conforms to this specification. However, Linux 2.4 (and earlier) does not: if a wait() or waitpid() call is made while SIGCHLD is being ignored, the call behaves just as though SIGCHLD were not being ignored, that is, the call blocks until the next child terminates and then returns the process ID and status of that child.


btw, I read in andrew s. tanenbaum's book that wait is deprecated and I should use waitpid instead, is that true?

Last edited on
There is a very in-depth discussion of what one must do (and why) in order to completely disconnect a process from its controlling terminal, making it a daemon process, in Advanced Programming in the Unix Environment by Stevens. I strongly suggest you buy that book. You need to close the stdin/stdout/stderr file descriptors and become a session leader to drop the TTY. It is not hard, but it is not exactly trivial either.

This should help in the meantime:
http://codeidol.com/unix/advanced-programming-in-unix/Daemon-Processes/-13.3.-Coding-Rules/#ch13fig01
closed account (oNbk4iN6)
Perhaps you can read the busybox source code to find the answer.
You have to add a wait() or waitpid() in the parent block. This will resolve the issue. Even though the execv replaces the child image with a new one, parent has to wait for the child. Also, you might want to add few statements after execv in the child block to catch error condition. execv is not supposed to return. If it returns, an error is occured.
Topic archived. No new replies allowed.