bp@pixar.UUCP (Bruce Perens) (06/11/90)
In article <1990Jun8.070904.7466@athena.mit.edu> jik@athena.mit.edu (Jonathan I. Kamens) writes: > > Pulled from etc/syslogd.c: > > if (!Debug) { > if (fork()) > exit(0); > for (i = 0; i < 10; i++) > (void) close(i); > (void) open("/", 0); > (void) dup2(0, 1); > (void) dup2(0, 2); > untty(); > } > keany@sequent.UUCP (Bernard Keany) writes: >"Change the working directory to /. Sorry, you didn't read the example carefully. There is no directory changing going on in this code fragment. The example is trying to divorce the process from its controlling tty, so that it will not be hit by the side-effects of being associated with a tty. To do this, it closes any fds that might be open to a tty, and opens 0, 1, and 2 to _anything_ that it is sure is not a tty. Then it calls untty(), which does an ioctl that clears the processes controlling tty. I think the usage of / for this is descended from a version of unix so old that it did not have /dev/null . I don't believe in programs that do this "because /dev/null might not exist". It might be that the programmer wants the fd open to something that will cause an error on _write_, but I don't buy that either. This code would fail if some system didn't allow one to open / as a regular file, which I feel is more likely than /dev/null going away, especially in the context of network filesystems. Some side effects from being associated with a controlling tty that daemons want to avoid are: blocking on read or _write_, possibly forever. interrupt, quit, and other signals sent by the tty. shells mucking with your process group, and sending signals. (feel free to add to this list) I the blocking part is more important than you might think. A while ago I found the console of a 4.2 system locked up (by a spurious control-S) and two dozen processes blocked on console writes. Versions of unix that I have played with set the controlling tty this way, your mileage may vary: If your parent has one, you get that one. Otherwise, the first time you do an open on a tty, that becomes your controlling tty. Here's how I would divorce a process from a controlling tty. Feel free to criticize and correct this: int count; int null_fd; int tty_fd; /* * Get rid of ALL open fds. Any one of them might be open * to a tty. */ count = NFDS; do { close(--count); } while ( count ); /* * Open the traditional fds for a tty connection to * something, to reduce the chance that they might be opened * to a tty by some code later on. */ null_fd = open("/dev/null", 0); #ifdef PARANOID if ( null_fd < 0 ) null_fd = open("/", 0); /* /dev/null might not exist */ #endif dup2(0, 1); dup2(0, 2); /* * Here's the fun part. See if there is still a controlling * tty by opening /dev/tty. If you don't have a controlling * tty, the open will fail! If it succeeds, do ioctl TIOCNOTTY * on that fd, and close it again. */ if ( (tty_fd = open("/dev/tty", 0)) >= 0 ) { ioctl(tty_fd, TIOCNOTTY, 0); close(tty_fd); } Now, don't go and open the console, or you might spoil everything. Use syslog for logging. Someone on the net will doubtless be able to correct my own misconceptions and typos. Bruce Perens
jtkohl@MIT.EDU (John T Kohl) (06/12/90)
In article <11388@pixar.UUCP> bp@pixar.UUCP (Bruce Perens) writes: > Here's how I would divorce a process from a controlling tty. Feel > free to criticize and correct this: > ... > count = NFDS; > ... Modern Unixes have a call to tell you the # of file descriptors: count = getdtablesize(); -- John Kohl <jtkohl@ATHENA.MIT.EDU> or <jtkohl@MIT.EDU> Digital Equipment Corporation/Project Athena (The above opinions are MINE. Don't put my words in somebody else's mouth!)
mar@athena.mit.edu (Mark A. Rosenstein) (06/13/90)
In article <11388@pixar.UUCP>, bp@pixar.UUCP (Bruce Perens) writes: |> Here's how I would divorce a process from a controlling tty. Feel |> free to criticize and correct this: [some code deleted] |> /* |> * Here's the fun part. See if there is still a controlling |> * tty by opening /dev/tty. If you don't have a controlling |> * tty, the open will fail! If it succeeds, do ioctl TIOCNOTTY |> * on that fd, and close it again. |> */ |> if ( (tty_fd = open("/dev/tty", 0)) >= 0 ) { |> ioctl(tty_fd, TIOCNOTTY, 0); |> close(tty_fd); |> } Some code like that caused a heisenbug (you know, one where observing it affects the outcome) here last year. We were restarting our nameserver regularly from a daemon. If the daemon were restarted by someone netting into the machine, then the daemon's controlling tty was a pseudo-tty. When the nameserver got to the code fragment above, if no one was currently logged in on that pseudo-tty, then it would hang. When we noticed it wasn't running and logged in to check on it, we would usually log in on the correct pseudo-tty to get it running again and not be able to tell that it had stopped. I fixed this by including the non-blocking I/O flag in the open(), but that requires a kernel mod from standard 4.3BSD for that to work. Does anyone know a better solution for this? -Mark Variables won't and constants aren't.
smb@ulysses.att.com (Steven Bellovin) (06/13/90)
In article <11388@pixar.UUCP>, bp@pixar.UUCP (Bruce Perens) writes: > > I think the usage of / for this is descended from a version of unix so > old that it did not have /dev/null . I don't believe in programs that > do this "because /dev/null might not exist". I'm not sure in what sense you ``don't believe in'' such programs. They most certainly do exist.... And no, they're not from code that old. I don't know how old /dev/null is, but I assure you it's much older than syslogd. > It might be that the programmer > wants the fd open to something that will cause an error on _write_, but > I don't buy that either. This code would fail if > some system didn't allow one to open / as a regular file, which I feel > is more likely than /dev/null going away, especially in the context of > network filesystems. As I replied earlier by email to Jonathan Kamens, code like that most certainly was intended to deal with /dev/null not being there. And while I don't recall cases of /dev/null going away, I've seen a fair number of instances of /dev/null having the wrong modes, or somehow being replaced by a regular file. There exists a school of thought, among some very serious wizards, that says that / is the only thing you know for certain exists. (Or rather, if it's not there, you're not likely to be able to do much of anything anyway...) The idea is to minimize the vulnerability of the subsystem to other failures. I'm not saying I agree or disagree -- I'm saying that the idea has been propounded, by highly-qualified people. --Steve Bellovin
karl@haddock.ima.isc.com (Karl Heuer) (06/14/90)
In article <JTKOHL.90Jun11153217@lycus.MIT.EDU> jtkohl@MIT.EDU (John T Kohl) writes: >Modern Unixes have a call to tell you the # of file descriptors: > count = getdtablesize(); Actually, in *modern* Unixes it's done with sysconf().