Search code examples
csignalsposix

Does tcsetpgrp() succeds when the caller belong to a background process?


According to the POSIX specification, tcsetpgrp can cause SIGTTOU to be sent to the group of the calling process if it is a background process.

However I can't understand if in such case the foreground group is changed.

Also, if the foreground group is actually changed despite the signal generation, I wonder what happens to the session and to the terminal if the new foreground group is the one that is going to receive the SIGTTOU.


Solution

  • TL:DR:

    No the foreground group does not change. This makes sense since the signal is supposed to be sent when the process is changing a setting on the terminal -- an output operation. The signal would also not be delivered to the process (now the foreground group) if the change succeeded, because then it could get stuck without someone to send SIGCONT.

    Longer answer:

    A simple example:

    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <signal.h>
    
    
    void sig(int signo) {
        const char* msg = strsignal(signo); // XXX: Not async-signal-safe.
        write(STDOUT_FILENO, msg, strlen(msg));
        write(STDOUT_FILENO, "\n", 1);
    }
    
    int main() {
        char cntl_tty[L_ctermid];
        ctermid(cntl_tty);
    
        signal(SIGTTOU, sig);
        signal(SIGCONT, sig);
    
        int fd = open(cntl_tty, O_RDONLY);
        if (fd == -1) {
            perror("open");
            exit(1);
        }
        if (tcsetpgrp(fd, getpgrp()) == -1) {
            perror("tcsetpgrp");
        } else {
            puts("foregrounded");
        }
        return 0;
    }
    

    When this code is started as a background process and SIGTTOU is handled, this loops forever printing that the signal is received. The perror is never called, which implies that the kernel restarts the system call. Sending SIGCONT does not matter. The foregrounding never succeeds. However when foregrounding the code through the shell, "foregrounded" is printed as expected.

    When the signal disposition for SIGTTOU is changed to SIG_IGN, "foregrounded" is printed immediately.