非制御プロセスの「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

出力を見ると、7番目のフィールドはマニュアルページtty_nrにあり、proc(5)制御端末を放棄する子プロセスだけがその端末を失い()、tty_nr = 0他のプロセスは失われることを示しています。

つまり、研究/学習目的以外の他の用途には使用してはならないと思います。通常setsid(2)、子供を作成する前に呼び出し、必要に応じてA(新しい)端末を割り当てずにオンにO_NOCTTYします。端末を制御します。

おすすめ記事