[comp.lang.c] ttyname

jonas@lkbpyr.UUCP (Jonas Heyman) (08/29/89)

Hello,

I was wondering why this work:

--------------------------------------
#include <stdio.h>
main()
{
	char *term;
	char *ttyname();
	term=ttyname();
	printf("%d",term);
}
---------------------------------------

And why this don't:
--------------------------------------
#include <stdio.h>
main()
{
	test();
}

test()
{
	char *term;
	char *ttyname();
	term=ttyname();
	printf("%d",term);
}
----------------------------------------

All the above should type out your current 'tty',example: '/dev/tty023'.

Be glad for an answer,sincerely jonas

-- 

  jonas@lkbpyr.lkb.se 

fieland@hobbiton.prime.com (08/30/89)

I can't answer your question.  In fact, your program(s) didn't
print out my tty on either the MIPS or my Sun 386i.  I was able
to get my tty on the mips with the program below, although the
term returned was null when I executted the program on the SUn
in a window.

Notice the print format.


Peggy
#include <stdio.h>
main()
{
	char *term;
	char *ttyname();
	term=ttyname();
	printf("%s\n",term);
	test();
}
test()
{
	char *term;
	char *ttyname();
	term=ttyname();
	printf("%s\n",term);
}

fieland@hobbiton.prime.com (08/30/89)

A further note:

tried this out on another Sun without the windows up.

Sure enough, the call in Main got the ttyname and the
call in test didn't.

Clearly, results are system dependent.

So how about it??? Any answers out there??????

Peggy

ping@cubmol.BIO.COLUMBIA.EDU (Shiping Zhang) (08/30/89)

In article <99@lkbpyr.UUCP> jonas@lkbpyr.UUCP (Jonas Heyman) writes:
>Hello,
>
>I was wondering why this work:

>#include <stdio.h>
>main()
>{
>	char *term;
>	char *ttyname();
>	term=ttyname();
>	printf("%d",term);
>}

I am wondring too because the format of printf() should be %s.





>And why this don't:

>#include <stdio.h>
>main()
>{
>	test();
>}
>
>test()
>{
>	char *term;
>	char *ttyname();
>	term=ttyname();
>	printf("%d",term);
>}

I guess because the format of printf() is incorrect.


-ping

chris@mimsy.UUCP (Chris Torek) (08/30/89)

In article <192700003@hobbiton> fieland@hobbiton.prime.com writes:
>A further note:
>tried this out on another Sun without the windows up.
>Sure enough, the call in Main got the ttyname and the
>call in test didn't.
>Clearly, results are system dependent.

Does no one use lint??

Hint: RTFM, or use lint.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

cpcahil@virtech.UUCP (Conor P. Cahill) (08/30/89)

In article <99@lkbpyr.UUCP>, jonas@lkbpyr.UUCP (Jonas Heyman) writes:
> Hello,
> 
> I was wondering why this work:
> 

    [ example 1 with ttyname() in main() ]

> And why this don't:

    [ example 2 with ttyname() in test() called from main() ]

> 
> All the above should type out your current 'tty',example: '/dev/tty023'.
> 

This is really on of those RTFM kind of things.  ttyname() takes a
file descriptor as an argument.  Both times you were getting whatever
value happened to be on the stack at the time the ttyname was called,
you were lucky the first time (within main) probably because the
ttyname was called so early that the stack was relatively clean, but
even this is a bad assumption because other processing has already
been accomplished in the startup routines before main is called.

So add the appropriate file descriptor whose ttyname you wish to 
obtain.  (I usually use 2, to allow for redirection of stdout and
stdin and still get the ttyname.  Of course if the user redirects
all three, you're out of luck (unless you open /dev/tty and then
call ttyname() with the fd returned from the open).



-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

diamond@csl.sony.co.jp (Norman Diamond) (08/30/89)

In article <99@lkbpyr.UUCP> jonas@lkbpyr.UUCP (Jonas Heyman) writes:

->I was wondering why this works:
->#include <stdio.h>
->main()
->{
->	char *term;
->	char *ttyname();
->	term=ttyname();
->	printf("%d",term);
->}
->
->And why this doesnn't:
->#include <stdio.h>
->main()
->{
->	test();
->}
->test()
->{
->	char *term;
->	char *ttyname();
->	term=ttyname();
->	printf("%d",term);
->}

