paul@vixie.UUCP (Paul Vixie Esq) (01/15/87)
I have a program that forks itself and exits upon running -- its child process runs as a daemon forever after. In 'ps aux', I notice that it still shows my tty as its control terminal -- even if I log out and back in. I see that syslogd, inetd, cron, and the rest do NOT show 'co' as their control terminal; how do I make this happen for me? This is (more or less) BSD 4.2, and the program is setuid root. Thanks... -- Paul A. Vixie {ptsfa, qantel, crash, winfree}!vixie!paul 329 Noe Street dual!ptsfa!vixie!paul@ucbvax.Berkeley.EDU San Francisco nike!ptsfa!vixie!paul@seismo.CSS.GOV CA 94116 paul@vixie.UUCP (415) 864-7013
wsr@lmi-angel.UUCP (01/21/87)
In article <> paul@vixie.UUCP (Paul Vixie Esq) writes: >I see that syslogd, inetd, cron, and the rest do NOT show 'co' as their >control terminal; how do I make this happen for me? try this: #include <sys/ioctl.h> fromlimbo () { int f; if ((f = open ("/dev/tty", 2)) >= 0) { ioctl (f, TIOCNOTTY, 0); close (f); } else perror ("open"); } -- Wolfgang Rupprecht {harvard|decvax!cca|mit-eddie}!lmi-angel!wsr
m5d@bobkat.UUCP (01/26/87)
In article <453@vixie.UUCP> paul@vixie.UUCP (Paul Vixie Esq) writes: >I have a program that forks itself and exits upon running -- its child >process runs as a daemon forever after. In 'ps aux', I notice that it >still shows my tty as its control terminal -- even if I log out and >back in. > >I see that syslogd, inetd, cron, and the rest do NOT show 'co' as their >control terminal; how do I make this happen for me? > >This is (more or less) BSD 4.2, and the program is setuid root. Thanks... >-- >Paul A. Vixie {ptsfa, qantel, crash, winfree}!vixie!paul >329 Noe Street dual!ptsfa!vixie!paul@ucbvax.Berkeley.EDU >San Francisco nike!ptsfa!vixie!paul@seismo.CSS.GOV >CA 94116 paul@vixie.UUCP (415) 864-7013 My guess is that the other daemons you mentioned are started in the "rc" command file. I think that "init" runs this with no standard file descriptors, or maybe with /dev/null. So far as I know, you can't get rid of the control terminal. You might try fiddling with the process group, although the shell will grab the tty back anyway. All this makes me wonder. I don't have source; all the stuff I know I've figured out through conjecture and the documentation. If I ask a question, and somebody who has source looks up the answer and posts it, will the Unix police come and gun us all down? -- **** **** **** At Digital Lynx, we're almost in Garland, but not quite **** **** **** Mike McNally Digital Lynx Inc. Software (not hardware) Person Dallas TX 75243 uucp: {texsun,killer,infotel}!pollux!bobkat!m5d (214) 238-7474
cudcv@warwick.UUCP (01/28/87)
In article <118@lmi-angel.UUCP> wsr@lmi-angel.UUCP (Wolfgang Rupprecht) writes: |In article <> paul@vixie.UUCP (Paul Vixie Esq) writes: |>I see that syslogd, inetd, cron, and the rest do NOT show 'co' as their |>control terminal; how do I make this happen for me? | |try this: | |#include <sys/ioctl.h> | |fromlimbo () |{ | int f; | | if ((f = open ("/dev/tty", 2)) >= 0) | { | ioctl (f, TIOCNOTTY, 0); | close (f); | } | else | perror ("open"); |} |-- |Wolfgang Rupprecht {harvard|decvax!cca|mit-eddie}!lmi-angel!wsr I would have thought the 'else perror(...);' was undesirable. If you can't open /dev/tty it probably means you're already without a controlling terminal and the ioctl is simply unecessary. Don't you want a setpgrp(getpid()); after that, too, to fully dissociate it from the terminal (otherwise when you hit ^C, you'll still get the signal). -- UUCP: ...!mcvax!ukc!warwick!cudcv PHONE: +44 203 523037 JANET: cudcv@uk.ac.warwick.daisy ARPA: cudcv@daisy.warwick.ac.uk Rob McMahon, Computing Services, Warwick University, Coventry CV4 7AL, England
mb@ttidca.UUCP (01/29/87)
In article <471@bobkat.UUCP> m5d@bobkat.UUCP (Mike McNally (dlsh)) answers paul@vixie.UUCP (Paul Vixie Esq)'s question: >>I see that syslogd, inetd, cron, and the rest do NOT show 'co' as their >>control terminal; how do I make this happen for me? with: > So far as I know, you can't get >rid of the control terminal. You might try fiddling with the process >group, although the shell will grab the tty back anyway. Since the original question was about 4.2BSD, the answer is to use the TIOCNOTTY ioctl. When we were converting from 4.1BSD to 4.2BSD, we had to take a somewhat different tack. We had an xns based network (without remote login capability - normally used for file transfer only) on the 4.1 systems which we brought up on our then sole 4.2 system while preparing to convert. To make it convenient for users to try out 4.2 and still be able to work on 4.1 without first logging out from the 4.2 system, I put together an rlogin/rlogind style pair for the xns based network, but had to deal with the control terminal problem, which caused a number of problems (including some involving getpass(), which still has, and probably always has had, a bug in the assumptions it makes about what fdopen will do/return when passed a -1 file descriptor). I couldnt afford the downtime needed to add and test a new ioctl, so I ended up using the following hack in the rlogind-like program on the 4.1 side: { /* reset detach flag */ struct proc p; int fd,t,pa; struct user *up = (struct user *)( 0x80000000-UPAGES*NBPG); int tpgrp; /* turned out I didnt have to use this, but on another system one might have to. */ fd = open("/dev/kmem",2); lseek(fd,up->u_procp,0); read(fd,&p,sizeof(p)); lseek(fd,up->u_procp,0); p.p_flag &= ~SDETACH; write(fd,&p,sizeof(p)); close(fd); } (void) close(slave); setdefaults(0); While it did the job, it certainly was not a clean way to go. Among other things, it would have been better to just write p.pflag, rather than all of p. Aesthetically it was broken, but in behavior it wasn't, so since nothing bad seemed to be happening, and there were lots of other tasks at hand, I left it as it was, for the couple of weeks it was needed. In this case, I needed to be able to have a control terminal that was the pty I was using. Something similar to the above could probably be used for related purposes as well.
guy@gorodish.UUCP (01/29/87)
>My guess is that the other daemons you mentioned are started in the >"rc" command file. I think that "init" runs this with no standard file >descriptors, or maybe with /dev/null. So far as I know, you can't get >rid of the control terminal. Well, yes, those other daemons are generally started from "/etc/rc" or "/etc/rc.local". However, most (if not all) such daemons manage to detach themselves from their control terminal even if they're run from such a terminal, so you *can* get rid of it. >If I ask a question, and somebody who has source looks up the answer >and posts it, will the Unix police come and gun us all down? Not unless they notice it, it's in violation of somebody's trade secret, and they decide to do something about it. In this case, the code was written at Berkeley and isn't covered by any trade secret restrictions, so here it is: #include <fcntl.h> #include <sys/ioctl.h> ... int tty_fd; tty_fd = open("/dev/tty", O_RDWR); /* any open mode will do */ if (tty_fd >= 0) { if (ioctl(tty_fd, TIOCNOTTY, 0) < 0) perror("Couldn't detach from controlling terminal"); (void) close(tty_fd); } That will be sufficient to detach you from your controlling terminal and set your process group back to 0.
oattes@utmanitou.toronto.edu (Lee Oattes) (01/30/87)
In article <118@lmi-angel.UUCP> wsr@lmi-angel.UUCP (Wolfgang Rupprecht) writes: >In article <> paul@vixie.UUCP (Paul Vixie Esq) writes: >>I see that syslogd, inetd, cron, and the rest do NOT show 'co' as their >>control terminal; how do I make this happen for me? > >try this: > if ((f = open ("/dev/tty", 2)) >= 0) > { > ioctl (f, TIOCNOTTY, 0); > close (f); > } >Wolfgang Rupprecht {harvard|decvax!cca|mit-eddie}!lmi-angel!wsr To this reply I would add that the following does a more complete job: #include <sys/ioctl.h> #include <sys/file.h> if( -1 == (fd = open("/dev/tty",O_RDWR)) ){ fprintf(stderr,"could not open controlling terminal!\n"); exit(-1); } if( -1 == ioctl(fd,TIOCNOTTY,0) ) { fprintf(stderr,"could not unlink conrolling terminal!\n"); exit(-1); } freopen("/dev/null","r",stdin); freopen("/dev/null","w",stdout); freopen("/dev/null","w",stderr); This will remove the process from a "tty" and also close off the standard connections to that "tty". We use this to run jobs from phone lines which will continue to run after we log off. If we do not remove the job from the phone line "tty" they cause the kernel to think that (correctly) the device is open and will not allow dialouts thru that device. Lee Oattes {ihnp4!utzoo!, seismo!utai!, decvax!utcsri!, watmath!utai!} utmanitou!oattes
postman#@andrew.cmu.edu.UUCP (01/31/87)
ReSent-To:nntp-xmit#@andrew.cmu.edu Return-path: <zs01#@andrew.cmu.edu> To: outnews#ext.nn.comp.unix.wizards@andrew.cmu.edu, m5d@bobkat.UUCP (Mike McNally (dlsh)), paul@vixie.UUCP In-Reply-To: <471@bobkat.UUCP> I had a lot of fun trying to figure out process groups and control terminals under BSD 4.2. There was this bug where I couldn't open /dev/tty in a certain process (ENXIO error). So after spending a year looking for it in my code, I got access to kernel sources. Here is what I found. The kernel's idea of a process without a control terminal is one who's process group is zero. It also has a pointer to the device, if this is NULL, you don't have a control terminal. The documentation doesn't help here, either you read the source or you lose. It says that if you have no control terminal and you open another tty, it will become your control terminal. What really happens is that if your process group is 0 and you open a tty, it becomes your control terminal. If your process group is non-zero, and that pointer is NULL, /dev/tty remains broken. Getting rid of a control terminal is pretty easy. The following code (strictly BSD 4.2) will do it: #include <stdio.h> #include <sys/file.h> #include <ioctl.h> void NukeControlTerminal() { int fd; if ((fd = open("/dev/tty", O_RDWR)) >= 0) { ioctl(fd, TIOCNOTTY, NULL); close(fd); } else /* Insert real error handling here... */ printf("Couldn't open control terminal, errno = %d\n", errno); } My bug was caused by setting the process group and then trying to open /dev/tty. Since I really didn't have a control terminal (i.e. pointer was NULL), it returned EXNIO. But when I opened another tty, it did not become /dev/tty (because my process group was not 0). There are a number of other problems you can get into by changing the process group of a terminal (or of your process), and then trying to do an ioctl on it. For example where you wish to fork a child, and have a terminal in the child's process group but not in yours. If you do the process group switching in the wrong order, you will not be able to ioctl the terminal into the target process group... Sincerely, Zalman Stern Information Technology Center Carnegie Mellon University zs01@andrew.cmu.edu
hedrick@topaz.UUCP (01/31/87)
One should perhaps note that after disinheriting your terminal by using TIOCNOTTY, if you open any terminal, that becomes your controlling terminal. This can happen in unexpected ways. Under 4.3 [more or less] we found that inetd was mysteriously getting connected to the console. This caused very odd results. Like every time somebody tried to log in via rlogin, they would get disconnected, and whatever job happened to be logged in on the console would get logged out. Anyway, the problem turned out to be that inetd was calling syslog, syslog was trying to open a network connection to loghost, this was failing, and so syslog then opened the console.
guy%gorodish@Sun.COM (Guy Harris) (02/01/87)
>To this reply I would add that the following does a more complete job:
While you're at it, you might also want to ream out the environment;
you may not want to inherit the PATH, USER/LOGNAME, IFS, etc., etc.,
etc. values that the person who ran the daemon used.
guy@gorodish.UUCP (02/02/87)
>I would have thought the 'else perror(...);' was undesirable. If you can't >open /dev/tty it probably means you're already without a controlling terminal >and the ioctl is simply unecessary. True. The standard idiom in all the daemons I've seen omits the "perror". You can, instead, check for errno == ENXIO, and only print the error message if it's *not* ENXIO, since the "/dev/tty" driver returns ENXIO if you don't have a controlling terminal. > Don't you want a > > setpgrp(getpid()); > >after that, too, to fully dissociate it from the terminal (otherwise when you >hit ^C, you'll still get the signal). Nope. First of all, "setpgrp" in 4BSD takes two arguments, so it would be setpgrp(0, getpid()); and second, TIOCNOTTY *really* disassociates you from the terminal, so it's not necessary. TIOCNOTTY sets your process group ID to 0.