假设会话有一个控制终端。如果会话中非会话领导者的进程调用,它只为自己ioctl(fd, TIOCNOTTY)
关闭 是否正确?fd
与 一样吗close(fd)
?
谢谢。
答案1
它不会关闭文件描述符,只是放弃进程的控制终端。由于该进程不是会话领导者,因此不会发生任何其他事情。我的 Linux 机器上的手册页就是这样描述的。尽管文档是您应该依赖的内容,因为测试实现并不能证明它在所有情况下都有效,但如果您可以接受糟糕的代码,那么尝试是非常简单的:
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define ERR(x) \
do { \
perror(x); \
return; \
} while (0)
void
main(void)
{
/* create a new session */
pid_t leader = setsid();
if (leader == (pid_t) -1) {
/* EPERM means we are already a process group leader */
if (errno != EPERM)
ERR("setsid");
}
int pid = fork();
if (pid < 0)
ERR("fork");
if (pid > 0) {
/* super-lazy clean-up and sync in one */
wait(NULL);
return;
}
pid_t parent = getppid();
pid_t child = getpid();
printf("Child PID: %lld\n", (long long) child);
pid = fork();
if (pid < 0)
ERR("fork");
if (pid > 0) {
int fd = open(ctermid(NULL), O_RDWR);
if (fd < 0)
ERR("open");
/* middle child gives up controlling terminal */
if (ioctl(fd, TIOCNOTTY) < 0) {
close(fd);
ERR("ioctl");
}
close(fd);
printf("Child gave up ctty, now waiting\n");
/* super-lazy clean-up and sync in one */
wait(NULL);
return;
}
/* even lazier sync */
sleep(1);
pid_t grandchild = getpid();
printf("Grandchild PID: %lld\n", (long long) grandchild);
char cmd[256] = {0};
snprintf(cmd, 256,
"head -c 60 /proc/%lld/stat /proc/%lld/stat /proc/%lld/stat",
(long long) parent, (long long) child, (long long) grandchild);
system(cmd);
/* the output of the command will not end with newline */
printf("\n");
}
运行此显示:
Child PID: 293750
Child gave up ctty, now waiting
Grandchild PID: 293751
==> /proc/293749/stat <==
293749 (test) S 290544 293749 290544 34822 293749 4210688 10
==> /proc/293750/stat <==
293750 (test) S 293749 293749 290544 0 -1 4210752 40 0 0 0 0
==> /proc/293751/stat <==
293751 (test) S 293750 293749 290544 34822 293749 4210752 32
如果您查看输出,第七个字段是tty_nr
来自proc(5)
手册页,它显示只有放弃其控制终端的子进程才丢失它(tty_nr = 0
),而不是其他进程。
综上所述,我认为除了用于研究/学习目的之外,不应将其用于任何其他地方,因为通常您会setsid(2)
在生成任何子级之前调用,并且如果这是您想要的,请打开一个(新)终端,而不O_NOCTTY
需要为其分配一个控制终端。