home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / shells / tcshsrc.zoo / tcsh / tc.who.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-25  |  14.1 KB  |  580 lines

  1. /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/tc.who.c,v 3.2 1991/07/17 13:25:11 christos Exp $ */
  2. /*
  3.  * tc.who.c: Watch logins and logouts...
  4.  */
  5. /*-
  6.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *    This product includes software developed by the University of
  20.  *    California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37. #include "config.h"
  38. RCSID("$Id: tc.who.c,v 3.2 1991/07/17 13:25:11 christos Exp $")
  39.  
  40. #include "sh.h"
  41. #include "tc.h"
  42.  
  43. /*
  44.  * kfk 26 Jan 1984 - for login watch functions.
  45.  */
  46. #include <ctype.h>
  47. #include <utmp.h>
  48.  
  49. #ifndef BROKEN_CC
  50. # define UTNAMLEN    sizeof(((struct utmp *) 0)->ut_name)
  51. # define UTLINLEN    sizeof(((struct utmp *) 0)->ut_line)
  52. # ifdef UTHOST
  53. #  ifdef _SEQUENT_
  54. #   define UTHOSTLEN    100
  55. #  else
  56. #   define UTHOSTLEN    sizeof(((struct utmp *) 0)->ut_host)
  57. #  endif
  58. # endif                /* UTHOST */
  59. #else
  60. /* give poor cc a little help if it needs it */
  61. struct utmp __ut;
  62.  
  63. # define UTNAMLEN    sizeof(__ut.ut_name)
  64. # define UTLINLEN    sizeof(__ut.ut_line)
  65. # ifdef UTHOST
  66. #  ifdef _SEQUENT_
  67. #   define UTHOSTLEN    100
  68. #  else
  69. #   define UTHOSTLEN    sizeof(__ut.ut_host)
  70. #  endif
  71. # endif                /* UTHOST */
  72. #endif                /* BROKEN_CC */
  73.  
  74. #ifndef _PATH_UTMP
  75. # ifdef    UTMP_FILE
  76. #  define _PATH_UTMP UTMP_FILE
  77. # else
  78. #  define _PATH_UTMP "/etc/utmp"
  79. # endif                /* UTMP_FILE */
  80. #endif                /* _PATH_UTMP */
  81.  
  82.  
  83. struct who {
  84.     struct who *w_next;
  85.     struct who *w_prev;
  86.     char    w_name[UTNAMLEN + 1];
  87.     char    w_new[UTNAMLEN + 1];
  88.     char    w_tty[UTLINLEN + 1];
  89. #ifdef UTHOST
  90.     char    w_host[UTHOSTLEN + 1];
  91. #endif /* UTHOST */
  92.     time_t  w_time;
  93.     int     w_status;
  94. };
  95.  
  96. static struct who *wholist = NULL;
  97. static int watch_period = 0;
  98. static time_t stlast = 0;
  99. extern char *month_list[];
  100. #ifdef WHODEBUG
  101. static    void    debugwholist    __P((struct who *, struct who *));
  102. #endif
  103. static    void    print_who    __P((struct who *));
  104.  
  105.  
  106. #define ONLINE        01
  107. #define OFFLINE        02
  108. #define CHANGED        04
  109. #define STMASK        07
  110. #define ANNOUNCE    010
  111.  
  112. /*
  113.  * Karl Kleinpaste, 26 Jan 1984.
  114.  * Initialize the dummy tty list for login watch.
  115.  * This dummy list eliminates boundary conditions
  116.  * when doing pointer-chase searches.
  117.  */
  118. void
  119. initwatch()
  120. {
  121.     register int i;
  122.  
  123.     wholist = (struct who *) xcalloc(1, sizeof *wholist);
  124.     wholist->w_next = (struct who *) xcalloc(1, sizeof *wholist);
  125.     wholist->w_next->w_prev = wholist;
  126.     for (i = 0; i < UTLINLEN; i++) {
  127.     wholist->w_tty[i] = '\01';
  128.     wholist->w_next->w_tty[i] = '~';
  129.     }
  130.     wholist->w_tty[i] = '\0';
  131.     wholist->w_next->w_tty[i] = '\0';
  132.  
  133. #ifdef WHODEBUG
  134.     debugwholist(NULL, NULL);
  135. #endif /* WHODEBUG */
  136. }
  137.  
  138. void
  139. resetwatch()
  140. {
  141.     watch_period = 0;
  142.     stlast = 0;
  143. }
  144.  
  145. /*
  146.  * Karl Kleinpaste, 26 Jan 1984.
  147.  * Watch /etc/utmp for login/logout changes.
  148.  */
  149. void
  150. watch_login()
  151. {
  152.     int     utmpfd, comp, alldone;
  153. #ifdef BSDSIGS
  154.     sigmask_t omask;
  155. #endif                /* BSDSIGS */
  156.     struct utmp utmp;
  157.     struct who *wp, *wpnew;
  158.     struct varent *v;
  159.     Char  **vp;
  160.     time_t  t, interval = MAILINTVL;
  161.     struct stat sta;
  162. #if defined(UTHOST) && defined(_SEQUENT_)
  163.     char   *host, *ut_find_host();
  164. #endif
  165.  
  166.     /* stop SIGINT, lest our login list get trashed. */
  167. #ifdef BSDSIGS
  168.     omask = sigblock(sigmask(SIGINT));
  169. #else
  170.     (void) sighold(SIGINT);
  171. #endif
  172.  
  173.     v = adrof(STRwatch);
  174.     if (v == NULL) {
  175. #ifdef BSDSIGS
  176.     (void) sigsetmask(omask);
  177. #else
  178.     (void) sigrelse(SIGINT);
  179. #endif
  180.     return;            /* no names to watch */
  181.     }
  182.     vp = v->vec;
  183.     if (blklen(vp) % 2)        /* odd # args: 1st == # minutes. */
  184.     interval = (number(*vp)) ? getn(*vp++) : MAILINTVL;
  185.     (void) time(&t);
  186.     if (t - watch_period < interval * 60) {
  187. #ifdef BSDSIGS
  188.     (void) sigsetmask(omask);
  189. #else
  190.     (void) sigrelse(SIGINT);
  191. #endif
  192.     return;            /* not long enough yet... */
  193.     }
  194.     watch_period = t;
  195.  
  196.     /*
  197.      * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
  198.      * Don't open utmp all the time, stat it first...
  199.      */
  200.     if (stat(_PATH_UTMP, &sta)) {
  201.     xprintf("cannot stat %s.  Please \"unset watch\".\n", _PATH_UTMP);
  202. #ifdef BSDSIGS
  203.     (void) sigsetmask(omask);
  204. #else
  205.     (void) sigrelse(SIGINT);
  206. #endif
  207.     return;
  208.     }
  209.     if (stlast == sta.st_mtime) {
  210. #ifdef BSDSIGS
  211.     (void) sigsetmask(omask);
  212. #else
  213.     (void) sigrelse(SIGINT);
  214. #endif
  215.     return;
  216.     }
  217.     stlast = sta.st_mtime;
  218.     if ((utmpfd = open(_PATH_UTMP, O_RDONLY)) < 0) {
  219.     xprintf("%s cannot be opened.  Please \"unset watch\".\n", _PATH_UTMP);
  220. #ifdef BSDSIGS
  221.     (void) sigsetmask(omask);
  222. #else
  223.     (void) sigrelse(SIGINT);
  224. #endif
  225.     return;
  226.     }
  227.  
  228.     /*
  229.      * xterm clears the entire utmp entry - mark everyone on the status list
  230.      * OFFLINE or we won't notice X "logouts"
  231.      */
  232.     for (wp = wholist; wp != NULL; wp = wp->w_next) {
  233.     wp->w_status = OFFLINE;
  234.     wp->w_time = 0;
  235.     }
  236.  
  237.     /*
  238.      * Read in the utmp file, sort the entries, and update existing entries or
  239.      * add new entries to the status list.
  240.      */
  241.     while (read(utmpfd, (char *) &utmp, sizeof utmp) == sizeof utmp) {
  242.  
  243. #ifdef DEAD_PROCESS
  244. # ifndef IRIS4D
  245.     if (utmp.ut_type != USER_PROCESS)
  246.         continue;
  247. # else
  248.     /* Why is that? Cause the utmp file is always corrupted??? */
  249.     if (utmp.ut_type != USER_PROCESS && utmp.ut_type != DEAD_PROCESS)
  250.         continue;
  251. # endif /* IRIS4D */
  252. #endif /* DEAD_PROCESS */
  253.  
  254.     if (utmp.ut_name[0] == '\0' && utmp.ut_line[0] == '\0')
  255.         continue;    /* completely void entry */
  256. #ifdef DEAD_PROCESS
  257.     if (utmp.ut_type == DEAD_PROCESS && utmp.ut_line[0] == '\0')
  258.         continue;
  259. #endif /* DEAD_PROCESS */
  260.     wp = wholist;
  261.     while ((comp = strncmp(wp->w_tty, utmp.ut_line, UTLINLEN)) < 0)
  262.         wp = wp->w_next;/* find that tty! */
  263.  
  264.     if (comp == 0) {    /* found the tty... */
  265. #ifdef DEAD_PROCESS
  266.         if (utmp.ut_type == DEAD_PROCESS) {
  267.         wp->w_time = utmp.ut_time;
  268.         wp->w_status = OFFLINE;
  269.         }
  270.         else
  271. #endif /* DEAD_PROCESS */
  272.         if (utmp.ut_name[0] == '\0') {
  273.         wp->w_time = utmp.ut_time;
  274.         wp->w_status = OFFLINE;
  275.         }
  276.         else if (strncmp(utmp.ut_name, wp->w_name, UTNAMLEN) == 0) {
  277.         /* someone is logged in */ 
  278.         wp->w_time = utmp.ut_time;
  279.         wp->w_status = 0;    /* same guy */
  280.         }
  281.         else {
  282.         (void) strncpy(wp->w_new, utmp.ut_name, UTNAMLEN);
  283. #ifdef UTHOST
  284. # ifdef _SEQUENT_
  285.         host = ut_find_host(wp->w_tty);
  286.         if (host)
  287.             (void) strncpy(wp->w_host, host, UTHOSTLEN);
  288.         else
  289.             wp->w_host[0] = 0;
  290. # else
  291.         (void) strncpy(wp->w_host, utmp.ut_host, UTHOSTLEN);
  292. # endif
  293. #endif /* UTHOST */
  294.         wp->w_time = utmp.ut_time;
  295.         if (wp->w_name[0] == '\0')
  296.             wp->w_status = ONLINE;
  297.         else
  298.             wp->w_status = CHANGED;
  299.         }
  300.     }
  301.     else {        /* new tty in utmp */
  302.         wpnew = (struct who *) xcalloc(1, sizeof *wpnew);
  303.         (void) strncpy(wpnew->w_tty, utmp.ut_line, UTLINLEN);
  304. #ifdef UTHOST
  305. # ifdef _SEQUENT_
  306.         host = ut_find_host(wpnew->w_tty);
  307.         if (host)
  308.         (void) strncpy(wpnew->w_host, host, UTHOSTLEN);
  309.         else
  310.         wpnew->w_host[0] = 0;
  311. # else
  312.         (void) strncpy(wpnew->w_host, utmp.ut_host, UTHOSTLEN);
  313. # endif
  314. #endif /* UTHOST */
  315.         wpnew->w_time = utmp.ut_time;
  316. #ifdef DEAD_PROCESS
  317.         if (utmp.ut_type == DEAD_PROCESS)
  318.         wpnew->w_status = OFFLINE;
  319.         else
  320. #endif /* DEAD_PROCESS */
  321.         if (utmp.ut_name[0] == '\0')
  322.         wpnew->w_status = OFFLINE;
  323.         else {
  324.         (void) strncpy(wpnew->w_new, utmp.ut_name, UTNAMLEN);
  325.         wpnew->w_status = ONLINE;
  326.         }
  327. #ifdef WHODEBUG
  328.         debugwholist(wpnew, wp);
  329. #endif /* WHODEBUG */
  330.  
  331.         wpnew->w_next = wp;    /* link in a new 'who' */
  332.         wpnew->w_prev = wp->w_prev;
  333.         wpnew->w_prev->w_next = wpnew;
  334.         wp->w_prev = wpnew;    /* linked in now */
  335.     }
  336.     }
  337.     (void) close(utmpfd);
  338. #if defined(UTHOST) && defined(_SEQUENT_)
  339.     endutent();
  340. #endif
  341.  
  342.     /*
  343.      * The state of all logins is now known, so we can search the user's list
  344.      * of watchables to print the interesting ones.
  345.      */
  346.     for (alldone = 0; !alldone && *vp != NULL && **vp != '\0' &&
  347.      *(vp + 1) != NULL && **(vp + 1) != '\0';
  348.      vp += 2) {        /* args used in pairs... */
  349.  
  350.     if (eq(*vp, STRany) && eq(*(vp + 1), STRany))
  351.         alldone = 1;
  352.  
  353.     for (wp = wholist; wp != NULL; wp = wp->w_next) {
  354.         if (wp->w_status & ANNOUNCE ||
  355.         (!eq(*vp, STRany) &&
  356.          !eq(*vp, str2short(wp->w_name)) &&
  357.          !eq(*vp, str2short(wp->w_new))) ||
  358.         (!eq(*(vp + 1), str2short(wp->w_tty)) &&
  359.          !eq(*(vp + 1), STRany)))
  360.         continue;    /* entry doesn't qualify */
  361.         /* already printed or not right one to print */
  362.  
  363.         if (wp->w_time == 0)/* utmp entry was cleared */
  364.         wp->w_time = watch_period;
  365.  
  366.         if ((wp->w_status & OFFLINE) &&
  367.         (wp->w_name[0] != '\0')) {
  368.         print_who(wp);
  369.         wp->w_name[0] = '\0';
  370.         wp->w_status |= ANNOUNCE;
  371.         continue;
  372.         }
  373.         if (wp->w_status & ONLINE) {
  374.         print_who(wp);
  375.         (void) strcpy(wp->w_name, wp->w_new);
  376.         wp->w_status |= ANNOUNCE;
  377.         continue;
  378.         }
  379.         if (wp->w_status & CHANGED) {
  380.         print_who(wp);
  381.         (void) strcpy(wp->w_name, wp->w_new);
  382.         wp->w_status |= ANNOUNCE;
  383.         continue;
  384.         }
  385.     }
  386.     }
  387. #ifdef BSDSIGS
  388.     (void) sigsetmask(omask);
  389. #else
  390.     (void) sigrelse(SIGINT);
  391. #endif
  392. }
  393.  
  394. #ifdef WHODEBUG
  395. static  oid
  396. debugwholist(new, wp)
  397.     register struct who *new, *wp;
  398. {
  399.     register struct who *a;
  400.  
  401.     a = wholist;
  402.     while (a != NULL) {
  403.     xprintf("%s/%s -> ", a->w_name, a->w_tty);
  404.     a = a->w_next;
  405.     }
  406.     xprintf("NULL\n");
  407.     a = wholist;
  408.     xprintf("backward: ");
  409.     while (a->w_next != NULL)
  410.     a = a->w_next;
  411.     while (a != NULL) {
  412.     xprintf("%s/%s -> ", a->w_name, a->w_tty);
  413.     a = a->w_prev;
  414.     }
  415.     xprintf("NULL\n");
  416.     if (new)
  417.     xprintf("new: %s/%s\n", new->w_name, new->w_tty);
  418.     if (wp)
  419.     xprintf("wp: %s/%s\n", wp->w_name, wp->w_tty);
  420. }
  421. #endif /* WHODEBUG */
  422.  
  423.  
  424. static void
  425. print_who(wp)
  426.     struct who *wp;
  427. {
  428. #ifdef UTHOST
  429.     char   *cp = "%n has %a %l from %m.";
  430.     char   *ptr, flg;
  431. #else
  432.     char   *cp = "%n has %a %l.";
  433. #endif /* UTHOST */
  434.  
  435.     struct varent *vp = adrof(STRwho);
  436.     struct tm *t;
  437.     char    ampm = 'a';
  438.     int     attributes = 0;
  439.  
  440.     t = localtime(&wp->w_time);
  441.     if (vp && vp->vec[0])
  442.     cp = short2str(vp->vec[0]);
  443.  
  444.     for (; *cp; cp++)
  445.     if (*cp != '%')
  446.         xputchar(*cp | attributes);
  447.     else
  448.         switch (*++cp) {
  449.         case 'n':        /* user name */
  450.         switch (wp->w_status & STMASK) {
  451.         case ONLINE:
  452.         case CHANGED:
  453.             xprintf("%a%s", attributes, wp->w_new);
  454.             break;
  455.         case OFFLINE:
  456.             xprintf("%a%s", attributes, wp->w_name);
  457.             break;
  458.         }
  459.         break;
  460.         case 'a':
  461.         switch (wp->w_status & STMASK) {
  462.         case ONLINE:
  463.             xprintf("%a%s", attributes, "logged on");
  464.             break;
  465.         case OFFLINE:
  466.             xprintf("%a%s", attributes, "logged off");
  467.             break;
  468.         case CHANGED:
  469.             xprintf("%areplaced %s on", attributes, wp->w_name);
  470.             break;
  471.         }
  472.         break;
  473.         case 'S':        /* start standout */
  474.         attributes |= STANDOUT;
  475.         break;
  476.         case 'B':        /* start bold */
  477.         attributes |= BOLD;
  478.         break;
  479.         case 'U':        /* start underline */
  480.         attributes |= UNDER;
  481.         break;
  482.         case 's':        /* end standout */
  483.         attributes &= ~STANDOUT;
  484.         break;
  485.         case 'b':        /* end bold */
  486.         attributes &= ~BOLD;
  487.         break;
  488.         case 'u':        /* end underline */
  489.         attributes &= ~UNDER;
  490.         break;
  491.         case 't':
  492.         case 'T':
  493.         case '@':
  494.         if (adrof(STRampm) || *cp != 'T') {
  495.             int     hr = t->tm_hour;
  496.  
  497.             if (hr >= 12) {
  498.             if (hr > 12)
  499.                 hr -= 12;
  500.             ampm = 'p';
  501.             }
  502.             else if (hr == 0)
  503.             hr = 12;
  504.             xprintf("%a%d:%02d%cm", attributes, hr, t->tm_min, ampm);
  505.         }
  506.         else
  507.             xprintf("%a%d:%02d", attributes, t->tm_hour, t->tm_min);
  508.         break;
  509.         case 'w':
  510.         xprintf("%a%s %d", attributes, month_list[t->tm_mon],
  511.             t->tm_mday);
  512.         break;
  513.         case 'W':
  514.         xprintf("%a%02d/%02d/%02d", attributes,
  515.             t->tm_mon + 1, t->tm_mday, t->tm_year);
  516.         break;
  517.         case 'D':
  518.         xprintf("%a%02d-%02d-%02d", attributes,
  519.             t->tm_year, t->tm_mon + 1, t->tm_mday);
  520.         break;
  521.         case 'l':
  522.         xprintf("%a%s", attributes, wp->w_tty);
  523.         break;
  524. #ifdef UTHOST
  525.         case 'm':
  526.         if (wp->w_host[0] == '\0')
  527.             xprintf("%alocal", attributes);
  528.         else
  529.             /* the ':' stuff is for <host>:<display>.<screen> */
  530.             for (ptr = wp->w_host, flg = Isdigit(*ptr) ? '\0' : '.';
  531.              *ptr != '\0' &&
  532.              (*ptr != flg || ((ptr = strchr(ptr, ':')) != 0));
  533.              ptr++) {
  534.             if (*ptr == ':')
  535.                 flg = '\0';
  536.             xputchar((int)
  537.                  ((Isupper(*ptr) ? Tolower(*ptr) : *ptr) |
  538.                   attributes));
  539.             }
  540.         break;
  541.         case 'M':
  542.         if (wp->w_host[0] == '\0')
  543.             xprintf("%alocal", attributes);
  544.         else
  545.             for (ptr = wp->w_host; *ptr != '\0'; ptr++)
  546.             xputchar((int)
  547.                  ((Isupper(*ptr) ? Tolower(*ptr) : *ptr) |
  548.                   attributes));
  549.         break;
  550. #endif /* UTHOST */
  551.         default:
  552.         xputchar('%' | attributes);
  553.         xputchar(*cp | attributes);
  554.         break;
  555.         }
  556.     xputchar('\n');
  557. } /* end print_who */
  558.  
  559. void
  560. /*ARGSUSED*/
  561. dolog(v, c)
  562. Char **v;
  563. struct command *c;
  564. {
  565.     struct who *wp;
  566.     struct varent *vp;
  567.  
  568.     if ((vp = adrof(STRwatch)) == NULL)
  569.     stderror(ERR_NOWATCH);
  570.     blkpr(vp->vec);
  571.     xprintf("\n");
  572.     watch_period = 0;
  573.     stlast = 0;
  574.     wp = wholist;
  575.     while (wp != NULL) {
  576.     wp->w_name[0] = '\0';
  577.     wp = wp->w_next;
  578.     }
  579. }
  580.