jsv@cci632.UUCP ( co-op) (03/06/90)
I have a program written in C that captures the HUP signal sent when a user logs out and prints some information to a file. This program works fine on System V but on BSD machines, the program doesn't seem to get the signal and when I log back on, it's still running (the interrupt function on this signal has an exit() in it) and nothing was written to the file. I know the program understands the signal, because when I execute: % kill -HUP <pid> the program ends (on both systems) properly. Any ideas as to why? Jepher ------------------- Jeffer Veiss Rochester Institute of Technology | Computer Consoles, Inc. JSV9504@RITVAX.BITNET | jsv@cci632.uucp jsv9504@ritcv.uucp | Disclaimer? yeah, right.
jik@athena.mit.edu (Jonathan I. Kamens) (03/06/90)
In article <34853@cci632.UUCP>, Jeffer Veis (jsv@cci632.UUCP) asks why
a program waiting for a HUP signal (which it should get when the user
logs out) gets the signal when it is run under System V, but never
receives the signal when it is run under BSD.
The likely explanation of this is that you are using the C shell (csh)
on the BSD machine, rather than the bourne shell (sh). While sh
automatically sends a HUP signal to all its children when you log out
(actually, I'm not sure the shell does this actively; it's might be a
side-effect of the way and process groups et al work in BSD), this
doesn't happen in csh. Therefore, the reason your process is not
getting the signal is because the signal is never sent.
Here at Project Athena, we have a hack in our /bin/login which makes
it possible to do what you want, although I don't know how universal
this is (it isn't in the vanilla 4.3-tahoe sources, which means it isn't
a standard 4.3bsd thing). After the child process (i.e. the login
shell) of /bin/login exits, /bin/login does "killpg(child, SIGHUP)",
where "child" is the process group of the child.
Then, any process that wants to get a HUP signal when it logs out,
after being placed into the background upon start-up, simply does
"setpgrp(0, getpgrp(getppid()))". In other words, "Make my process
group the same as the process group of my parent." This overrides the
default csh behavior of creating a new process group for each child
process it runs.
I don't know if there's any other way (that is more universally
available, and doesn't require modifications to /bin/login) to do what
you want effectively, other than having your process periodically check
the status of the parent process, by doing "kill(getppid(), 0)", and
assuming that the user has logged out when this kill returns an error.
I hope this is helpful.
Jonathan Kamens USnail:
MIT Project Athena 11 Ashford Terrace
jik@Athena.MIT.EDU Allston, MA 02134
Office: 617-253-8495 Home: 617-782-0710
maart@cs.vu.nl (Maarten Litmaath) (03/07/90)
In article <1990Mar6.070333.29327@athena.mit.edu>, jik@athena.mit.edu (Jonathan I. Kamens) writes: )... While sh )automatically sends a HUP signal to all its children when you log out )(actually, I'm not sure the shell does this actively; it's might be a )side-effect of the way and process groups et al work in BSD), this It's always been the kernel. Quoting from termio(4) on SunOS 4.0.3c: Modem Disconnect If a modem disconnect is detected, and the CLOCAL flag is not set in the c_cflag field, a SIGHUP signal is sent to all processes in the distinguished process group associated with this terminal. Unless other arrangements have been made, this signal terminates the processes. If SIGHUP is ignored or caught, any subsequent read() returns with an end-of-file indication until the terminal is closed. Thus, programs that read a terminal and test for end-of-file can terminate appropriately after a disconnect. Any subsequent write() will return -1 and set errno to EIO until the terminal is closed. )doesn't happen in csh. Therefore, the reason your process is not )getting the signal is because the signal is never sent. ...because csh puts each job into its own process group and a the group of a background job never equals the tty process group (by definition!). ) Here at Project Athena, we have a hack in our /bin/login which makes )it possible to do what you want, although I don't know how universal )this is (it isn't in the vanilla 4.3-tahoe sources, which means it isn't )a standard 4.3bsd thing). After the child process (i.e. the login )shell) of /bin/login exits, /bin/login does "killpg(child, SIGHUP)", )where "child" is the process group of the child. Why don't you let the kernel or init(8) do the killpg()? Now you have an extra process hanging around, doing nothing but wait()ing. ) Then, any process that wants to get a HUP signal when it logs out, )after being placed into the background upon start-up, simply does )"setpgrp(0, getpgrp(getppid()))". In other words, "Make my process )group the same as the process group of my parent." This overrides the )default csh behavior of creating a new process group for each child )process it runs. [...] I assume you wrote a utility `hup' (the opposite of nohup(1)) too: a) to do this setpgrp() for you (!) b) to catch the keyboard signals (!!) -- "Belfast: a sentimental journey to the Dark Ages - Crusades & Witchburning - Europe's Lebanon - Book Now!" | maart@cs.vu.nl, uunet!mcsun!botter!maart
jik@athena.mit.edu (Jonathan I. Kamens) (03/08/90)
In article <5913@star.cs.vu.nl>, maart@cs.vu.nl (Maarten Litmaath) writes: > It's always been the kernel. Quoting from termio(4) on SunOS 4.0.3c: Well, first of all, it's tty(4) in BSD, which is what I was talking about. Just a a small nit :-) > )doesn't happen in csh. Therefore, the reason your process is not > )getting the signal is because the signal is never sent. > > ...because csh puts each job into its own process group and a the group of a > background job never equals the tty process group (by definition!). Yes, I should have let that specifically. > ) Here at Project Athena, we have a hack in our /bin/login which makes > )it possible to do what you want, although I don't know how universal > )this is (it isn't in the vanilla 4.3-tahoe sources, which means it isn't > )a standard 4.3bsd thing). After the child process (i.e. the login > )shell) of /bin/login exits, /bin/login does "killpg(child, SIGHUP)", > )where "child" is the process group of the child. > > Why don't you let the kernel or init(8) do the killpg()? Now you have an > extra process hanging around, doing nothing but wait()ing. Because I believe that the kernel SIGHUP functionality only works when a dialup line or a hard-wired terminal line (i.e. something that init deals with, I believe) is the login tty in question. We don't use hard-wired tty's here at Project Athena, we use pty's almost exclusively (Remember, the X Window System was INVENTED at Project Athena :-). > I assume you wrote a utility `hup' (the opposite of nohup(1)) too: No, actually, although it's an interesting idea. I'll have to think about it some more :-) > a) to do this setpgrp() for you (!) > b) to catch the keyboard signals (!!) What do you mean by "keyboard signals"?? Jonathan Kamens USnail: MIT Project Athena 11 Ashford Terrace jik@Athena.MIT.EDU Allston, MA 02134 Office: 617-253-8495 Home: 617-782-0710
maart@cs.vu.nl (Maarten Litmaath) (03/09/90)
In article <1990Mar8.084830.9252@athena.mit.edu>, jik@athena.mit.edu (Jonathan I. Kamens) writes: )... )> ) Here at Project Athena, we have a hack in our /bin/login which makes )> )it possible to do what you want, although I don't know how universal )> )this is (it isn't in the vanilla 4.3-tahoe sources, which means it isn't )> )a standard 4.3bsd thing). After the child process (i.e. the login )> )shell) of /bin/login exits, /bin/login does "killpg(child, SIGHUP)", )> )where "child" is the process group of the child. )> )> Why don't you let the kernel or init(8) do the killpg()? Now you have an )> extra process hanging around, doing nothing but wait()ing. ) ) Because I believe that the kernel SIGHUP functionality only works when )a dialup line or a hard-wired terminal line (i.e. something that init )deals with, I believe) is the login tty in question. Not necessarily. Here's a little excerpt from the SunOS pty `deallocate' routine: if (tp->t_state & TS_ISOPEN) gsignal(tp->t_pgrp, SIGHUP); tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ You're right insofar that init(8) can't offer the SIGHUP service for ptys. )... )> I assume you wrote a utility `hup' (the opposite of nohup(1)) too: )... )> a) to do this setpgrp() for you (!) )> b) to catch the keyboard signals (!!) ) ) What do you mean by "keyboard signals"?? If you setpgrp() to your parent's group, and this parent happens to be in the foreground, *you* will receive keyboard signals too. % cat c.c main() { if (setpgrp(0, getpgrp(getppid())) < 0) perror("setpgrp"); pause(); } % cc c.c % a.out & [1] 6338 % ^? [1] a.out % kill -0 6338 6338: No such process % a.out & [1] 6349 % ^\ [1] Quit a.out (core dumped) % Remarks: - `^?' denotes `DEL' (interrupt); - csh seems to get confused about process 6338. -- 1) Will 4.5BSD have wait5()? |Maarten Litmaath @ VU Amsterdam: 2) Sleep(3) should be sleep(2) again.|maart@cs.vu.nl, uunet!mcsun!botter!maart
guy@auspex.auspex.com (Guy Harris) (03/10/90)
> Because I believe that the kernel SIGHUP functionality only works when >a dialup line or a hard-wired terminal line (i.e. something that init >deals with, I believe) is the login tty in question. Well, it's a bit more complicated. Your original article said: > While sh automatically sends a HUP signal to all its children when you > log out (actually, I'm not sure the shell does this actively; it's > might be a side-effect of the way and process groups et al work in > BSD) ... and Maarten replied: > It's always been the kernel. Quoting from termio(4) on SunOS 4.0.3c: > > Modem Disconnect > If a modem disconnect is detected, and the CLOCAL flag is > not set in the c_cflag field, a SIGHUP signal is sent to all > processes in the distinguished process group associated with > this terminal. ... The latter has been true since Time Immemorial; however, it only delivers the SIGHUP if you actually get a "modem disconnect". Note, though, that both the 4.3BSD and SunOS 4.x pseudo-tty drivers (and, I suspect, the S5R4 pseudo-tty mechanism as well) treat the final "close" of the controller side of a pseudo-tty as being the moral equivalent of a "modem disconnect", and send a SIGHUP exactly as it's done for Carrier Detect dropping on a "real" tty line. So your belief that the kernel SIGHUP functionality only works on a dialup or hardwired terminal line is incorrect; it works on pseudo-ttys as well. However, there is *another* source of SIGHUP. In BSD, "getty", "rlogind", and "telnetd" issue a "vhangup" call on the tty they're using, in order to blow any old processes off that line. One consequence of "vhangup" is that, if the tty is still open, a SIGHUP gets sent to its process group. In System V, when a "process group leader" (a login shell, for example) exits, and: 1) it has a controlling tty and 2) that tty's process group is the process group of which that process is a leader, a SIGHUP is given to that process group. Of course, if you have a job control shell, neither of the SIGHUPs mentioned above will reach background processes, as stated by Maarten.
jik@athena.mit.edu (Jonathan I. Kamens) (03/12/90)
Well, I've looked in my kernel code, and I do, indeed, see code that *should be* sending a HUP signal to the process group of the tty, although I may certainly be reading something wrong, given that I have limited experience with kernel hacking. I then compiled a new /bin/login for testing -- the new /bin/login doesn't do anything with killpg(), because I'm trying to figure out if the kernel does it automatically. I then compiled the following program, telnet'd into my workstation (thus, I assume logging in on a pty), ran it in the background, and logged out: #include <syslog.h> #include <signal.h> report_it() { syslog(LOG_DEBUG, "Got a SIGHUP!"); exit(0); } main() { signal(SIGHUP, report_it); setpgrp(0, getpgrp(getppid())); for (;;) sigpause(0); } Now, *if* the kernel sends a HUP when a pty is closed, then the program should have received a HUP and exited when I logged out, right? Well, it didn't. How come? When I put back our standard /bin/login with the killpg() statement in it and do the same thing, the program does get a HUP when I log out. So what am I missing? One more thing -- I think that someone else asked earlier what the point is of having /bin/login wait around while the user is logged in -- he said that if we take out the killpg() in /bin/login, we can just have it exec() the login shell rather than waiting for the shell to finish. Well, unfortunately, we can't do that, because our /bin/login does various other clean-up tasks after the user logs out (e.g. removing the user's entry from the /etc/passwd file if he was added to the /etc/passwd file when he logged in, and automatically destroying the user's kerberos tickets). Therefore, exec()'ing the login shell isn't an option. Jonathan Kamens USnail: MIT Project Athena 11 Ashford Terrace jik@Athena.MIT.EDU Allston, MA 02134 Office: 617-253-8495 Home: 617-782-0710
rr@csuna.cs.uh.edu (Ravindran Ramachandran) (03/14/90)
In article <1990Mar8.084830.9252@athena.mit.edu> jik@athena.mit.edu (Jonathan I. Kamens) writes: >In article <5913@star.cs.vu.nl>, maart@cs.vu.nl (Maarten Litmaath) writes: >> )doesn't happen in csh. Therefore, the reason your process is not >> )getting the signal is because the signal is never sent. >> >> ...because csh puts each job into its own process group and a the group of a >> background job never equals the tty process group (by definition!). > I had a similar kind of a problem on a Pyramid running ATT Sys 5, having csh as the base shell. I have a Bourne shell script that is started up from my .login, which runs a clock at the top corner of my tty. When I log out, however, the process remains active even though there is no actual device to output to. I tried in the script to 'trap' the signals, but they are not received on logout. The suggestion to: a) set setpgrp() is slightly a pain in a shell script. b) modify /bin/login (?) is impossible for me. Right now, in my .logout I do a ps, and use awk to get the pid so that I can explicitly kill the process. However, I wish the script would directly get the signal when I logout and expire! For your eyes only (please destroy after reading), --Ravi-