Xref: utzoo comp.unix.wizards:22414 comp.bugs.4bsd:1568 Path: utzoo!attcan!uunet!cs.utexas.edu!sdd.hp.com!ucsd!ucbvax!ucsfcgl!pixar!bp From: bp@pixar.UUCP (Bruce Perens) Newsgroups: comp.unix.wizards,comp.bugs.4bsd Subject: How to divorce a process from the controlling tty (was syslogd.c) Message-ID: <11388@pixar.UUCP> Date: 11 Jun 90 16:48:05 GMT References: <1990Jun8.070904.7466@athena.mit.edu> <36447@sequent.UUCP> Organization: Pixar -- Marin County, California Lines: 99 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