Path: utzoo!news-server.csri.toronto.edu!cs.utexas.edu!sdd.hp.com!elroy.jpl.nasa.gov!lll-winken!taco!mcnc!rti!mcm From: mcm@rti.rti.org (Mike Mitchell) Newsgroups: comp.unix.ultrix Subject: Re: Xterminals and dxsession (summary - long) Summary: dxsession has process group problems Keywords: Xterminals dxsession Message-ID: <1991Mar14.183509.24302@rti.rti.org> Date: 14 Mar 91 18:35:09 GMT References: <1214@usage.csd.unsw.oz.au> Organization: Research Triangle Institute, RTP, NC Lines: 161 In article <1214@usage.csd.unsw.oz.au> Michael Ashley wrote about his promblems with Xterminals and dxsession. We have just received some software that turns VAXstation 2000's into Xterminals, and I've had many of the same problems. With the help of a home-grown system-call tracing facility and a friend with Ultrix 3.1 source, I've found some serious bugs in dxsession. The first bug is that it calls 'getpgrp' with the wrong number of arguments. It calls 'getpgrp' with no arguments, which is fine IF THE PROGRAM WAS COMPILED IN THE POSIX ENVIRONMENT (which it is NOT). The next bug is that it calls 'setpgrp' with the wrong number of arguments. It calls 'setpgrp' with one argument, which is WRONG for both SYSV and Berkeley forms of the call. The next problem is that dxsession doesn't try hard enough to kill off its children. It only sends a SIGHUP to the process group, when it should send a SIGHUP, wait, send a SIGTERM, wait, then send a SIGKILL. Back to the BIG problems. The original intention of calling 'getpgrp' is to find out if dxsession is in process group 0 or 1. If it dxsession is in either of these groups, a new process group is entered by calling 'setpgrp'. Later when the quit box is clicked, dxsession does a 'killpg(1, getpgrp());' and then exits. Well, the 'if' statement that checks for process group 0 or 1 does not check for an error return, so if the 'getpgrp()' fails, dxsession assumes it is already in a process group. The 'getpgrp()' will fail, because the pid to search for was NOT passed in, and the system call gets garbage from the stack. If they had said 'getpgrp(0)', the code would be correct. Now then, if the dxsession is in process group 0 or 1, the setpgrp call gets executed. It is of the form 'setpgrp(getpid())'. Under SYSV, setpgrp takes no arguments, and under Berkeley, it takes two. This has the desired effect I guess, as the process group of process id 'getpid()' will be set to some random value that was left on the stack. However, if there is more than one dxsession running on your system, it is very likely they took the same path to get to the 'setpgrp' call, so the same value is probably on the stack. The net result is that everyone is running in the same process group. This explains why when one person is logged in twice and logs out in one window, both windows get killed. To fix these problems, I put a wrapper program around the invocation of dxsession. This program forks, the child puts itself in its own process group, and then execs dxsession. The parent waits for dxsession to terminate, then it does a killpg with a SIGTERM. Five seconds later it does a killpg with a SIGKILL, then it exits. I'm including my scripts and program below. In my /etc/ttys file I have: xterm1:0 "/local/etc/startwindow xterm1::0" none on secure Init will pass to the startwindow script the 'xterm1::0' argument. The startwindow script looks like: #! /bin/sh # # `login' needs an extra argument as a tty name. Without it, getttyname # dumps core. Luckily, it passes the name in to the Xprompter, and the # Xprompter uses that as a display name. # DISPLAY=${1} export DISPLAY exec /usr/bin/login -P /usr/bin/Xprompter -C /local/etc/dxsession ${DISPLAY} The whole reason for the script is to set the environment variable for the display. Our version of dxsession is again a script, which contains the following: #! /bin/sh exec /local/etc/newpgrp /usr/bin/dxsession ${1+"$@"} And the program 'newpgrp' is the following: /* * This program forks and execs its argument list. It puts * the child in its own process group. It waits for the * child to terminate, and then sends a SIGTERM to the * process group. Five seconds later it sends a SIGKILL * to the process group. The parent exits with the * same status as the original child. * * The purpose of this program is to put an 'Xsession' program * in a process group, then kill off all of the clients when the * 'Xsession' program terminates. This is used to support the * Xterminal software on the VaxStation 2000s. */ #include #include #include #include main(argc, argv) int argc; char *argv[]; { int i, rc; long s; /* wait status */ if (argc > 1) { if ((i = fork()) == 0) { i = getpid(); setpgrp(i, i); /* set process group to pid */ execvp(argv[1], &argv[1]); perror(argv[1]); /* couldn't exec, tell why */ exit(127); } /* wait for child to terminate */ while((rc = wait(&s)) > 0) { /* * if the pid is the one we are waiting for, and * it is not stopped, break out of the loop. */ if (rc == i && !WIFSTOPPED(s)) break; } /* * Send a SIGTERM, and if that succeeds, send a SIGKILL */ if (killpg(i, SIGTERM) == 0) { sleep(5); (void) killpg(i, SIGKILL); } /* * if the child exited due to a signal, signal * ourselves with the same signal. Hopefully * we will exit the same way. */ if (WIFSIGNALED(s)) (void) kill(getpid(), WTERMSIG(s)); /* * Now exit with the same exit status as the child */ exit(WEXITSTATUS(s)); } /* * Here there were no arguments, so exit with an error code. */ exit(127); } ----------------------------------------------------------- Mike Mitchell mcm@rti.rti.org uunet!rti!mcm "There's laughter where I used to see a tear. (919) 541-6098 It's all done with mirrors, have no fear." -- Mike Mitchell mcm@rti.rti.org uunet!rti!mcm "There's laughter where I used to see a tear. (919) 541-6098 It's all done with mirrors, have no fear."