home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / tcsh / Source / tc.who.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-21  |  13.6 KB  |  561 lines

  1. /* $Header: /u/christos/src/tcsh-6.03/RCS/tc.who.c,v 3.16 1992/10/05 02:41:30 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 "sh.h"
  38.  
  39. RCSID("$Id: tc.who.c,v 3.16 1992/10/05 02:41:30 christos Exp $")
  40.  
  41. #include "tc.h"
  42.  
  43. #ifndef HAVENOUTMP
  44. /*
  45.  * kfk 26 Jan 1984 - for login watch functions.
  46.  */
  47. #include <ctype.h>
  48.  
  49. #ifdef HAVEUTMPX
  50. # include <utmpx.h>
  51. /* I just redefine a few words here.  Changing every occurrence below
  52.  * seems like too much of work.  All UTMP functions have equivalent
  53.  * UTMPX counterparts, so they can be added all here when needed.
  54.  * Kimmo Suominen, Oct 14 1991
  55.  */
  56. # ifndef _PATH_UTMP
  57. #  define _PATH_UTMP UTMPX_FILE
  58. # endif /* _PATH_UTMP */
  59. # define utmp utmpx
  60. # define ut_time ut_xtime
  61. #else /* !HAVEUTMPX */
  62. # include <utmp.h>
  63. #endif /* HAVEUTMPX */
  64.  
  65. #ifndef BROKEN_CC
  66. # define UTNAMLEN    sizeof(((struct utmp *) 0)->ut_name)
  67. # define UTLINLEN    sizeof(((struct utmp *) 0)->ut_line)
  68. # ifdef UTHOST
  69. #  ifdef _SEQUENT_
  70. #   define UTHOSTLEN    100
  71. #  else
  72. #   define UTHOSTLEN    sizeof(((struct utmp *) 0)->ut_host)
  73. #  endif
  74. # endif    /* UTHOST */
  75. #else
  76. /* give poor cc a little help if it needs it */
  77. struct utmp __ut;
  78.  
  79. # define UTNAMLEN    sizeof(__ut.ut_name)
  80. # define UTLINLEN    sizeof(__ut.ut_line)
  81. # ifdef UTHOST
  82. #  ifdef _SEQUENT_
  83. #   define UTHOSTLEN    100
  84. #  else
  85. #   define UTHOSTLEN    sizeof(__ut.ut_host)
  86. #  endif
  87. # endif /* UTHOST */
  88. #endif /* BROKEN_CC */
  89.  
  90. #ifndef _PATH_UTMP
  91. # ifdef    UTMP_FILE
  92. #  define _PATH_UTMP UTMP_FILE
  93. # else
  94. #  define _PATH_UTMP "/etc/utmp"
  95. # endif /* UTMP_FILE */
  96. #endif /* _PATH_UTMP */
  97.  
  98.  
  99. struct who {
  100.     struct who *who_next;
  101.     struct who *who_prev;
  102.     char    who_name[UTNAMLEN + 1];
  103.     char    who_new[UTNAMLEN + 1];
  104.     char    who_tty[UTLINLEN + 1];
  105. #ifdef UTHOST
  106.     char    who_host[UTHOSTLEN + 1];
  107. #endif /* UTHOST */
  108.     time_t  who_time;
  109.     int     who_status;
  110. };
  111.  
  112. static struct who whohead, whotail;
  113. static int watch_period = 0;
  114. static time_t stlast = 0;
  115. extern char *month_list[];
  116. extern char *day_list[];
  117. #ifdef WHODEBUG
  118. static    void    debugwholist    __P((struct who *, struct who *));
  119. #endif
  120. static    void    print_who    __P((struct who *));
  121.  
  122.  
  123. #define ONLINE        01
  124. #define OFFLINE        02
  125. #define CHANGED        04
  126. #define STMASK        07
  127. #define ANNOUNCE    010
  128.  
  129. /*
  130.  * Karl Kleinpaste, 26 Jan 1984.
  131.  * Initialize the dummy tty list for login watch.
  132.  * This dummy list eliminates boundary conditions
  133.  * when doing pointer-chase searches.
  134.  */
  135. void
  136. initwatch()
  137. {
  138.     whohead.who_next = &whotail;
  139.     whotail.who_prev = &whohead;
  140. #ifdef WHODEBUG
  141.     debugwholist(NULL, NULL);
  142. #endif /* WHODEBUG */
  143. }
  144.  
  145. void
  146. resetwatch()
  147. {
  148.     watch_period = 0;
  149.     stlast = 0;
  150. }
  151.  
  152. /*
  153.  * Karl Kleinpaste, 26 Jan 1984.
  154.  * Watch /etc/utmp for login/logout changes.
  155.  */
  156. void
  157. watch_login()
  158. {
  159.     int     utmpfd, comp = -1, alldone;
  160. #ifdef BSDSIGS
  161.     sigmask_t omask;
  162. #endif                /* BSDSIGS */
  163.     struct utmp utmp;
  164.     struct who *wp, *wpnew;
  165.     struct varent *v;
  166.     Char  **vp;
  167.     time_t  t, interval = MAILINTVL;
  168.     struct stat sta;
  169. #if defined(UTHOST) && defined(_SEQUENT_)
  170.     char   *host, *ut_find_host();
  171. #endif
  172.  
  173.     /* stop SIGINT, lest our login list get trashed. */
  174. #ifdef BSDSIGS
  175.     omask = sigblock(sigmask(SIGINT));
  176. #else
  177.     (void) sighold(SIGINT);
  178. #endif
  179.  
  180.     v = adrof(STRwatch);
  181.     if (v == NULL) {
  182. #ifdef BSDSIGS
  183.     (void) sigsetmask(omask);
  184. #else
  185.     (void) sigrelse(SIGINT);
  186. #endif
  187.     return;            /* no names to watch */
  188.     }
  189.     trim(vp = v->vec);
  190.     if (blklen(vp) % 2)        /* odd # args: 1st == # minutes. */
  191.     interval = (number(*vp)) ? getn(*vp++) : MAILINTVL;
  192.     (void) time(&t);
  193.     if (t - watch_period < interval * 60) {
  194. #ifdef BSDSIGS
  195.     (void) sigsetmask(omask);
  196. #else
  197.     (void) sigrelse(SIGINT);
  198. #endif
  199.     return;            /* not long enough yet... */
  200.     }
  201.     watch_period = t;
  202.  
  203.     /*
  204.      * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
  205.      * Don't open utmp all the time, stat it first...
  206.      */
  207.     if (stat(_PATH_UTMP, &sta)) {
  208.     xprintf("cannot stat %s.  Please \"unset watch\".\n", _PATH_UTMP);
  209. #ifdef BSDSIGS
  210.     (void) sigsetmask(omask);
  211. #else
  212.     (void) sigrelse(SIGINT);
  213. #endif
  214.     return;
  215.     }
  216.     if (stlast == sta.st_mtime) {
  217. #ifdef BSDSIGS
  218.     (void) sigsetmask(omask);
  219. #else
  220.     (void) sigrelse(SIGINT);
  221. #endif
  222.     return;
  223.     }
  224.     stlast = sta.st_mtime;
  225.     if ((utmpfd = open(_PATH_UTMP, O_RDONLY)) < 0) {
  226.     xprintf("%s cannot be opened.  Please \"unset watch\".\n", _PATH_UTMP);
  227. #ifdef BSDSIGS
  228.     (void) sigsetmask(omask);
  229. #else
  230.     (void) sigrelse(SIGINT);
  231. #endif
  232.     return;
  233.     }
  234.  
  235.     /*
  236.      * xterm clears the entire utmp entry - mark everyone on the status list
  237.      * OFFLINE or we won't notice X "logouts"
  238.      */
  239.     for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) {
  240.     wp->who_status = OFFLINE;
  241.     wp->who_time = 0;
  242.     }
  243.  
  244.     /*
  245.      * Read in the utmp file, sort the entries, and update existing entries or
  246.      * add new entries to the status list.
  247.      */
  248.     while (read(utmpfd, (char *) &utmp, sizeof utmp) == sizeof utmp) {
  249.  
  250. #ifdef DEAD_PROCESS
  251. # ifndef IRIS4D
  252.     if (utmp.ut_type != USER_PROCESS)
  253.         continue;
  254. # else
  255.     /* Why is that? Cause the utmp file is always corrupted??? */
  256.     if (utmp.ut_type != USER_PROCESS && utmp.ut_type != DEAD_PROCESS)
  257.         continue;
  258. # endif /* IRIS4D */
  259. #endif /* DEAD_PROCESS */
  260.  
  261.     if (utmp.ut_name[0] == '\0' && utmp.ut_line[0] == '\0')
  262.         continue;    /* completely void entry */
  263. #ifdef DEAD_PROCESS
  264.     if (utmp.ut_type == DEAD_PROCESS && utmp.ut_line[0] == '\0')
  265.         continue;
  266. #endif /* DEAD_PROCESS */
  267.     wp = whohead.who_next;
  268.     while (wp->who_next && (comp = strncmp(wp->who_tty, utmp.ut_line, UTLINLEN)) < 0)
  269.         wp = wp->who_next;/* find that tty! */
  270.  
  271.     if (wp->who_next && comp == 0) {    /* found the tty... */
  272. #ifdef DEAD_PROCESS
  273.         if (utmp.ut_type == DEAD_PROCESS) {
  274.         wp->who_time = utmp.ut_time;
  275.         wp->who_status = OFFLINE;
  276.         }
  277.         else
  278. #endif /* DEAD_PROCESS */
  279.         if (utmp.ut_name[0] == '\0') {
  280.         wp->who_time = utmp.ut_time;
  281.         wp->who_status = OFFLINE;
  282.         }
  283.         else if (strncmp(utmp.ut_name, wp->who_name, UTNAMLEN) == 0) {
  284.         /* someone is logged in */ 
  285.         wp->who_time = utmp.ut_time;
  286.         wp->who_status = 0;    /* same guy */
  287.         }
  288.         else {
  289.         (void) strncpy(wp->who_new, utmp.ut_name, UTNAMLEN);
  290. #ifdef UTHOST
  291. # ifdef _SEQUENT_
  292.         host = ut_find_host(wp->who_tty);
  293.         if (host)
  294.             (void) strncpy(wp->who_host, host, UTHOSTLEN);
  295.         else
  296.             wp->who_host[0] = 0;
  297. # else
  298.         (void) strncpy(wp->who_host, utmp.ut_host, UTHOSTLEN);
  299. # endif
  300. #endif /* UTHOST */
  301.         wp->who_time = utmp.ut_time;
  302.         if (wp->who_name[0] == '\0')
  303.             wp->who_status = ONLINE;
  304.         else
  305.             wp->who_status = CHANGED;
  306.         }
  307.     }
  308.     else {        /* new tty in utmp */
  309.         wpnew = (struct who *) xcalloc(1, sizeof *wpnew);
  310.         (void) strncpy(wpnew->who_tty, utmp.ut_line, UTLINLEN);
  311. #ifdef UTHOST
  312. # ifdef _SEQUENT_
  313.         host = ut_find_host(wpnew->who_tty);
  314.         if (host)
  315.         (void) strncpy(wpnew->who_host, host, UTHOSTLEN);
  316.         else
  317.         wpnew->who_host[0] = 0;
  318. # else
  319.         (void) strncpy(wpnew->who_host, utmp.ut_host, UTHOSTLEN);
  320. # endif
  321. #endif /* UTHOST */
  322.         wpnew->who_time = utmp.ut_time;
  323. #ifdef DEAD_PROCESS
  324.         if (utmp.ut_type == DEAD_PROCESS)
  325.         wpnew->who_status = OFFLINE;
  326.         else
  327. #endif /* DEAD_PROCESS */
  328.         if (utmp.ut_name[0] == '\0')
  329.         wpnew->who_status = OFFLINE;
  330.         else {
  331.         (void) strncpy(wpnew->who_new, utmp.ut_name, UTNAMLEN);
  332.         wpnew->who_status = ONLINE;
  333.         }
  334. #ifdef WHODEBUG
  335.         debugwholist(wpnew, wp);
  336. #endif /* WHODEBUG */
  337.  
  338.         wpnew->who_next = wp;    /* link in a new 'who' */
  339.         wpnew->who_prev = wp->who_prev;
  340.         wpnew->who_prev->who_next = wpnew;
  341.         wp->who_prev = wpnew;    /* linked in now */
  342.     }
  343.     }
  344.     (void) close(utmpfd);
  345. #if defined(UTHOST) && defined(_SEQUENT_)
  346.     endutent();
  347. #endif
  348.  
  349.     /*
  350.      * The state of all logins is now known, so we can search the user's list
  351.      * of watchables to print the interesting ones.
  352.      */
  353.     for (alldone = 0; !alldone && *vp != NULL && **vp != '\0' &&
  354.      *(vp + 1) != NULL && **(vp + 1) != '\0';
  355.      vp += 2) {        /* args used in pairs... */
  356.  
  357.     if (eq(*vp, STRany) && eq(*(vp + 1), STRany))
  358.         alldone = 1;
  359.  
  360.     for (wp = whohead.who_next; wp->who_next != NULL; wp = wp->who_next) {
  361.         if (wp->who_status & ANNOUNCE ||
  362.         (!eq(STRany, vp[0]) &&
  363.          !Gmatch(str2short(wp->who_name), vp[0]) &&
  364.          !Gmatch(str2short(wp->who_new),  vp[0])) ||
  365.         (!Gmatch(str2short(wp->who_tty),  vp[1]) &&
  366.          !eq(STRany, vp[1])))
  367.         continue;    /* entry doesn't qualify */
  368.         /* already printed or not right one to print */
  369.  
  370.         if (wp->who_time == 0)/* utmp entry was cleared */
  371.         wp->who_time = watch_period;
  372.  
  373.         if ((wp->who_status & OFFLINE) &&
  374.         (wp->who_name[0] != '\0')) {
  375.         print_who(wp);
  376.         wp->who_name[0] = '\0';
  377.         wp->who_status |= ANNOUNCE;
  378.         continue;
  379.         }
  380.         if (wp->who_status & ONLINE) {
  381.         print_who(wp);
  382.         (void) strcpy(wp->who_name, wp->who_new);
  383.         wp->who_status |= ANNOUNCE;
  384.         continue;
  385.         }
  386.         if (wp->who_status & CHANGED) {
  387.         print_who(wp);
  388.         (void) strcpy(wp->who_name, wp->who_new);
  389.         wp->who_status |= ANNOUNCE;
  390.         continue;
  391.         }
  392.     }
  393.     }
  394. #ifdef BSDSIGS
  395.     (void) sigsetmask(omask);
  396. #else
  397.     (void) sigrelse(SIGINT);
  398. #endif
  399. }
  400.  
  401. #ifdef WHODEBUG
  402. static void
  403. debugwholist(new, wp)
  404.     register struct who *new, *wp;
  405. {
  406.     register struct who *a;
  407.  
  408.     a = whohead.who_next;
  409.     while (a->who_next != NULL) {
  410.     xprintf("%s/%s -> ", a->who_name, a->who_tty);
  411.     a = a->who_next;
  412.     }
  413.     xprintf("TAIL\n");
  414.     if (a != &whotail) {
  415.     xprintf("BUG! last element is not whotail!\n");
  416.     abort();
  417.     }
  418.     a = whotail.who_prev;
  419.     xprintf("backward: ");
  420.     while (a->who_prev != NULL) {
  421.     xprintf("%s/%s -> ", a->who_name, a->who_tty);
  422.     a = a->who_prev;
  423.     }
  424.     xprintf("HEAD\n");
  425.     if (a != &whohead) {
  426.     xprintf("BUG! first element is not whohead!\n");
  427.     abort();
  428.     }
  429.     if (new)
  430.     xprintf("new: %s/%s\n", new->who_name, new->who_tty);
  431.     if (wp)
  432.     xprintf("wp: %s/%s\n", wp->who_name, wp->who_tty);
  433. }
  434. #endif /* WHODEBUG */
  435.  
  436.  
  437. static void
  438. print_who(wp)
  439.     struct who *wp;
  440. {
  441. #ifdef UTHOST
  442.     Char   *cp = str2short("%n has %a %l from %m.");
  443. #else
  444.     Char   *cp = str2short("%n has %a %l.");
  445. #endif /* UTHOST */
  446.     struct varent *vp = adrof(STRwho);
  447.     Char buf[BUFSIZE];
  448.  
  449.     if (vp && vp->vec[0])
  450.     cp = vp->vec[0];
  451.  
  452.     tprintf(FMT_WHO, buf, cp, BUFSIZE, NULL, wp->who_time, (ptr_t) wp);
  453.     for (cp = buf; *cp;)
  454.     xputchar(*cp++);
  455.     xputchar('\n');
  456. } /* end print_who */
  457.  
  458.  
  459. char *
  460. who_info(ptr, c, wbuf)
  461.     ptr_t ptr;
  462.     int c;
  463.     char *wbuf;
  464. {
  465.     struct who *wp = (struct who *) ptr;
  466. #ifdef UTHOST
  467.     char *wb = wbuf;
  468.     int flg;
  469.     char *pb;
  470. #endif /* UTHOST */
  471.  
  472.     switch (c) {
  473.     case 'n':        /* user name */
  474.     switch (wp->who_status & STMASK) {
  475.     case ONLINE:
  476.     case CHANGED:
  477.         return wp->who_new;
  478.     case OFFLINE:
  479.         return wp->who_name;
  480.     default:
  481.         break;
  482.     }
  483.     break;
  484.  
  485.     case 'a':
  486.     switch (wp->who_status & STMASK) {
  487.     case ONLINE:
  488.         return "logged on";
  489.     case OFFLINE:
  490.         return "logged off";
  491.     case CHANGED:
  492.         xsprintf(wbuf, "replaced %s on", wp->who_name);
  493.         return wbuf;
  494.     default:
  495.         break;
  496.     }
  497.     break;
  498.  
  499. #ifdef UTHOST
  500.     case 'm':
  501.     if (wp->who_host[0] == '\0')
  502.         return "local";
  503.     else {
  504.         /* the ':' stuff is for <host>:<display>.<screen> */
  505.         for (pb = wp->who_host, flg = Isdigit(*pb) ? '\0' : '.';
  506.          *pb != '\0' &&
  507.          (*pb != flg || ((pb = strchr(pb, ':')) != 0));
  508.          pb++) {
  509.         if (*pb == ':')
  510.             flg = '\0';
  511.         *wb++ = Isupper(*pb) ? Tolower(*pb) : *pb;
  512.         }
  513.         *wb = '\0';
  514.         return wbuf;
  515.     }
  516.  
  517.     case 'M':
  518.     if (wp->who_host[0] == '\0')
  519.         return "local";
  520.     else {
  521.         for (pb = wp->who_host; *pb != '\0'; pb++)
  522.         *wb++ = Isupper(*pb) ? Tolower(*pb) : *pb;
  523.         *wb = '\0';
  524.         return wbuf;
  525.     }
  526. #endif /* UTHOST */
  527.  
  528.     case 'l':
  529.     return wp->who_tty;
  530.  
  531.     default:
  532.     wbuf[0] = '%';
  533.     wbuf[1] = c;
  534.     wbuf[2] = '\0';
  535.     return wbuf;
  536.     }
  537.     return NULL;
  538. }
  539.  
  540. void
  541. /*ARGSUSED*/
  542. dolog(v, c)
  543. Char **v;
  544. struct command *c;
  545. {
  546.     struct who *wp;
  547.     struct varent *vp;
  548.  
  549.     if ((vp = adrof(STRwatch)) == NULL)
  550.     stderror(ERR_NOWATCH);
  551.     blkpr(vp->vec);
  552.     xputchar('\n');
  553.     resetwatch();
  554.     wp = whohead.who_next;
  555.     while (wp->who_next != NULL) {
  556.     wp->who_name[0] = '\0';
  557.     wp = wp->who_next;
  558.     }
  559. }
  560. #endif /* HAVENOUTMP */
  561.