[comp.unix.questions] What is the name of /dev/tty? Summary

aj@zyx.UUCP (Arndt Jonasson) (10/29/87)

In a previous posting, I asked for a way to obtain the true name of a
process's controlling terminal (the one that /dev/tty refers to). I
received various suggestions. Here is a summary:

One suggested method was that I use 'fstat(2)' on a file descriptor
open on "/dev/tty" and compare the device number with the one gotten
by calling 'fstat' for stdout (descriptor 1), to see whether they are
equal. On HP-UX and 4.2BSD, they were not. On Apollo's Domain/IX, they
were. In other words, on Apollo, 'fstat' and 'stat' don't give the
same answer for "/dev/tty", and so this can be used to find the real
name of "/dev/tty" there. Is there a defined 'correct behaviour' in
this situation?

Others suggested using 'ttyname(3)'. This call essentially does an
'fstat(2)' or 'stat(2)' for each tty in "/dev" until it finds the one
that was given to it as an argument, so when the above fails,
'ttyname' fails too.

Another suggestion was to look in the utmp entry (like 'who am i'
does). This only works if there is a utmp entry for the terminal
(which may not be the case in a window system, with one pty for each
window).  Also, if the user is logged in twice, the process can't know
which utmp entry is the right one.

Yet another, more direct approach, is to look in the process's user
area, either by forking a subprocess and use 'ptrace(2)', or by
peeking in /dev/kmem (if it's readable). On HP-UX, the former method
works; I didn't try hard enough with the latter. Example program
below. On one system where I tested 'ptrace', I discovered a kernel
bug - be careful.


It was also pointed out that the appropriate stream to output error
message to is 'stderr' (which I knew, but had somehow forgotten). The
issue is a little more complex than just writing to 'stderr', since
there is to be a stream for 'error input' as well, but as it turns
out, my program has no need for knowing the real name of /dev/tty any
longer. Picking up 'stderr', 'stdin' and 'stdout' and juggling a
little suffices.

Thanks to all who answered.

/*
   ttydev: Prints the device number of the process's controlling tty
           on stdout. Only tested on HP-UX.
	   Not lint-free (nor kludge-free). Never checks for error
	   conditions.
*/

#include <sys/types.h>
#include <sys/dir.h>
#include <signal.h>
#include <sys/param.h>
#include <sys/user.h>

#define PROGRAM		"/bin/tty"	/* Any small program will do */

main ()
{
   struct user buf;
   int *bp;
   int pid, i;

   bp = (int *) &buf;			/* We'll use this pointer to fill */
					/* in the struct user buffer */
   pid = fork ();
   if (pid == 0)
   {
      ptrace (0, 0, 0, 0);		/* Give father the right to */
					/* ptrace us */
      execl (PROGRAM, (char *) 0);	/* Get into stopped state */
					/* (I don't know any other way) */
   }
   else
   {
      sleep (1);			/* Make it probable that the */
					/* subprocess has had time to do */
					/* the ptrace */
      for (i = 0; i < sizeof (buf); i += 4)
	 *bp++ = ptrace (3, pid, i, 0);	/* Fill in the struct user buffer */
      printf ("controlling terminal device = %#x\n", buf.u_ttyd);
					/* Now, this number can be compared */
					/* with the st_rdev field returned */
					/* from an 'fstat(2)' on a file */
					/* descriptor */
   }
}

-- 
Arndt Jonasson, ZYX Sweden AB, Styrmansgatan 6, 114 54 Stockholm, Sweden
email address:	 <backbone>!mcvax!enea!!zyx!aj	=	aj@zyx.SE