세션에 제어 터미널이 있다고 가정합니다. 세션 리더가 아닌 프로세스에 의해 호출된 경우에만 자체적으로 닫히는 것이 맞습니까 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)
자녀를 생성하기 전에 호출하고, 원하는 경우 A(새) 터미널을 O_NOCTTY
할당 하지 않고 켜십시오. 터미널을 제어합니다.