[comp.unix.wizards] Getting tty name without using ttyname

her@compel.UUCP (Helge Egelund Rasmussen) (02/15/90)

I need to write a replacement for the SYSV release 3 ttyname(3) function.
The reason is that the ttyname call is veeeery slow on our machine 
(5 to 10 seconds).

As far as I can see by prof'ing a test program, ttyname calls stat(2)
on the files in /dev until it finds the correct tty (its doing about 300
stat calls!).

Presumably ttyname is comparing the 'st_rdev' field in the stat structure with 
something identifying the current tty.

I'd like to know what the ttyname call really is doing.

I need the call to identify the terminal used by the current process 
(for logging purposes), so it's not enough to get "/dev/tty" as answer..

Any help would be appreciated.

Helge

---
Helge E. Rasmussen  .  PHONE + 45 31 37 11 00  .  E-mail:  her@compel.dk
Compel A/S          .  FAX   + 45 31 37 06 44  . 
Copenhagen, Denmark

brnstnd@stealth.acf.nyu.edu (02/16/90)

In article <673@compel.UUCP> her@compel.UUCP (Helge Egelund Rasmussen) writes:
> I need to write a replacement for the SYSV release 3 ttyname(3) function.

ttyname() takes a file descriptor argument and (as you observed) searches
through /dev for a tty (or just any file? I haven't checked) referencing
the same inode. If you have a lot of non-tty entries in /dev, you could
write a much faster version that only looks at files beginning with tty.
Of course, to avoid confusion you shouldn't call this ttyname().

Use directory(3), stat(2). (The whole thing is a kludge.)

---Dan

dold@mitisft.Convergent.COM (Clarence Dold) (02/16/90)

in article <673@compel.UUCP>, her@compel.UUCP (Helge Egelund Rasmussen) says:

> I need to write a replacement for the SYSV release 3 ttyname(3) function.
> As far as I can see by prof'ing a test program, ttyname calls stat(2)
> on the files in /dev until it finds the correct tty (its doing about 300
> stat calls!).

As a first shot, try fstat(0, buf), looking at buf.st_rdev to get your 
minor device number.  Then do a stat of /dev/ttyXXX where XXX is the minor
device number of your tty, and see if buf.st_ino matches.

This only works if the minor device lines up with the port number, but 
it probably does.

If this fails, then call ttyname().
-- 
---
Clarence A Dold - dold@tsmiti.Convergent.COM            (408) 435-5293
               ...pyramid!ctnews!tsmiti!dold        FAX (408) 435-3105
               P.O.Box 6685, San Jose, CA 95150-6685         MS#10-007

cpcahil@virtech.uucp (Conor P. Cahill) (02/16/90)

In article <673@compel.UUCP> her@compel.UUCP (Helge Egelund Rasmussen) writes:
>As far as I can see by prof'ing a test program, ttyname calls stat(2)
>on the files in /dev until it finds the correct tty (its doing about 300
>stat calls!).

ttyname() does a fstat on the file descriptor that it is passed and then
looks throught the /dev directory (using the stat()s you mentioned) looking
for a matching entry.

If you really need the performance gain, you could make a new directory say
/dev/only_ttys which contains links to all the tty devices in /dev.  You
could then modify ttyname() (or write your own) that would look through
this directory instead (of course it would have to drop off the "only_ttys/"
in order to be compatible with standard ttyname().


Another, slightly more dangerous, but more compatible method would be to:

	put your system into single user mode

	make a copy of the entire /dev directory hierarchy in another directory

	mv /dev /dev.old

	mkdir /dev

	move tty devices from /dev.old to /dev

	move rest of the stuff back to /dev

This solves the problem by placing all the tty devices first in the directory
so they should be found sooner.
-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

jfh@rpp386.cactus.org (John F. Haugh II) (02/16/90)

In article <15137:00:09:24@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes:
>In article <673@compel.UUCP> her@compel.UUCP (Helge Egelund Rasmussen) writes:
>> I need to write a replacement for the SYSV release 3 ttyname(3) function.
>
>ttyname() takes a file descriptor argument and (as you observed) searches
>through /dev for a tty (or just any file? I haven't checked) referencing
>the same inode. If you have a lot of non-tty entries in /dev, you could
>write a much faster version that only looks at files beginning with tty.
>Of course, to avoid confusion you shouldn't call this ttyname().
>
>Use directory(3), stat(2). (The whole thing is a kludge.)

How about using DBM?  Write a program which takes filenames as arguments
and saves the names away using the device-inode as the index.  To find the
name of your tty you would just make a request of the database.  You could
then feed all of the tty device names to this program at boot-time to
create the index.
-- 
John F. Haugh II                             UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832                           Domain: jfh@rpp386.cactus.org

lwall@jpl-devvax.JPL.NASA.GOV (Larry Wall) (02/17/90)

In article <17954@rpp386.cactus.org> jfh@rpp386.cactus.org (John F. Haugh II) writes:
: How about using DBM?  Write a program which takes filenames as arguments
: and saves the names away using the device-inode as the index.  To find the
: name of your tty you would just make a request of the database.  You could
: then feed all of the tty device names to this program at boot-time to
: create the index.

You mean a little program like this?

#!/usr/bin/perl
chdir '/dev' || die "Can't cd to /dev: $!";
unlink 'devices.dir', 'devices.pag';
dbmopen(DEV,'devices',0644) || die "Can't dbmopen /dev/devices: $!";
foreach $file (grep( -c $_ || -b _, <*>)) {
    ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev) = stat $file;
    $DEV{sprintf("%d,%d", int($rdev / 256), $rdev % 256)} = $file;
}

It could also be done with makedbm, if you've got it.  In fact, you could
write makedbm in perl if you don't have it...

In fact, here's a version that does everything but the YP claptrap.

#!/usr/bin/perl

$usage = <<EOM;
Usage:
    $0 infile outfile
    $0 -u dbmfile
EOM

for ($_ = shift; /^-\w/; $_ = shift) {
    /^-u/ && (++$undo,next);
    die "Unrecognized switch: $_\n$usage";
}
unshift(@ARGV,$_);

$dbmfile = pop(@ARGV);

$#ARGV == 0 - $undo || die $usage;

if ($undo) {
    -f "$dbmfile.dir" || die "Can't find $dbmfile\n";
    -f "$dbmfile.pag" || die "Can't find $dbmfile\n";
    dbmopen(DBM,$dbmfile,0644) || die "Can't open $dbmfile: $!\n";
    while (($key,$val) = each(%DBM)) {
	print $key," ",$val,"\n";
    }
}
else {
    unlink "$dbmfile.dir", "$dbmfile.pag";
    dbmopen(DBM,$dbmfile,0644) || die "Can't create $dbmfile: $!";
    while (<>) {
	chop;
	while (/\\$/) {
	    chop;
	    $_ .= <>;
	    chop;
	}
	($key,$val) = split(/\s/,$_,2);
	$DBM{$key} = $val;
    }
}

You'd use it like this:
	ls -l /dev | \
	sed -e '/^[^cb]/d' \
	    -e 's/.*\([0-9][0-9]*,\) *\([0-9][0-9]*\).* \(.*\)/\1\2 \3/' | \
	makedbm - /dev/devices

To list it out:
	makedbm -u /dev/devices

Larry Wall
lwall@jpl-devvax.jpl.nasa.gov

chris@mimsy.umd.edu (Chris Torek) (02/18/90)

In article <1990Feb16.040357.2555@virtech.uucp> cpcahil@virtech.uucp
(Conor P. Cahill) writes:
>If you really need the performance gain, you could make a new directory say
>/dev/only_ttys which contains links to all the tty devices in /dev.

This ought not to be necessary.  ttyname() should only stat the right
file anyway, because it should be (as the 4.3BSD one is) written as

	... fstat the file descriptor ...
	for (all entries in the device directory)
		if (this entry has the right inode number &&
		    stat works &&
		    device fields match)
			return (name);
	return (not found);

Typically ttyname() makes 1 fstat() call, 1 open() call, 1 or 2
read() or getdirentries() calls, 1 stat() call, and 1 close() call.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@cs.umd.edu	Path:	uunet!mimsy!chris

lutmann@geocub.greco-prog.fr (03/03/90)

In article <15137:00:09:24@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes:
>In article <673@compel.UUCP> her@compel.UUCP (Helge Egelund Rasmussen) writes:
>> I need to write a replacement for the SYSV release 3 ttyname(3) function.
>
>ttyname() takes a file descriptor argument and (as you observed) searches
>through /dev for a tty (or just any file? I haven't checked) referencing


    Ttyname() scans the whole /dev !
    But I'm not sure that the prefix tty is enough... Don't forget
    /dev/console, pty... and so on (;-)
    
    What you can do, all of your ttys installed, is to build a sort
    of hash-table containing the inode of all these ttys. It'll reduce
    the numbers of tests, and after two or three accesses in this table,
    you'll get it !
    Disadvantage : this table is about 4 Kb...
    *Advantages* : easy
                   and it seems there's nothing faster !


  
                                Johan.
                                
                               

.-----------------------------.    
|           Johan             |    ...!uunet!mcvsun!inria!geocub!goofi!lutmann
| On goofi, at ENSERB, France |    ...!uunet!mcvsun!inria!geocub!deimos!pat
`-----------------------------'