kevin@nuchat.UUCP (Kevin Brown) (01/06/91)
Sorry for the length of this article, but I'm describing the manifestation of a bug in Minix in detail. Perhaps the detailed description I provide below will help people track this thing down. I have been having some rather strange problems with the Minix console driver on my system. This problem occurs seemingly regardless of WHAT console driver you're using. It occurs with Gordon Irlam's virtual console driver running under Minix-386 (thanks, Bruce!), and it occurs on vintage PC-Minix 1.5.10 (floppy version, no frills). Allow me to explain in the context of virtual consoles, which is where I originally thought the problem actually existed: When running an application like less, which can act as the tail end of a pipe but which takes input from the terminal, if I shell out of such an application (thus getting me a subshell with the standard '$' prompt) and, when the prompt is displayed, hit the INT key (usually the delete key), all my processes for that terminal will die (and I'll be given the login prompt). Now, less doesn't know what terminal you're running on, and since it has to be able to act as a member of a pipe, it will open /dev/tty as standard input and standard output before executing the shell. Quite reasonable, right? I thought that less was the cause of the problem, but it's not. Do the following: sh </dev/tty Now hit the INT key. Your shell and your subshell will go away, and you'll get the login prompt back. In fact, when I do this with the basic P-H 1.5.10 system, I get "login:" repeatedly printed on my screen until I hit <return>, at which point it stops and gives me the login prompt and will then accept a login. I don't understand this behavior at all. Since the virtual console driver knows which virtual console you're on, it (supposedly) just sends a SIGINT to the process group leader associated with the virtual terminal from which the INT key was pressed. At the point that you press the INT key, all the processes associated with the terminal (including the process group leader) are either catching SIGINT or ignoring it. Were this not the case, you would be able to simply do a "sh", which gives you a subshell, hit INT, and get the same results. This doesn't happen. In fact, let's say that you're on virtual terminal tty4. If you do a "sh </dev/tty", as above, and hit the INT key, then all your processes go away and you get the login: prompt. HOWEVER, if you do a "sh </dev/tty4", things work properly (note: for those of you who do not have virtual consoles, substitute /dev/tty0 for /dev/tty4, and you'll see the same behavior. Works fine for /dev/tty0 but not for /dev/tty). Aha, I thought, this means that the ACTUAL terminal has to be "opened" like the rest. The only place in which it is really proper to distinguish between devices is in fs/device.c, right? So I went there and implemented code that would, if it saw that /dev/tty was being opened, fix up the message and pass it on such that the actual control terminal would be opened. Since doing a "sh </dev/ttyN" works, I figured that this was the problem. I was wrong. If it's related to the actual inode of the device that's being opened, then I can't immediately conceive of an elegant solution to the problem. I don't much like the idea, nor can I conceive of a reasonable way, of putting in code to fetch the inode of the REAL terminal that's being referenced when /dev/tty is being opened. Other symptoms: if you're running a virtual console system, or have an external terminal attached (I don't know if you get this behavior from an external terminal, but my money says you will), you can log into the console (or a virtual console), do the "sh </dev/tty", and then send signals to the processes on the console you logged into from your other session. Let's say that the original shell process that's attached to the console is process 41, and the subshell (which is taking its input from /dev/tty) is process 42. If you do a "kill 41", nothing happens (kill without a switch, e.g. -9, sends a SIGINT to the specified process), regardless of where you do it from. If you do a "kill 42" from the terminal in which you're running the subshell, nothing happens (which is the way it should be). HOWEVER, if you do a "kill 42" from the OTHER terminal, all the processes for the console go away and you get a login prompt on the console. In other words, if you do a "sh </dev/tty", then try to SIGINT the subshell process WHILE IT'S WAITING ON A PROCESS, then there's no effect (which is the right behavior). But if you SIGINT the subshell process (either via the INT key or via a kill command) when it's waiting for input, it and all its parents will die. SIGINTing the parent of the subshell does nothing (which is the way it should be). Help! I don't understand at all what the @#$@#!! is going on here. It's almost as if doing a "sh </dev/tty" blows away the signal masks of all the processes associated with the control terminal, but there's no code in there that's actually doing any such thing that I've seen. And why would doing "sh </dev/tty" result in the above behavior while doing "sh </dev/tty0" won't? I'm baffled...:-( The problem happens regardless of which version of init or anything else I'm running. It happens with both 16 and 32 bit versions. It happens with Minix 1.5.10 as distributed by PH. Whatever it is, it's caused by code that's common to all these different flavors of 1.5.10. Can the Atari people speak up and tell us if ST-Minix behaves the same way? Has anyone else experienced these problems? Has anyone else found a fix? It's not a devastating problem, mind you (if you run a program from the subshell with input from /dev/tty, and hit INT while running it, everything works fine. I'm SOOOO confused!), but it's quite annoying. I don't know about you, but I *don't* like weird behavior like this in my operating system. :-( It could be worse. I *could* be having hard drive problems...:-) Thanks in advance. -- Kevin Brown Addresses in preferred order: csci31f7@cl.uh.edu nuchat!kevin@uunet.uu.net
HBO043%DJUKFA11.BITNET@cunyvm.cuny.edu (Christoph van Wuellen) (01/07/91)
I remember that I have seen parts of that strange behaviour on my 68K MINIX-1.5 system (especially repeated login: prompts after hitting the DEL key). C.v.W.
joerg@mwtech.UUCP (Joerg Werner) (01/12/91)
In article <1991Jan6.042939.10130@menudo.uh.edu> uace0@menudo.uh.edu.UUCP (ATARI Computer Enthusiasts) writes: >I thought that less was the cause of the problem, but it's not. Do the >following: > sh </dev/tty > >Now hit the INT key. Your shell and your subshell will go away, and you'll >get the login prompt back. In fact, when I do this with the basic P-H 1.5.10 >system, I get "login:" repeatedly printed on my screen until I hit <return>, >at which point it stops and gives me the login prompt and will then accept >a login. I have a similar problem, maybe the same:-). It occurs if /etc/rc executes the following program: #include <signal.h> trap() {exit(1);} main() { char buf[256]; signal(SIGALRM,trap); alarm(5); printf("Hit <Return> or wait 5 seconds.\n"); read(0,buf,sizeof(buf)); exit(0); } If I wait and the alarm signal occurs, the login prompt is printed repeatedly and no login is accepted. >Aha, I thought, this means that the ACTUAL terminal has to be "opened" like >the rest. The only place in which it is really proper to distinguish >between devices is in fs/device.c, right? So I went there and implemented >code that would, if it saw that /dev/tty was being opened, fix up the >message and pass it on such that the actual control terminal would be >opened. Since doing a "sh </dev/ttyN" works, I figured that this was the >problem. I was wrong. If it's related to the actual inode of the device The problem lies indeed in fs/device.c. More specifically rw_dev2() is the hog. The global pointer `fp' points to the callers process table [Minix Manual, line 16266]. If the caller is a user process everything works fine. But sometimes MM calls the FS, and `fp' points to MM's process table, of course. That's the case if a signal is sent to a process. If the process is hanging on a system call (READ for example) the FS must be informed. But what happens if rw_dev2() is called now? The controlling tty of the MM is checked:-(( This means that fp->fs_tty is always 0, and the message is sent to the MEM task. A hanging read-call is n o t terminated!!! Luckily there is a easy way to find out which process table we need. The message contains the process number! Please have a look at the patch. I hope this helps (and if, please let me know). Ciao Joerg PS: I'm using MINIX ST 1.5.[10.3]. BTW, the result of two days work, was a 2 line patch :-) ------------------------ cut here ------------------------------- *** /usr/src.1.5.10.3/fs/device.c Tue Nov 20 21:19:33 1990 --- /usr/src/fs/device.c Thu Dec 27 16:26:58 1990 *************** *** 188,193 **** --- 188,196 ---- */ int task_nr, major_device; + register struct fproc *fp; + + fp = &fproc[ mess_ptr->PROC_NR ]; if (fp->fs_tty == 0) { mess_ptr->DEVICE = NULL_DEV; ------------------------ cut here ------------------------------- -- Joerg Werner, email: joerg@mwtech.UUCP, voice: 49-(0)6151-37 33 66