Re: tty hangup on session leader exit

Theodore Ts'o (
Sun, 15 Oct 1995 20:41:18 -0400

From: Zoltan Hidvegi <>
Date: Tue, 10 Oct 1995 22:16:23 +0100 (MET)

Recently Theodore Ts'o posted an experimental patch which causes an
implicit vhangup() on the controlling terminal when the session
leader exits. I tried this patch with Linux-1.2.13. I have a
dial-in modem on /dev/ttyS1. It uses getty_ps with the WAITFOR
option: it watches the serial port, and when a RING message comes, it
answers the phone. When it is started, it waits for a character on
/dev/ttyS1. If I start a dial-out program uugetty receives the first
character it sends to /dev/cua1, sees that there is a lock on the
device, so it exits, and gives the terminal to the dialout program.
Unfortunately on exit, the dialout program receives the hangup. This
only happens with the patched kernel. It may be a bug in uugetty,
which should not make /dev/ttyS1 a controlling terminal. I do not
know enough about that to fix it. As far as I know, when a process
without a controlling terminal opens a tty, it automatically becomes
its controlling tty. Is there a way to avoid that?

Thanks for pointing this out!

Yes, there is a way of preventing a process without a controlling tty to
not acquire the tty as the controlling tty when it is opened. It's done
by passing the O_NOCTTY flag to open.

I'd appreciate it if you (or someone else) to look at uugetty and see if
using this flag (1) solves the problem, and (2) doesn't cause any other
problems in the code. In particular when a dialin user actually calss
the system uugetty may have to forcibly acquire the tty as its
controlling tty by using the TIOCSCTTY ioctl.

Has anyone tried out the patch to see if it causes any problems with the
other gettys that are commonly in use? In particular, mgetty? Please
send me mail if you have. Thanks!!

- Ted

P.S. Here's the patch again (actually, it's a slightly different from
the one I posted before, but it works the same way.)

RCS file: drivers/char/RCS/ChangeLog,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/ChangeLog
--- drivers/char/ChangeLog 1995/10/11 16:45:17 1.1
+++ drivers/char/ChangeLog 1995/10/11 16:59:09
@@ -1,3 +1,16 @@
+Wed Oct 11 12:45:24 1995 <>
+ * tty_io.c (disassociate_ctty): If dissassociate_ctty is called by
+ exit, perform an implicit vhangup on the tty.
+ * pty.c (pty_close): When the master pty is closed, send a hangup
+ to the slave pty.
+ (pty_open): Use the flag TTY_SLAVE_CLOSED to test to see
+ if there are any open slave ptys, instead of using
+ tty->link->count. The old method got confused if there
+ were processes that had hung-up file descriptors on the
+ slave tty.
Tue May 2 00:53:25 1995 <>

* tty_io.c (tty_set_ldisc): Wait until the output buffer is
RCS file: drivers/char/RCS/pty.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/pty.c
--- drivers/char/pty.c 1995/10/11 12:26:29 1.1
+++ drivers/char/pty.c 1995/10/11 12:26:41
@@ -77,9 +77,10 @@
- if (tty->driver.subtype == PTY_TYPE_MASTER)
+ if (tty->driver.subtype == PTY_TYPE_MASTER) {
- else {
+ set_bit(TTY_SLAVE_CLOSED, &tty->flags);
+ } else {
set_bit(TTY_SLAVE_CLOSED, &tty->link->flags);
@@ -204,7 +205,8 @@
set_bit(TTY_THROTTLED, &tty->flags);
if (filp->f_flags & O_NDELAY)
return 0;
- while (!tty->link->count && !(current->signal & ~current->blocked))
+ while (test_bit(TTY_SLAVE_CLOSED, &tty->link->flags) &&
+ !(current->signal & ~current->blocked))
if (!tty->link->count)
RCS file: drivers/char/RCS/tty_io.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/tty_io.c
--- drivers/char/tty_io.c 1995/10/11 16:52:36 1.1
+++ drivers/char/tty_io.c 1995/10/11 17:13:54
@@ -443,22 +443,28 @@
* (2) Clears the tty from being controlling the session
* (3) Clears the controlling tty for all processes in the
* session group.
+ *
+ * The argument on_exit is set to 1 if called when a process is
+ * exiting; it is 0 if called by the ioctl TIOCNOTTY.
-void disassociate_ctty(int priv)
+void disassociate_ctty(int on_exit)
struct tty_struct *tty = current->tty;
struct task_struct *p;

- if (!tty) {
+ if (tty) {
+ if (on_exit)
+ tty_vhangup(tty);
+ } else {
if (current->tty_old_pgrp) {
- kill_pg(current->tty_old_pgrp, SIGHUP, priv);
- kill_pg(current->tty_old_pgrp, SIGCONT, priv);
+ kill_pg(current->tty_old_pgrp, SIGHUP, on_exit);
+ kill_pg(current->tty_old_pgrp, SIGCONT, on_exit);
if (tty->pgrp > 0) {
- kill_pg(tty->pgrp, SIGHUP, priv);
- kill_pg(tty->pgrp, SIGCONT, priv);
+ kill_pg(tty->pgrp, SIGHUP, on_exit);
+ kill_pg(tty->pgrp, SIGCONT, on_exit);

current->tty_old_pgrp = 0;