对于非控制进程,“ioctl(fd, TIOCNOTTY)”与“close(fd)”相同吗?

对于非控制进程,“ioctl(fd, TIOCNOTTY)”与“close(fd)”相同吗?

假设会话有一个控制终端。如果会话中非会话领导者的进程调用,它只为自己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需要为其分配一个控制终端。

相关内容