Context:
I'm working on an application that needs to determine whether the
pseudo-terminal opened by a process is its controlling terminal. I'm trying to
use the tcgetpgrp()
libc/system call to achieve this.
Observations:
1) I noticed that tcgetpgrp()
returns 0 for the master pseudo-terminal in the
simple application below. I'm running Glibc 2.25 on Linux 4.10.3.
int main()
{
int master_fd = open("/dev/ptmx", O_RDWR);
grantpt(master_fd);
unlockpt(master_fd);
char *slave_pty = ptsname(master_fd);
int slave_fd = open(slave_pty, O_RDWR);
struct termios term;
tcgetattr(slave_fd, &term);
term.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
tcsetattr(slave_fd, TCSANOW, &term);
if (fork()) {
// parent
close(slave_fd);
while (1) {
pid_t pgrp = tcgetpgrp(master_fd);
// tcgetpgrp on master_fd returns 0
printf("tcgetpgrp returned: %d\n", pgrp);
sleep(1);
}
} else {
// child
close(master_fd);
while (1) {
pid_t pgrp = tcgetpgrp(slave_fd);
// tcgetpgrp on slave_fd returns -1
printf("tcgetpgrp returned: %d\n", pgrp);
sleep(1);
}
}
return 0;
}
2) The Linux man page for tcgetpgrp()
says that:
When fd refers to the controlling terminal of the calling process, the function tcgetpgrp() will return the foreground process group ID of that terminal if there is one, and some value larger than 1 that is not presently a process group ID otherwise. When fd does not refer to the controlling terminal of the calling process, -1 is returned, and errno is set appropriately.
3) The POSIX man page for tcgetpgrp()
says that:
Upon successful completion, tcgetpgrp() shall return the value of the process group ID of the foreground process associated with the terminal. Otherwise, −1 shall be returned and errno set to indicate the error.
4) Looking through the libc source, I found that the only thing the tcgetpgrp()
wrapper does
is call into the kernel using ioctl(TIOCGPGRP)
and forward the return value
to the caller.
Questions:
Unless I'm misinterpreting it, the Linux man seems to be ambiguous about what happens when the fd passed to tcgetpgrp is not the controlling terminal of the calling process. While the first sentence seems to be saying that a value > 1 will be returned, the second sentence says that -1 will be returned.
When the man page says a value > 1 will be returned that is not a process group, does it mean that I have to go through the list of all the process groups in the system to figure out if the return value refers to a valid process group?
What is the meaning of a return value of 0? Is that a valid process group?
Is there something that I'm missing in my program?
I'm still trying to trace it through the kernel sources ... but does anyone know the history behind this?
(My understanding is that the master is typically not supposed to be a controlling terminal, but the system call behavior and the explanation on the man page still appear to be weird.)
Thanks.