Looks to me like they should both fail.  You CAN print the decimal
value of a pointer (using "%d") but it isn't what you're asking for.
Try "%s" or maybe even "%s\n".

-- 
Norman Diamond, Sony Corporation (diamond@ws.sony.junet)
  The above opinions are inherited by your machine's init process (pid 1),
  after being disowned and orphaned.  However, if you see this at Waterloo or
  Anterior, then their administrators must have approved of these opinions.

tbecker@incas.UUCP (Thomas Becker) (08/30/89)

jonas@lkbpyr.UUCP (Jonas Heyman) writes:

>	printf("%d",term);
                ^^
yes, of course, use %d ...

Anyway, I have tried the two versions on a Sun 3/60 and found out the same.
The manpage of ttyname(3) says that the function takes a field descritor as
an argument. So I tried to call ttyname(NULL) within test(), and it worked!

>  jonas@lkbpyr.lkb.se 

Thomas

-- 
Thomas Becker --------- University of Kaiserslautern ------------- West Germany
------------ P.O. Box 3049 -------------------- D-6750 Kaiserslautern ---------
-------------------- e-mail: incas!tbecker@uklirb.uucp ------------------------
------------------------- phone: +49 631 205 3295 -----------------------------

andre@targon.UUCP (andre) (08/30/89)

In article <99@lkbpyr.UUCP> jonas@lkbpyr.UUCP (Jonas Heyman) writes:
]I was wondering why this work:
]#include <stdio.h>
]main()
]{
]       char *term;
]       char *ttyname();
]       term=ttyname();
]       printf("%d",term);
]}

Because you were lucky,

]And why this don't:
]--------------------------------------
]#include <stdio.h>
]main()
]{
]       test();
]}
]
]test()
]{
]       char *term;
]       char *ttyname();
]       term=ttyname();
]       printf("%d",term);
]}

because you were not lucky, there was something else on the stack.

The *MANUAL* says, char *ttyname(filedes).
So if you use in on stdin it will work:

term=ttyname(0);

-- 
    \---|    AAA         DDDD  It's not the kill, but the thrill of the chase.
     \  |   AA AAvv   vvDD  DD        Ketchup is a vegetable.
  /\  \ |  AAAAAAAvv vvDD  DD                    {nixbur|nixtor}!adalen.via
_/__\__\| AAA   AAAvvvDDDDDD    Andre van Dalen, uunet!hp4nl!targon!andre

bazza@hppad.HP.COM (Carlos Bazzarella) (08/30/89)

Hello,

I was wondering why this work:

--------------------------------------
#include <stdio.h>
main()
{
	char *term;
	char *ttyname();
	term=ttyname();
	printf("%d",term);
}
---------------------------------------

And why this don't:
--------------------------------------
#include <stdio.h>
main()
{
	test();
}

test()
{
	char *term;
	char *ttyname();
	term=ttyname();
	printf("%d",term);
}
----------------------------------------


The second one doesn't work because when the 
compiler gets to main() and sees test(), he doesn't
know what to do with it, since it was not 
previously defined or compiled. there are 2 things 
you can do. first you could move the test() function
prior to main(), that way by the time main() is 
compiled, test() will the ready. second you could 
declared test() on top of your program or in a include
file, so when main() is compiled, test() will be given
a function overhead, that way the linker will know what
to do with test().
a function declaration, for your case, looks like this:
void test();
  3    1 2 
/* it reads: test (1) is a function (2) with no
 * returning value (void (2))
 */


			Carlos Bazzarella.
		     University of Waterloo.

vaughan@mcc.com (Paul Vaughan) (08/30/89)

   From: cpcahil@virtech.UUCP (Conor P. Cahill)

   In article <99@lkbpyr.UUCP>, jonas@lkbpyr.UUCP (Jonas Heyman) writes:
   > Hello,
   > 
   > I was wondering why this work:
   > 

       [ example 1 with ttyname() in main() ]

   > And why this don't:

       [ example 2 with ttyname() in test() called from main() ]

   > 
   > All the above should type out your current 'tty',example: '/dev/tty023'.
   > 

   This is really on of those RTFM kind of things.  ttyname() takes a
   file descriptor as an argument.  Both times you were getting whatever
   value happened to be on the stack at the time the ttyname was called,
   you were lucky the first time (within main) probably because the
   ttyname was called so early that the stack was relatively clean, but
   even this is a bad assumption because other processing has already
   been accomplished in the startup routines before main is called.

