jc@minya.UUCP (John Chambers) (01/02/88)
Well, here I am with something else I've screwed up, and can't make sense of from the Unix manuals! (:-) What's going wrong now is that I have a program, let's call it X, which starts up a sub-process, and execs /bin/sh in it. It then hangs around waiting for the shell to die. All very normal, you say? Well, then, explain why, to this shell and anything it starts, /dev/tty doesn't seem to exist. The first hint was from a script that did something like: | echo "This is an error message." >/dev/tty so that it could write to the control terminal regardless of how output had been redirected. Instead of the error message, what appeared on the control terminal was: | /dev/tty: cannot create This seems a bit bizarre; a bit of looking turns up the fact that: | crw-rw-rw- 1 root sys 2, 0 Jan 1 20:42 /dev/tty I.e., /dev/tty does indeed exist, and is world-writable. After a bit of testing, I wrote a little test C program that says: | if ((fn = open("/dev/tty", 2)) < 0) | fprintf(stderr,"Can't open(\"/dev/tty\",2) errno=%d.\n",errno); Guess what it says? OK, I'll tell you: | Can't open("/dev/tty",2) errno=6. Replacing the '2' with '1' or '0' gets the same results. Anyone have an idea what my program X might be doing to screw up /dev/tty? Some hints: This is a rather generic Unix Sys/V.2, so the problem should be similar to most ATT Unices. The most unusual thing about how X is run is that it isn't being started by a login shell; it is started as a daemon by init, and in some cases, decides to grab a terminal (whose name is on its command line, and which doesn't have getty on it) and run a program there. This is a useful thing to do if, for instance, you are playing around with process-control applications. Perhaps the question could be rephrased: What is the official, approved way for a daemon process like this to attach a terminal? If the answer is RTFM, can you say where? The 1/4-page /dev/tty entry isn't much help. [In fact, the Unix manuals aren't very helpful in general if you want to write a free-running background program. I've tried to help various users who wanted to do this, and it's frustrating never quite knowing what I'm talking about :-] -- John Chambers <{adelie,ima,maynard,mit-eddie}!minya!{jc,root}> (617/484-6393)
dave@sdeggo.UUCP (David L. Smith) (01/03/88)
In article <445@minya.UUCP >, jc@minya.UUCP (John Chambers) writes: > Some hints: This is a rather generic Unix Sys/V.2, so the problem should > be similar to most ATT Unices. The most unusual thing about how X is run > is that it isn't being started by a login shell; it is started as a daemon > by init, and in some cases, decides to grab a terminal (whose name is on > its command line, and which doesn't have getty on it) and run a program > there. This is a useful thing to do if, for instance, you are playing > around with process-control applications. > > Perhaps the question could be rephrased: What is the official, approved > way for a daemon process like this to attach a terminal? If the answer > is RTFM, can you say where? The 1/4-page /dev/tty entry isn't much help. > [In fact, the Unix manuals aren't very helpful in general if you want to > write a free-running background program. I've tried to help various users > who wanted to do this, and it's frustrating never quite knowing what I'm > talking about :-] The problem would seem to be that /dev/tty has no idea what tty you really want to be talking to. In order to set things up, you need to do a setpgrp() and then open the terminal you wish to talk to. Termio(7) briefly explains about the control terminal. -- David L. Smith {sdcsvax!man,ihnp4!jack!man, hp-sdd!crash, pyramid}!sdeggo!dave man!sdeggo!dave@sdcsvax.ucsd.edu Sinners can repent, but stupid is forever.
ron@topaz.rutgers.edu (Ron Natalie) (01/04/88)
Sure, /dev/tty works by redirecting the output to your controlling teletype. Network processes that don't explicitly use some feature like pty's, don't have a controlling teletype so /dev/tty doesn't mean anything. By the way, you have a real cute fprintf there that prints out the error number. Why not use perror, which does exactly what you did only printing the error in English. -Ron
ford@crash.cts.com (Michael Ditto) (01/04/88)
In article <445@minya.UUCP> jc@minya.UUCP (John Chambers) writes: >The first hint was from a script that did something like: >| echo "This is an error message." >/dev/tty >so that it could write to the control terminal regardless of how output >had been redirected. Instead of the error message, what appeared on the >control terminal was: >| /dev/tty: cannot create >This seems a bit bizarre; a bit of looking turns up the fact that: >| crw-rw-rw- 1 root sys 2, 0 Jan 1 20:42 /dev/tty >I.e., /dev/tty does indeed exist, and is world-writable. The "cannot create" message from the shell is misleading. It means the creat(2) system call failed. ('creat' will create a file if it doesn't exist, otherwise it's similar to 'open'). So the message just means that /dev/tty could not be opened. The shell is very stupid in that it does not give any indication as to why the open failed. >After a bit of testing, I wrote a little test C program that says: >| if ((fn = open("/dev/tty", 2)) < 0) >| fprintf(stderr,"Can't open(\"/dev/tty\",2) errno=%d.\n",errno); >Guess what it says? OK, I'll tell you: >| Can't open("/dev/tty",2) errno=6. The first thing you should have noticed is that errno=6, ENXIO. This is "No such device or address", an error which indicates that you are attempting to opening a logical device that has no corresponding physical device. In this case, you are openning "/dev/tty", which (according to tty(7)) is supposed to open for you the "control terminal associated with the process group of the process". The error means that there is no control terminal associated with the process group of your process. (more explanation below) >Some hints: This is a rather generic Unix Sys/V.2, so the problem should >be similar to most ATT Unices. The most unusual thing about how X is run >is that it isn't being started by a login shell; it is started as a daemon >by init, and in some cases, decides to grab a terminal (whose name is on >its command line, and which doesn't have getty on it) and run a program >there. This is a useful thing to do if, for instance, you are playing >around with process-control applications. First of all, you need to know what a process group is. Basically, any process can request to be separated from its current group and become a group of its own. Any future children of this process are also part of this new group. In your case, your program run from init is the "process group leader" of its own process group, which init created for your program. When your program (or shell script, if that's what it is) runs a child process, it is also part of your process group. Now the problem is that when your process (and process group) are created, they have never opened a terminal, and therefore do not have a "controlling terminal". A process group gets a controlling terminal when its PROCESS GROUP LEADER opens a terminal for the first time. A child process in the group may open a terminal, but this will NOT become the controlling tty. To get a controlling tty, your process group leader must open the terminal. >Perhaps the question could be rephrased: What is the official, approved >way for a daemon process like this to attach a terminal? If the answer >is RTFM, can you say where? The 1/4-page /dev/tty entry isn't much help. tty(7) explains "/dev/tty". The semantics of getting a controlling terminal are explained in termio(7). Creating a process group is described in setpgrp(2). The terminology (such as "controlling tty" and "process group leader") and error codes are briefly explained in intro(2). What you need to do is have your main program (the one that is directly running from init) open the terminal in question. You might want to call setpgrp() first, just to make sure you have your own process group, and to allow this program to work when run in other ways. Then, you can have child processes (such as shell commands) that use /dev/tty. You can also leave the tty open when you fork the subprocesses, allowing them to use the file descriptors you already have open, rather than opening the tty again in the child. Note that the above description applies to System V. BSD is even more bizarre. Good luck with your program. -- Mike Ditto -=] Ford [=- P.O. Box 1721 ford%kenobi@crash.CTS.COM Bonita, CA 92002 ford@crash.CTS.COM
jra@jc3b21.UUCP (Jay R. Ashworth) (01/04/88)
In article <445@minya.UUCP>, jc@minya.UUCP (John Chambers) says: > > Anyone have an idea what my program X might be doing to screw up /dev/tty? [ Yes. ] > Some hints: This is a rather generic Unix Sys/V.2, so the problem should > be similar to most ATT Unices. The most unusual thing about how X is run > is that it isn't being started by a login shell; it is started as a daemon > by init, and in some cases, decides to grab a terminal (whose name is on > its command line, and which doesn't have getty on it) and run a program > there. This is a useful thing to do if, for instance, you are playing > around with process-control applications. > John Chambers <{adelie,ima,maynard,mit-eddie}!minya!{jc,root}> (617/484-6393) Aha. As I understand the way these things work, and I'm sure someone will clarify what I'm about to say :-), /dev/tty is set by the kernel to point to the control terminal of a process group. Background process, those running as daemons, have no control terminal. Look at a ps listing. Also, when was the last time you tried to make an rc script read the console? My last time, I discovered that I had to use /dev/console (Yes, ack, this was on a tandy 6000), just /dev/tty bombed. Good luck. -- jra -- Jay R. Ashworth ---+-- The Great Ashworth & ------------+...!uunet!codas!pdn! 10974 111th St. N. | Petrillo Production Company | jc3b21!jra Seminole FL 34648 +-- watch for BayLink Public Access -+- UNIX ----+--------- (813) 397-1859 ----+-- Tampa Bay's Smallest Video Production House -+ :-) !$
mitch@stride1.UUCP (Thomas P. Mitchell) (01/06/88)
In article <167@sdeggo.UUCP> dave@sdeggo.UUCP (David L. Smith) writes: >In article <445@minya.UUCP >, jc@minya.UUCP (John Chambers) writes: > > > > Perhaps the question could be rephrased: What is the official, approved > > way for a daemon process like this to attach a terminal? If the answer > > is RTFM.... It is in the manual but a bit hard to find. Try "man man" and look for an option "man -f something". Keep the 'something' simple because a simple minded grep is done on the man page headers. Here is part of the result of "man -f tty" on this system. Note that two 'tty' man pages exist. getty (8) - set terminal type, modes, speed, and line discipline stty (1) - set the options for a terminal tty (1) - get the name of the terminal tty (4) - controlling terminal interface >The problem would seem to be that /dev/tty has no idea what tty you really >want to be talking to. In order to set things up, you need to do a >setpgrp() and then open the terminal you wish to talk to. Termio(7) briefly >explains about the control terminal. > It (/dev/tty) is a clever pseudo device. The key is that it figures out which "real" device the process is connected to. ======== man page follows ======= this system's "man 4 tty" === NAME tty - controlling terminal interface DESCRIPTION The file /dev/tty is, in each process, a synonym for the control terminal associated with the process group of that process, if any. It is useful for programs or shell sequences that wish to be sure of writing messages on the terminal no matter how output has been redirected. It can also be used for programs that demand the name of a file for output, when typed output is desired and it is tiresome to find out what terminal is currently in use. FILES /dev/tty /dev/tty* Thomas P. Mitchell (mitch@stride1.Stride.COM) Phone: (702) 322-6868 TWX: 910-395-6073 MicroSage Computer Systems Inc. a Division of Stride Micro. Opinions expressed are probably mine.
allbery@ncoast.UUCP (Brandon Allbery) (01/06/88)
As quoted from <243@jc3b21.UUCP> by jra@jc3b21.UUCP (Jay R. Ashworth): +--------------- | In article <445@minya.UUCP>, jc@minya.UUCP (John Chambers) says: | > Some hints: This is a rather generic Unix Sys/V.2, so the problem should | > be similar to most ATT Unices. The most unusual thing about how X is run | > is that it isn't being started by a login shell; it is started as a daemon | > by init, and in some cases, decides to grab a terminal (whose name is on | Aha. As I understand the way these things work, and I'm sure someone | will clarify what I'm about to say :-), /dev/tty is set by the kernel | to point to the control terminal of a process group. Background | process, those running as daemons, have no control terminal. Look at +--------------- /dev/tty is more of an alias than a device. A function call on /dev/tty looks up in the user block of the process to determine the controlling terminal, then repeats the function call on that terminal. If there is no controlling terminal, an open on /dev/tty will fail because the /dev/tty open routine can't figure out what tty's open routine to call. In particular, /dev/tty does not work at all like the /dev/window device on the 3B1, which searches for the first UNUSED window device rather than the current one. -- Brandon S. Allbery, Moderator of comp.sources.misc {hoptoad,harvard!necntc,cbosgd,sun!mandrill!hal,uunet!hnsurg3}!ncoast!allbery PS/2: Half a computer. OS/2: Half an operating system for half a computer.
marcus@illusion.UUCP (Marcus Hall) (01/07/88)
In article <2256@crash.cts.com> ford%kenobi@crash.CTS.COM (Michael Ditto) writes: >In article <445@minya.UUCP> jc@minya.UUCP (John Chambers) writes: >>The first hint was from a script that did something like: >>| echo "This is an error message." >/dev/tty >>so that it could write to the control terminal regardless of how output >>had been redirected. Instead of the error message, what appeared on the >>control terminal was: >>| /dev/tty: cannot create .... > >What you need to do is have your main program (the one that is directly >running from init) open the terminal in question. You might want to call >setpgrp() first, just to make sure you have your own process group, and to >allow this program to work when run in other ways. Then, you can have >child processes (such as shell commands) that use /dev/tty. You can also >leave the tty open when you fork the subprocesses, allowing them to use >the file descriptors you already have open, rather than opening the tty >again in the child. Well,,,,, This is indeed the problem, but I'm afraid that this solution will not work. As it turns out, a tty can be the control terminal of only one process group at a time. (I don't have the man page here, but it reads something like "when a process opens a tty device for the first time" which actually means that the device is opened for the first time.) I have tried to figure out ways around this problem without success. If anyone has any suggestions, I'd really like to hear them. If you don't do a setpgrp() call, you will still be able to access /dev/tty because your login shell is the process group leader and it should have a control terminal (There are ways around this, so this statement isn't strictly true, but it usually is.) For ksh at least, there is a flag, -m I believe (check this to be sure) that causes it to place all backgrounded jobs into their own process groups. If you use ksh, clear this flag and see if your program works, for other shells, check for a similar flag. Incidently, the reason that a tty device can be attached to only one process group is that there is a pointer in the tty structure that points to the process group. When an interrupt or kill character is processed (or other conditions at times), this is used to send a signal to the process group. It would have been just about as easy to just have the proc table entries point to the control terminal and scan the proc table for pointers to the terminal generating the signal, (the proc table has to be scanned to distribute the signal to the process group anyway), but that's just how it is done -- no use worrying about how it "should" have been done :-) Marcus Hall ..!{ihnp4,mcdchg}!illusion!marcus
jc@minya.UUCP (John Chambers) (01/28/88)
> >In article <445@minya.UUCP >, jc@minya.UUCP (John Chambers) writes: > > > > > > Perhaps the question could be rephrased: What is the official, approved > > > way for a daemon process like this to attach a terminal? If the answer > > > is RTFM.... > Well, after wading through lots of responses, most of which told me things I already knew, and didn't answer the question, a couple of folks gave the right hint, something that I still can't get from re-reading TFM: the call of setpgrp() must happen BEFORE opening any terminal device. If there is any file open that looks like a terminal, setpgrp() seems to have no effect at all (or maybe it's just too subtle for me :-). Anyhow, I have my program finding /dev/tty now, so thanks. There is still a puzzle, in that my process starts children, including quite often a shell, and these inherit the terminal (as with getty/login, I guess). I've tried making the children into process-group leaders on their own, to no avail. No matter what I do, the ^C at the terminal goes to the original process. It doesn't even work for a child to close all its files, setpgrp(), and re-open all its files. Very, very strange stuff here. I've sort of handled this by having the program intercept all signals and pass them along to its children. This works, but it doesn't seem to reach the grandchildren, even if I do kill(0,<sig>). The manual says it should, but the grandchildren don't notice the signal. Am I paranoid, or did they do this intentionally to make my life difficult? -- John Chambers <{adelie,ima,maynard,mit-eddie}!minya!{jc,root}> (617/484-6393)
davel@hpcupt1.HP.COM (Dave Lennert) (01/31/88)
> There is still a puzzle, in that my process starts children, including quite > often a shell, and these inherit the terminal (as with getty/login, I guess). > I've tried making the children into process-group leaders on their own, to > no avail. No matter what I do, the ^C at the terminal goes to the original > process. It doesn't even work for a child to close all its files, setpgrp(), > and re-open all its files. Very, very strange stuff here. > > John Chambers <{adelie,ima,maynard,mit-eddie}!minya!{jc,root}> (617/484-6393) I'm guessing a little at what your programs look like but... First some background. (All this assumes System V without BSD style job control. BSD and/or job control does this differently in subtle ways.) setpgrp(): if your process is NOT ALREADY a process group leader, setpgrp() will make it a pgrp leader and then remove its controlling terminal (if any). Just the calling process loses the controlling tty, other process which share this tty as a controlling tty still retain it. open(): If a pgrp leader is without a controlling tty and opens a tty which IS NOT CURRENTLY a controlling tty for other processes, then this tty becomes the controlling tty of the calling process. If the tty is already a controlling tty for another pgrp, then it does NOT become the controlling tty of the caller. In either case, the open succeeds (i.e., no indication is given that the terminal did or did not become your controlling tty). fork(): child processes inherit the controlling tty of the parent, if any. close(): a controlling tty will cease to be a controlling tty when either (a) the pgrp leader which allocated it terminates or (b) NO process has the tty open. signals: tty keyboard generated signals are sent to ALL processes in the pgrp of the pgrp leader which allocated the controlling tty. Now, I assume you have a program which calls setpgrp() and then open()'s a tty, thus aquiring it as a controlling tty. It then forks and creates children which (a) share the controlling tty and (b) are members of the same process group. Keyboard signals go to all processes in the pgrp (including the pgrp leader parent). Even if the children close all their file descriptors to the terminal, if the parent still has it opened it will remain a controlling tty and keyboard signals will continue to be sent to the child processes which remain in the same pgrp. If the children do a setpgrp(), they will cease to share the controlling tty and (more importantly) cease to be in the pgrp so they will no longer receive keyboard signals. The pgrp leader parent cannot leave the pgrp since SysV forbids a pgrp leader to leave its pgrp; so it will always receive the signals. -Dave Lennert HP ihnp4!hplabs!hpda!davel