How do I get tcsetpgrp() to work in C?

后端 未结 3 469
情歌与酒
情歌与酒 2020-12-03 11:04

I\'m trying to give a child process (via fork()) foreground access to the terminal.

After I fork(), I run the following code in the child p

3条回答
  •  清歌不尽
    2020-12-03 11:34

    It's the parent rather than child who should invoke tcsetpgrp(). After setpgid() call, the child becomes a background process. A valid case is the foreground group gives up its permission, let another background group become foreground and itself background. A process in background group can't grab controlling terminal. Example code maybe look like:

    /* perror_act.h */
    #ifndef PERROR_ACT_H
    #define PERROR_ACT_H
    
    #define PERROR_ACT(rtn, act) do { \
        perror(rtn);\
        act; \
    } while (0)
    
    #define PERROR_EXIT1(rtn) PERROR_ACT(rtn, exit(1))
    #define PERROR_RETN1(rtn) PERROR_ACT(rtn, return -1)
    
    #endif
    
    /* invnano.c */
    #include 
    #include 
    #include 
    #include 
    #include "perror_act.h"
    
    void sig_chld(int chld)
    {
        exit(0);
    }
    
    int main(void)
    {
        pid_t child;
        int p2c[2];
        struct sigaction sa = {.sa_handler = sig_chld};
    
        if (sigaction(SIGCHLD, &sa, NULL))
            PERROR_EXIT1("sigaction");
        if (pipe(p2c))
            PERROR_EXIT1("pipe");
        if ((child = fork()) < 0)
            PERROR_EXIT1("fork");
        if (child == 0) {
            char buff;
            size_t nread;
            if (close(p2c[1])) /* We must make sure this fd is closed. The reason is explained in following comments. */
                            PERROR_EXIT1("close");
            if ((nread = read(p2c[0], &buff, 1)) < 0) /* Just to receive a message from parent indicating its work is done. Content is not important.  */
                PERROR_EXIT1("read");
            if (nread == 0) /* When all the write ends of a pipe are closed, a read() to the read end of this pipe will get a return value of 0. We've closed the child's write end so if 0 as returned, we can sure the parent have exited because of error. */
                exit(1);
            close(p2c[0]);
            execlp("nano", "nano", (char *) 0);
            PERROR_EXIT1("execlp");
        } else {
            if (close(p2c[0]))
                PERROR_EXIT1("close");
            if (setpgid(child, child))
                PERROR_EXIT1("setpgid");
            if (tcsetpgrp(STDIN_FILENO, child))
                PERROR_EXIT1("tcsetpgrp");
            if (write(p2c[1], &child, 1) != 1) /* If all the read ends of a pipe are close, a write() to the write end of this pipe will let the calling process receive a SIGPIPE whose default deposition is to terminate. */
                PERROR_EXIT1("write");
            while (1) /* If parent exit here, login shell will see the news and grab the controlling terminal */
                pause();
        }
        return 0;
    }
    

提交回复
热议问题