Good answer.  I was wondering why the compiler hadn't cited the
appropriate passages of TFM to him.  I guess that's something you give
up if you use <stdio.h> instead of <stream.h>.  I tried it using (the gnu
lib-g++) <stream.h> and got

io.cc:8: warning: type mismatch with previous external decl
/usr/local/gnu/lib/g++-include/std.h:204: warning: previous external
decl of `char *ttyname (int)'

The line number is different because I also bothered to declare test
first to get rid of the implicit declaration warning.  When I found
the argument passing error, I decided the original poster was
completely lost and that it wasn't worth looking at.  However, I think
it's useful to note that using <stream.h> instead of stdio.h would
have caught this one.  Not to mention that using cout instead of
printf would obviated the problem with the %d format specifier and
that the program is very clearly expressed in one line

cout << ttyname(2);


 Paul Vaughan, MCC CAD Program | ARPA: vaughan@mcc.com | Phone: [512] 338-3639
 Box 200195, Austin, TX 78720  | UUCP: ...!cs.utexas.edu!milano!cadillac!vaughan

karl@haddock.ima.isc.com (Karl Heuer) (08/31/89)

In article <1088@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
>Of course if the user redirects all three, you're out of luck (unless you
>open /dev/tty and then call ttyname() with the fd returned from the open).

In which case you'll probably (depending on flavor) get the return string
"/dev/tty" rather than the true name of the terminal.  (Assuming the open
succeeds in the first place.  Not every process has a controlling terminal.)

cpcahil@virtech.UUCP (Conor P. Cahill) (08/31/89)

In article <14481@haddock.ima.isc.com>, karl@haddock.ima.isc.com (Karl Heuer) writes:
> In article <1088@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
> >Of course if the user redirects all three, you're out of luck (unless you
> >open /dev/tty and then call ttyname() with the fd returned from the open).
> 
> In which case you'll probably (depending on flavor) get the return string
> "/dev/tty" rather than the true name of the terminal.  (Assuming the open
> succeeds in the first place.  Not every process has a controlling terminal.)

I beg to differ.  If the open succeeded you will have gotten a file 
descriptor for the "controlling terminal", not /dev/tty.  The gentty driver,
which is the driver for /dev/tty,  just obtains the major/minor device
number for the current process and calls the device specific open 
routine for that device.

I can't imagine that there is a kernel out there that will return a 
file descriptor associated with /dev/tty and then re-maps it to the
appropriate device for every read and write (which it would have to 
do if the fd is associated with /dev/tty as opposed to the real terminal). 

Now that we have the file descriptor for the controlling terminal we pass
this to ttyname() which will perform an fstat
on that file descriptor and then look through the /dev directory 
for an entry that matches the device number obtained in the fstat().


-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

ams@cbnewsl.ATT.COM (andrew.m.shaw) (08/31/89)

From article <2613@incas.UUCP>, by tbecker@incas.UUCP (Thomas Becker):
> The manpage of ttyname(3) says that the function takes a field descritor as
> an argument. So I tried to call ttyname(NULL) within test(), and it worked!

You were lucky that in your implementation the representation of NULL is the
same as the representation of (int)0, giving you stdin.  A field [sic] 
descriptor is properly an int, not a pointer.

	Andrew Shaw

uri@arnor.UUCP (Uri Blumenthal) (09/01/89)

From article <192700003@hobbiton>, by fieland@hobbiton.prime.com:
> 
> tried this out on another Sun without the windows up.
> 
> Sure enough, the call in Main got the ttyname and the
> call in test didn't.
> 
> Clearly, results are system dependent.
> So how about it??? Any answers out there??????

This definitely works correctly (AIX system):
-------------------
#include <stdio.h>
void test()
{
	char *ttyname();

	printf("test: %s\n", ttyname(2));

}

main()
{
	char *ttyname();

	printf("main: %s\n", ttyname(2));
	test();

	exit(0);

}
-------------------------------

Points to be made:
	
	a) %s in 'printf' statement;

	b) the manual says:

		char *ttyname(fildes)
		int  fildes;

	   and when you call 'ttyname' WITHOUT proper parameter -
	   it does work from 'main', but doesn't work in subroutines.
	   Why? Implementation details, who cares?

Regards,
Uri.
________________
<Disclaimer>

flaps@dgp.toronto.edu (Alan J Rosenthal) (09/01/89)

cpcahil@virtech.UUCP (Conor P. Cahill) writes:
>I beg to differ.  If the open succeeded you will have gotten a file 
>descriptor for the "controlling terminal", not /dev/tty...
>I can't imagine that there is a kernel out there that will return a 
>file descriptor associated with /dev/tty and then re-maps it to the
>appropriate device for every read and write...

FOR F***K'S SAKE DOES NO ONE CHECK THINGS OUT BEFORE POSTING?

Script started on Thu Aug 31 16:40:46 1989
champlain.dgp% cat ttyname.c
#include <stdio.h>
#include <fcntl.h>

int main()
{
    int fd;
    char *p;
    extern char *ttyname();

    if ((fd = open("/dev/tty", O_RDWR)) < 0)
	perror("/dev/tty");
    else if ((p = ttyname(fd)) == NULL)
	fprintf(stderr, "ttyname failed\n");
    else
	printf("tty is %s\n", p);

    return(0);
}
champlain.dgp% cc ttyname.c
champlain.dgp% a.out
tty is /dev/tty
champlain.dgp% ^D
script done on Thu Aug 31 16:41:04 1989

That was on a sun running 3.5; I got the same output on an iris running sys V
whose motd says "IRIX System V Release 4D1-3.1D".

--

Posting etiquette:
When I saw Karl's posting about /dev/tty, I was surprised and I thought it was
wrong.  But I didn't just bang on my followup key.  I pressed ^Z and typed
"ttyname </dev/tty".  Much to my surprise I got the output "/dev/tty".  It's
quite simple to check before posting.  Remember that when you post hasty
replies you are wasting many people's time, especially by the volume of
followups to your followup which are generated.

ajr

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/01/89)

In article <2613@incas.UUCP> tbecker@incas.UUCP (Thomas Becker) writes:
>So I tried to call ttyname(NULL) within test(), and it worked!

Only by accident.  You should use NULL only as a null pointer constant.
For a file descriptor that's associated with the terminal, try 2 (in a
UNIX environment), or, more portably, fileno(stderr).

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/01/89)

In article <1860001@hppad.HP.COM> bazza@hppad.HP.COM (Carlos Bazzarella) writes:
>The second one doesn't work because when the 
>compiler gets to main() and sees test(), he doesn't
>know what to do with it, since it was not 
>previously defined or compiled.

Therefore "test" must be the name of an function returning int,
as has always been the rule in C.  Later that is how it is defined,
although the required return statement was omitted.  Try again..

cpcahil@virtech.UUCP (Conor P. Cahill) (09/01/89)

In article <1860001@hppad.HP.COM>, bazza@hppad.HP.COM (Carlos Bazzarella) writes:
> The second one doesn't work because when the 
> compiler gets to main() and sees test(), he doesn't
> know what to do with it, since it was not 
> previously defined or compiled.

I think you need to go back and read your C book again.  There is
no requirement that functions be defined before being used 
in C.  If there was, every program that uses standard library calls
(which the compiler usually knows nothing about) would blow up.

The only requirement for pre-definition is that the function is
assumed to return an int if it is used before any declaration/definition.
In this example the function does return an int so no problem.

As I said in an earlier message the problem with the code is that
the ttyname() function requires a file descriptor argument. (Several others
also pointed out the typo in the printf("%d", but since the author said
the first sample worked I would assume that the %d was a typo added 
when he typed the article.
-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

cpcahil@virtech.UUCP (Conor P. Cahill) (09/01/89)

In article <1989Aug31.165349.13125@jarvis.csri.toronto.edu>, flaps@dgp.toronto.edu (Alan J Rosenthal) writes:
> 
> Posting etiquette:
> When I saw Karl's posting about /dev/tty, I was surprised and I thought it was
> wrong.  But I didn't just bang on my followup key.  I pressed ^Z and typed
> "ttyname </dev/tty".  Much to my surprise I got the output "/dev/tty".  It's
> quite simple to check before posting.  Remember that when you post hasty
> replies you are wasting many people's time, especially by the volume of
> followups to your followup which are generated.


You are absolutely correct and I apologize for the inaccurate response.  I just
"KNEW" it had to be that way.  So much for knowing without checking.




-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

matthew@sunpix.UUCP ( Sun Visualization Products) (09/02/89)

In article <1860001@hppad.HP.COM> bazza@hppad.HP.COM (Carlos Bazzarella) writes:
)
)The second one doesn't work because when the 
)compiler gets to main() and sees test(), he doesn't
)know what to do with it, since it was not 
)previously defined or compiled. there are 2 things 
)you can do. first you could move the test() function
)prior to main(), that way by the time main() is 
)compiled, test() will the ready. second you could 
)declared test() on top of your program or in a include
)file, so when main() is compiled, test() will be given
)a function overhead, that way the linker will know what
)to do with test().
)a function declaration, for your case, looks like this:
)void test();
)  3    1 2 
)/* it reads: test (1) is a function (2) with no
) * returning value (void (2))
) */
)
)

What's this!!!

Sorry, This newsgroup is "comp.lang.c", not "comp.lang.pascal", function order
is not important.

The correct answer to this problem is the one previosly posted.  The 'ttyname()'
function call was lacking the file descriptor arguement.  Changing the function
call to 'ttyname(0)' fixes the problem.



-- 
Matthew Lee Stier                            |
Sun Microsystems ---  RTP, NC  27709-3447    |     "Wisconsin   Escapee"
uucp:  sun!mstier or mcnc!rti!sunpix!matthew |
phone: (919) 469-8300 fax: (919) 460-8355    |

karzes@mfci.UUCP (Tom Karzes) (09/02/89)

In article <1860001@hppad.HP.COM> bazza@hppad.HP.COM (Carlos Bazzarella) writes:
>The second one doesn't work because when the 
>compiler gets to main() and sees test(), he doesn't
>know what to do with it, since it was not 
>previously defined or compiled.

Nonsense.  You obviously know nothing of C.  You should probably try to
understand something simple like "Hello world" before bothering the net
again with such rank amateur comments.  (I can tolerate dumb questions, but
not dumb answers, particularly when it's obvious that the code has not
been tested, or run through lint, or when TFM hasn't been consulted.)

cpcahil@virtech.UUCP (Conor P. Cahill) (09/02/89)

After some more thought as to why ttyname(open("/dev/tty",0)) == "/dev/tty" 
as opposed to /dev/tty?? or whatever the name of the controlling terminal is,
I *think* I figured out the problem.

When open is called with the name "/dev/tty", it translates the name into
the inode (using the appropriate kernel routine such as namei()), and then
determines that the file to be opened is a device special file.

At this point the open calls the device specific open, which in 
this case just calls another device specific open (for the controlling
terminal).  The open code is not aware that the device that was 
actually opened is different than the one it thought was being opened and
so sets up the file table entries to point to /dev/tty.

-- 
+-----------------------------------------------------------------------+
| Conor P. Cahill     uunet!virtech!cpcahil      	703-430-9247	!
| Virtual Technologies Inc.,    P. O. Box 876,   Sterling, VA 22170     |
+-----------------------------------------------------------------------+

rfg@dg-rtp.dg.com (Ron Guilmette) (09/02/89)

In article <1111@virtech.UUCP> cpcahil@virtech.UUCP (Conor P. Cahill) writes:
>After some more thought as to why ttyname(open("/dev/tty",0)) == "/dev/tty" 
>...


Has this discussion got anything specifically to do with C++?

If not, could you please confine it to comp.lang.c.  Thanks.

// rfg

mccaugh@s.cs.uiuc.edu (10/04/89)

 Shouldn't the declaration be:

      extern char *ttyname();

 as it surely isn't defined by you, nor does it appear in <stdio.h>. Also, did
 you know that 'ttyname' takes a system file-descriptor (I did not see one as
 an argument). You might try calling 'isatty' just to determine if your tty is
 "recognized" by the system. You refer to system differences, so I would con-
 sult the 'man' pages, then include enough #ifdef's to (hopefully) cover most
 of the cases.

 Best of Luck.

 Scott McCaughrin
 University of Illinois
 (mccaugh@s.cs.uiuc.edu)

 P.S. Perhaps some other '.h' has to be included for 'ttyname' to be under-
      stood properly in your configuration.