Path: utzoo!mnetor!uunet!seismo!sundc!pitstop!sun!amdcad!ames!rutgers!sdcsvax!ucsdhub!hp-sdd!ncr-sd!crash!ford From: ford@crash.cts.com (Michael Ditto) Newsgroups: comp.unix.wizards Subject: Re: /dev/tty doesn't exist? Message-ID: <2256@crash.cts.com> Date: 3 Jan 88 20:30:00 GMT References: <445@minya.UUCP> Reply-To: ford%kenobi@crash.CTS.COM (Michael Ditto) Organization: Crash TS, El Cajon, CA Lines: 82 Summary: "can't open" != "doesn't exist"; /dev/tty is the "controlling tty" 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