Reed B
Reed B

Reputation: 656

Terminal Access Control issues

I am attempting to write a shell. When a foreground process is run, the forked process pipeline is given its own process group id. The terminal is then given over to this process group id (using tcsetpgrp) and the shell waits for it to terminate before giving itself terminal control once again. This works perfectly fine.

The issue that arises is when I attempt to run a background process. Again, I give all of the processes in the pipeline a single process group id but this time I do not give terminal control to this group. Upon running, the output of a given background command is output to the terminal (before it is finished executing) and the terminal gives the user back the prompt at the same time. What should have happened is that the child process that attempts to write to the terminal should get a SIGTTOU and it should stop, but this clearly doesn't happen. I verified that the forked processes all have the same process group id and that this id is different from the shell's.

Upon exiting the shell (via ctrl-c) and returning to the standard bash shell that ran it, because I did not reap the background process upon shell termination, the background process continues running (which is excepted). What is weird though is that this process continues writing output to the bash shell even though it is not the foreground process. This leads me to conclude that either this background process is not getting any SIGTTOUs because of a POSIX bug (unlikely), it is handling them (causing the default action of stopping to be ignored), or the background process is ignoring SIGTTOUs.

Is there a way to, before exec'ing a forked process, ensure that it will stop upon receiving a SIGTTOU (assuming that the exec binary does not change anything)?

Upvotes: 4

Views: 321

Answers (2)

Reed B
Reed B

Reputation: 656

The solution was to make the forked process execute the following before calling exec:

struct termios term; 
if (tcgetattr(STDIN_FILENO, &term) < 0)
        printf("ERROR\n");
    term.c_lflag = TOSTOP;
    if (tcsetattr(STDIN_FILENO,TCSANOW,&term)<0)
        printf("ERROR\n");

Upvotes: 1

rici
rici

Reputation: 241901

SIGTTOU is sent to a background process which tries to write to the terminal only if the termios flag TOSTOP is set for that terminal. By default, it is generally not set, in which case the background process can happily write to the terminal. (The TOSTOP flag does not affect read permissions. If the process tries to read, it will be sent a SIGTTIN.)

So, yes, there is something the foreground process can do: use tcsetattr to set TOSTOP

Upvotes: 3

Related Questions