source: trunk/athena/bin/session/session_gate.c @ 8892

Revision 8892, 9.7 KB checked in by ghudson, 28 years ago (diff)
BSD -> ANSI string and memory functions
Line 
1/*
2 *  session_gate - Keeps session alive by continuing to run
3 *
4 *      $Source: /afs/dev.mit.edu/source/repository/athena/bin/session/session_gate.c,v $
5 *      $Header: /afs/dev.mit.edu/source/repository/athena/bin/session/session_gate.c,v 1.13 1996-09-20 03:19:29 ghudson Exp $
6 *      $Author: ghudson $
7 */
8
9#include <signal.h>
10#include <string.h>
11#ifdef SOLARIS
12#include <sys/fcntl.h>
13#endif
14#include <sys/types.h>
15#include <sys/file.h>
16#include <sys/stat.h>
17#include <sys/wait.h>
18
19#ifdef SGISession
20#include <stdio.h>
21#include <errno.h>
22#include <X11/Xlib.h>
23
24Display *dpy;
25Window root;
26Atom sessionAtom, wmAtom;
27int logoutsignal = 0;
28int SGISession_debug = 0;
29
30#define SGISession_TIMEOUT 1
31#define SGISession_ATHENALOGOUT 2
32#define SGISession_SGILOGOUT 3
33
34#define SGISession_NOBODY 1
35#define SGISession_WMONLY 2
36#define SGISession_EVERYONE 3
37
38void flaglogout();
39void SGISession_EndSession(), SGISession_Debug();
40#endif
41
42#define BUFSIZ 1024
43#define MINUTE 60
44#define PID_FILE_TEMPLATE "/tmp/session_gate_pid."
45
46static char filename[80];
47
48void main( );
49int itoa( );
50void cleanup( );
51void logout( );
52void clean_child( );
53time_t check_pid_file( );
54time_t create_pid_file( );
55time_t update_pid_file( );
56void write_pid_to_file( );
57
58
59void main(argc, argv)
60int argc;
61char **argv;
62{
63    int pid;
64    int parentpid;
65    char buf[10];
66    time_t mtime;
67    int dologout = 0;
68#ifdef SGISession
69    int logoutStarted = 0;
70
71
72    while (*argv)
73      {
74        if (!strcmp(*argv, "-logout"))
75          dologout = 1;
76
77        if (!strcmp(*argv, "-debug"))
78          SGISession_debug = 1;
79
80        argv++;
81      }
82#else
83    if (argc == 2 && !strcmp(argv[1], "-logout"))
84      dologout = 1;
85#endif
86
87    pid = getpid();
88    parentpid = getppid();
89   
90    /*  Set up signal handlers for a clean exit  */
91
92#ifdef SGISession
93        signal(SIGHUP, flaglogout);
94        signal(SIGINT, flaglogout);
95        signal(SIGQUIT, flaglogout);
96        signal(SIGTERM, flaglogout);
97#else
98    if (dologout) {
99        signal(SIGHUP, logout);
100        signal(SIGINT, logout);
101        signal(SIGQUIT, logout);
102        signal(SIGTERM, logout);
103    } else {
104        signal(SIGHUP, cleanup);
105        signal(SIGINT, cleanup);
106        signal(SIGQUIT, cleanup);
107        signal(SIGTERM, cleanup);
108    }
109#endif
110
111#ifdef SYSV
112    sigset(SIGCHLD, clean_child);       /* Clean up zobmied children */
113#else
114    signal(SIGCHLD, clean_child);       /* Clean up zobmied children */
115#endif
116
117    /*  Figure out the filename  */
118
119    strcpy(filename, PID_FILE_TEMPLATE);
120    itoa(getuid(), buf);
121    strcat(filename, buf);
122
123    /*  Put pid in file for the first time  */
124
125    mtime = check_pid_file(filename, pid, (time_t)0);
126
127    /*
128     * Now sit and wait.  If a signal occurs, catch it, cleanup, and exit.
129     * Every minute, wake up and perform the following checks:
130     *   - If parent process does not exist, cleanup and exit.
131     *   - If pid file has been modified or is missing, refresh it.
132     */
133
134#ifdef SGISession
135#define goodbye() if (dologout) logout(); else cleanup()
136
137    if (0 == SGISession_Initialize())
138      {
139        SGISession_Debug("Gating an SGI session\n");
140        while (1)
141          {
142            switch(SGISession_Wait())
143              {
144              case SGISession_TIMEOUT: /* MINUTE passed */
145                SGISession_Debug("chime\n");
146                clean_child();  /* In case there are any zombied children */
147                if (parentpid != getppid())
148                  cleanup();
149                mtime = check_pid_file(filename, pid, mtime);
150                break;
151
152              case SGISession_ATHENALOGOUT: /* HUP signal */
153                SGISession_Debug("Received hangup\n");
154                logoutsignal = 0;
155                if (logoutStarted)
156                  {
157                    /* This is our second signal. Something bad must
158                       have happened the first time. Just log the user
159                       out. */
160                    SGISession_Debug("Second hangup; doing Athena logout\n");
161                    goodbye();
162                  }
163
164                logoutStarted = 1;
165                switch(SGISession_WhoCares())
166                  {
167                  case SGISession_NOBODY:
168                    SGISession_Debug("Nobody cares; doing Athena logout\n");
169                    goodbye();
170                    break;
171                  case SGISession_WMONLY:
172                    SGISession_Debug(
173"Window manager about cares session but reaper was not run;\n\
174calling endsession and doing Athena logout\n");
175                    SGISession_EndSession();
176                    goodbye();
177                    break;
178                  case SGISession_EVERYONE:
179                    SGISession_Debug(
180                     "starting endsession and waiting for window property\n");
181                    SGISession_EndSession();
182                    break;
183                  }
184                break;
185
186              case SGISession_SGILOGOUT: /* property deleted */
187                SGISession_Debug(
188                         "Window property deleted; doing Athena logout\n");
189                goodbye();
190                break;
191              }
192          }
193      }
194    else
195 SGISession_Debug("Gating a normal session; SGISession_Initialize failed\n");
196#endif
197   
198    while (1)
199      {
200          sleep(MINUTE);
201          clean_child();        /* In case there are any zombied children */
202          if (parentpid != getppid())
203            cleanup();
204          mtime = check_pid_file(filename, pid, mtime);
205      }
206}
207
208#ifdef SGISession
209int SGISession_Initialize()
210{
211  int screen;
212
213  dpy = XOpenDisplay(NULL);
214
215    if (dpy == NULL)
216      return -1;
217
218  screen = DefaultScreen(dpy);
219  root = RootWindow(dpy, screen);
220
221  sessionAtom = XInternAtom(dpy, "_SGI_SESSION_PROPERTY", False);
222  wmAtom = XInternAtom(dpy, "_SGI_TELL_WM", False);
223
224  XSelectInput(dpy, root, PropertyChangeMask);
225  return 0;
226}
227
228void flaglogout( )
229{
230  logoutsignal++;
231}
232
233int SGISession_Wait()
234{
235  static int initialized = 0;
236  static fd_set read;
237  static struct timeval timeout;
238  int selret;
239  XEvent event;
240
241  if (!initialized)
242    {
243      FD_ZERO(&read);
244      timeout.tv_sec = MINUTE;
245      timeout.tv_usec = 0;
246      initialized++;
247    }
248
249  while (1)
250    {
251      while (XPending(dpy) > 0)
252        {
253          if (logoutsignal)
254            return SGISession_ATHENALOGOUT;
255
256          XNextEvent(dpy, &event);
257          if (event.type == PropertyNotify &&
258              event.xproperty.atom == sessionAtom &&
259              event.xproperty.state == PropertyDelete)
260            return SGISession_SGILOGOUT;
261        }
262
263      FD_SET(ConnectionNumber(dpy), &read);
264
265      if (logoutsignal)
266        return SGISession_ATHENALOGOUT;
267
268      selret = select(ConnectionNumber(dpy) + 1,
269                      &read, NULL, NULL, &timeout);
270      switch(selret)
271        {
272        case -1:
273          if (errno == EINTR && logoutsignal)
274            return SGISession_ATHENALOGOUT;
275          if (errno != EINTR) /* !SIGCHLD, basically */
276            fprintf(stderr,
277                    "session_gate: Unexpected error %d from select\n",
278                    errno);
279          break;
280        case 0:
281          return SGISession_TIMEOUT;
282          break;
283        default:
284          if (!FD_ISSET(ConnectionNumber(dpy), &read))
285            {
286              /* This can't happen. */
287              fprintf(stderr,
288                      "session_gate: select returned data for unknown fd\n");
289              exit(0);
290            }
291          break;
292        }
293    }
294}
295
296int SGISession_WhoCares()
297{
298  Atom *properties;
299  int i, numprops;
300  int wmcares = 0, wecare = 0;
301
302  properties = XListProperties(dpy, root, &numprops);
303  if (properties)
304    {
305      for (i = 0; i < numprops; i++)
306        if (properties[i] == sessionAtom)
307          wecare = 1;
308        else
309          if (properties[i] == wmAtom)
310            wmcares = 1;
311    }
312  else
313    return SGISession_NOBODY;
314
315  XFree(properties);
316
317  if (wmcares && wecare)
318    return SGISession_EVERYONE;
319
320  if (wmcares)
321    return SGISession_WMONLY;
322
323  return SGISession_NOBODY;
324}
325
326void SGISession_EndSession()
327{
328  system("/usr/bin/X11/endsession -f");
329}
330
331void SGISession_Debug(message)
332     char *message;
333{
334  if (SGISession_debug)
335    fprintf(stderr, "session_gate debug: %s", message);
336}
337#endif
338
339
340static powers[] = {100000,10000,1000,100,10,1,0};
341
342int itoa(x, buf)
343int x;
344char *buf;
345{
346    int i;
347    int pos=0;
348    int digit;
349
350    for (i = 0; powers[i]; i++)
351      {
352          digit = (x/powers[i]) % 10;
353          if ((pos > 0) || (digit != 0) || (powers[i+1] == 0))
354            buf[pos++] = '0' + (char) digit;
355      }
356    buf[pos] = '\0';
357    return pos;
358}
359
360
361void cleanup( )
362{
363    unlink(filename);
364    exit(0);
365}
366
367void logout( )
368{
369    int f;
370
371    /* Ignore Alarm in child since HUP probably arrived during
372     * sleep() in main loop.
373     */
374    signal(SIGALRM, SIG_IGN);
375    unlink(filename);
376    f = open(".logout", O_RDONLY, 0);
377    if (f >= 0) {
378        dup2(f, 0);
379        execl("/bin/athena/tcsh", "logout", 0);
380    }
381    exit(0);
382}
383
384/*
385 * clean_child() --
386 *      Clean up any zombied children that are awaiting this process's
387 *      acknowledgement of the child's death.
388 */
389void clean_child( )
390{
391#ifdef POSIX
392    waitpid((pid_t)-1, 0, WNOHANG);
393#else
394    wait3(0, WNOHANG, 0);
395#endif
396}
397
398time_t check_pid_file(filename, pid, mtime)
399char* filename;
400int pid;
401time_t mtime;
402{
403    struct stat st_buf;
404
405    if (stat(filename, &st_buf) == -1)
406      return create_pid_file(filename, pid);    /*  File gone:  create  */
407    else if (st_buf.st_mtime > mtime)
408      return update_pid_file(filename, pid);    /*  File changed:  update  */
409    else
410      return mtime;                             /*  File unchanged  */
411}
412
413
414time_t create_pid_file(filename, pid)
415char* filename;
416int pid;
417{
418    int fd;
419    struct stat st_buf;
420
421    if ((fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0)) >= 0)
422      {
423          write_pid_to_file(pid, fd);
424          fchmod(fd, S_IREAD | S_IWRITE);   /* set file mode 600 */
425          close(fd);
426      }
427
428    stat(filename, &st_buf);
429    return st_buf.st_mtime;
430}
431
432
433time_t update_pid_file(filename, pid)
434char* filename;
435int pid;
436{
437    int fd;
438    char buf[BUFSIZ];
439    int count;
440    char* start;
441    char* end;
442    struct stat st_buf;
443
444    /*  Determine if the file already contains the pid  */
445
446    if ((fd = open(filename, O_RDONLY, 0)) >= 0)
447      {
448          if ((count = read(fd, buf, BUFSIZ-1)) > 0)
449            {
450                buf[count-1] = '\0';
451                start = buf;
452                while ((end = strchr(start, '\n')) != 0)
453                  {
454                      *end = '\0';
455                      if (atoi(start) == pid)
456                        {
457                            stat(filename, &st_buf);
458                            return st_buf.st_mtime;
459                        }
460                      start = end + 1;
461                  }
462            }
463          close(fd);
464      }
465
466    /*  Append the pid to the file  */
467
468    if ((fd = open(filename, O_WRONLY | O_APPEND, 0)) >= 0)
469      {
470          write_pid_to_file(pid, fd);
471          close(fd);
472      }
473         
474    stat(filename, &st_buf);
475    return st_buf.st_mtime;
476}
477
478
479void write_pid_to_file(pid, fd)
480int pid;
481int fd;
482{
483    char buf[10];
484
485    itoa(pid, buf);
486    strcat(buf, "\n");
487    write(fd, buf, strlen(buf));
488}
Note: See TracBrowser for help on using the repository browser.