Below is the source of a program that executes cat
:
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
pid_t pid = fork();
if (!pid) {
// create a new process group
setpgid(0, 0);
execlp("cat", "cat", NULL);
}
pid_t reaped = wait(NULL);
printf("reaped PID = %d\n", (int) reaped);
return 0;
}
Note the call to setpgid(0, 0)
.
When run in a shell (either sh
or bash
), I expected:
- the parent to spawn a child process of
cat
, and - the child to start interacting with the terminal.
However, what happens is:
- the parent spawns
cat
with no problem, but - the child is stopped (with process state code
T
inps
), and - the child accepts no input from the terminal, and
- the child does not respond to any of
SIGINT
,SIGSTOP
orSIGQUIT
, only to be killed bySIGKILL
.
When the call to setpgid()
is commented out, everything is as expected.
I suspect the behavior is caused by:
- the child
cat
is trying to read stdin and is waiting (thus stopped), but - the input to the terminal is first passed to
bash
, and then to the program above, however not to thecat
, possibly becausebash
does not recognize its grandchildren,cat
, because of its different process group.
Of course, removing setpgid()
call is the simplest solution. Unfortunately there are some reasons; mainly to intercept some signals (such as SIGINT or SIGSTOP) in the parent. In other words, a <Ctrl-C>
should not kill the cat
but somehow signal the program above. (There are no signal handlers in the program above, yes, for illustrative purpose.)
I'd like to ask:
- Is this correct?
- Whether it is or not, how can I have
cat
to receive inputs from stdin?