home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Shells / zsh-3.0.5-MIHS / src / Src / watch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-28  |  9.8 KB  |  470 lines

  1. /*
  2.  * $Id: watch.c,v 2.3 1996/10/15 20:16:35 hzoli Exp $
  3.  *
  4.  * watch.c - login/logout watching
  5.  *
  6.  * This file is part of zsh, the Z shell.
  7.  *
  8.  * Copyright (c) 1992-1996 Paul Falstad
  9.  * All rights reserved.
  10.  *
  11.  * Permission is hereby granted, without written agreement and without
  12.  * license or royalty fees, to use, copy, modify, and distribute this
  13.  * software and to distribute modified versions of this software for any
  14.  * purpose, provided that the above copyright notice and the following
  15.  * two paragraphs appear in all copies of this software.
  16.  *
  17.  * In no event shall Paul Falstad or the Zsh Development Group be liable
  18.  * to any party for direct, indirect, special, incidental, or consequential
  19.  * damages arising out of the use of this software and its documentation,
  20.  * even if Paul Falstad and the Zsh Development Group have been advised of
  21.  * the possibility of such damage.
  22.  *
  23.  * Paul Falstad and the Zsh Development Group specifically disclaim any
  24.  * warranties, including, but not limited to, the implied warranties of
  25.  * merchantability and fitness for a particular purpose.  The software
  26.  * provided hereunder is on an "as is" basis, and Paul Falstad and the
  27.  * Zsh Development Group have no obligation to provide maintenance,
  28.  * support, updates, enhancements, or modifications.
  29.  *
  30.  */
  31.  
  32. #include "zsh.h"
  33.  
  34. static int wtabsz;
  35. STRUCT_UTMP *wtab;
  36. static time_t lastutmpcheck;
  37.  
  38. /* get the time of login/logout for WATCH */
  39.  
  40. /**/
  41. time_t
  42. getlogtime(STRUCT_UTMP *u, int inout)
  43. {
  44.     FILE *in;
  45.     STRUCT_UTMP uu;
  46.     int first = 1;
  47.     int srchlimit = 50;        /* max number of wtmp records to search */
  48.  
  49.     if (inout)
  50.     return u->ut_time;
  51.     if (!(in = fopen(WTMP_FILE, "r")))
  52.     return time(NULL);
  53.     fseek(in, 0, 2);
  54.     do {
  55.     if (fseek(in, ((first) ? -1 : -2) * sizeof(STRUCT_UTMP), 1)) {
  56.         fclose(in);
  57.         return time(NULL);
  58.     }
  59.     first = 0;
  60.     if (!fread(&uu, sizeof(STRUCT_UTMP), 1, in)) {
  61.         fclose(in);
  62.         return time(NULL);
  63.     }
  64.     if (uu.ut_time < lastwatch || !srchlimit--) {
  65.         fclose(in);
  66.         return time(NULL);
  67.     }
  68.     }
  69.     while (memcmp(&uu, u, sizeof(uu)));
  70.  
  71.     do
  72.     if (!fread(&uu, sizeof(STRUCT_UTMP), 1, in)) {
  73.         fclose(in);
  74.         return time(NULL);
  75.     }
  76.     while (strncmp(uu.ut_line, u->ut_line, sizeof(u->ut_line)));
  77.     fclose(in);
  78.     return uu.ut_time;
  79. }
  80.  
  81. /* Mutually recursive call to handle ternaries in $WATCHFMT */
  82.  
  83. #define BEGIN3    '('
  84. #define END3    ')'
  85.  
  86. /**/
  87. char *
  88. watch3ary(int inout, STRUCT_UTMP *u, char *fmt, int prnt)
  89. {
  90.     int truth = 1, sep;
  91.  
  92.     switch (*fmt++) {
  93.     case 'n':
  94.     truth = (u->ut_name[0] != 0);
  95.     break;
  96.     case 'a':
  97.     truth = inout;
  98.     break;
  99.     case 'l':
  100.     if (!strncmp(u->ut_line, "tty", 3))
  101.         truth = (u->ut_line[3] != 0);
  102.     else
  103.         truth = (u->ut_line[0] != 0);
  104.     break;
  105. #ifdef HAVE_UT_HOST
  106.     case 'm':
  107.     case 'M':
  108.     truth = (u->ut_host[0] != 0);
  109.     break;
  110. #endif
  111.     default:
  112.     prnt = 0;        /* Skip unknown conditionals entirely */
  113.     break;
  114.     }
  115.     sep = *fmt++;
  116.     fmt = watchlog2(inout, u, fmt, (truth && prnt), sep);
  117.     return watchlog2(inout, u, fmt, (!truth && prnt), END3);
  118. }
  119.  
  120. /* print a login/logout event */
  121.  
  122. /**/
  123. char *
  124. watchlog2(int inout, STRUCT_UTMP *u, char *fmt, int prnt, int fini)
  125. {
  126.     char buf[40], buf2[80];
  127.     time_t timet;
  128.     struct tm *tm;
  129.     char *fm2;
  130. #ifdef HAVE_UT_HOST
  131.     char *p;
  132.     int i;
  133. #endif
  134.  
  135.     while (*fmt)
  136.     if (*fmt == '\\')
  137.         if (*++fmt) {
  138.         if (prnt)
  139.             putchar(*fmt);
  140.         ++fmt;
  141.         } else if (fini)
  142.         return fmt;
  143.         else
  144.         break;
  145.     else if (*fmt == fini)
  146.         return ++fmt;
  147.     else if (*fmt != '%') {
  148.         if (prnt)
  149.         putchar(*fmt);
  150.         ++fmt;
  151.     } else {
  152.         if (*++fmt == BEGIN3)
  153.         fmt = watch3ary(inout, u, ++fmt, prnt);
  154.         else if (!prnt)
  155.         ++fmt;
  156.         else
  157.         switch (*(fm2 = fmt++)) {
  158.         case 'n':
  159.             printf("%.*s", (int)sizeof(u->ut_name), u->ut_name);
  160.             break;
  161.         case 'a':
  162.             printf("%s", (!inout) ? "logged off" : "logged on");
  163.             break;
  164.         case 'l':
  165.             if (!strncmp(u->ut_line, "tty", 3))
  166.             printf("%.*s", (int)sizeof(u->ut_line) - 3, u->ut_line + 3);
  167.             else
  168.             printf("%.*s", (int)sizeof(u->ut_line), u->ut_line);
  169.             break;
  170. #ifdef HAVE_UT_HOST
  171.         case 'm':
  172.             for (p = u->ut_host, i = sizeof(u->ut_host); i && *p; i--, p++) {
  173.             if (*p == '.' && !idigit(p[1]))
  174.                 break;
  175.             putchar(*p);
  176.             }
  177.             break;
  178.         case 'M':
  179.             printf("%.*s", (int)sizeof(u->ut_host), u->ut_host);
  180.             break;
  181. #endif
  182.         case 'T':
  183.         case 't':
  184.         case '@':
  185.         case 'W':
  186.         case 'w':
  187.         case 'D':
  188.             switch (*fm2) {
  189.             case '@':
  190.             case 't':
  191.             fm2 = "%l:%M%p";
  192.             break;
  193.             case 'T':
  194.             fm2 = "%k:%M";
  195.             break;
  196.             case 'w':
  197.             fm2 = "%a %e";
  198.             break;
  199.             case 'W':
  200.             fm2 = "%m/%d/%y";
  201.             break;
  202.             case 'D':
  203.             if (fm2[1] == '{') {
  204.                 char *dd, *ss;
  205.                 int n = 79;
  206.  
  207.                 for (ss = fm2 + 2, dd = buf2;
  208.                  n-- && *ss && *ss != '}'; ++ss, ++dd)
  209.                 *dd = *((*ss == '\\' && ss[1]) ? ++ss : ss);
  210.                 if (*ss == '}') {
  211.                 *dd = '\0';
  212.                 fmt = ss + 1;
  213.                 fm2 = buf2;
  214.                 }
  215.                 else fm2 = "%y-%m-%d";
  216.             }
  217.             else fm2 = "%y-%m-%d";
  218.             break;
  219.             }
  220.             timet = getlogtime(u, inout);
  221.             tm = localtime(&timet);
  222.             ztrftime(buf, 40, fm2, tm);
  223.             printf("%s", (*buf == ' ') ? buf + 1 : buf);
  224.             break;
  225.         case '%':
  226.             putchar('%');
  227.             break;
  228.         case 'S':
  229.             txtset(TXTSTANDOUT);
  230.             tsetcap(TCSTANDOUTBEG, -1);
  231.             break;
  232.         case 's':
  233.             txtset(TXTDIRTY);
  234.             txtunset(TXTSTANDOUT);
  235.             tsetcap(TCSTANDOUTEND, -1);
  236.             break;
  237.         case 'B':
  238.             txtset(TXTDIRTY);
  239.             txtset(TXTBOLDFACE);
  240.             tsetcap(TCBOLDFACEBEG, -1);
  241.             break;
  242.         case 'b':
  243.             txtset(TXTDIRTY);
  244.             txtunset(TXTBOLDFACE);
  245.             tsetcap(TCALLATTRSOFF, -1);
  246.             break;
  247.         case 'U':
  248.             txtset(TXTUNDERLINE);
  249.             tsetcap(TCUNDERLINEBEG, -1);
  250.             break;
  251.         case 'u':
  252.             txtset(TXTDIRTY);
  253.             txtunset(TXTUNDERLINE);
  254.             tsetcap(TCUNDERLINEEND, -1);
  255.             break;
  256.         default:
  257.             putchar('%');
  258.             putchar(*fm2);
  259.             break;
  260.         }
  261.     }
  262.     if (prnt)
  263.     putchar('\n');
  264.  
  265.     return fmt;
  266. }
  267.  
  268. /* check the List for login/logouts */
  269.  
  270. /**/
  271. void
  272. watchlog(int inout, STRUCT_UTMP *u, char **w, char *fmt)
  273. {
  274.     char *v, *vv, sav;
  275.     int bad;
  276.  
  277.     if (!*u->ut_name)
  278.     return;
  279.  
  280.     if (*w && !strcmp(*w, "all")) {
  281.     (void)watchlog2(inout, u, fmt, 1, 0);
  282.     return;
  283.     }
  284.     if (*w && !strcmp(*w, "notme") &&
  285.     strncmp(u->ut_name, get_username(), sizeof(u->ut_name))) {
  286.     (void)watchlog2(inout, u, fmt, 1, 0);
  287.     return;
  288.     }
  289.     for (; *w; w++) {
  290.     bad = 0;
  291.     v = *w;
  292.     if (*v != '@' && *v != '%') {
  293.         for (vv = v; *vv && *vv != '@' && *vv != '%'; vv++);
  294.         sav = *vv;
  295.         *vv = '\0';
  296.         if (strncmp(u->ut_name, v, sizeof(u->ut_name)))
  297.         bad = 1;
  298.         *vv = sav;
  299.         v = vv;
  300.     }
  301.     for (;;)
  302.         if (*v == '%') {
  303.         for (vv = ++v; *vv && *vv != '@'; vv++);
  304.         sav = *vv;
  305.         *vv = '\0';
  306.         if (strncmp(u->ut_line, v, sizeof(u->ut_line)))
  307.             bad = 1;
  308.         *vv = sav;
  309.         v = vv;
  310.         }
  311. #ifdef HAVE_UT_HOST
  312.         else if (*v == '@') {
  313.         for (vv = ++v; *vv && *vv != '%'; vv++);
  314.         sav = *vv;
  315.         *vv = '\0';
  316.         if (strncmp(u->ut_host, v, strlen(v)))
  317.             bad = 1;
  318.         *vv = sav;
  319.         v = vv;
  320.         }
  321. #endif
  322.         else
  323.         break;
  324.     if (!bad) {
  325.         (void)watchlog2(inout, u, fmt, 1, 0);
  326.         return;
  327.     }
  328.     }
  329. }
  330.  
  331. /* compare 2 utmp entries */
  332.  
  333. /**/
  334. int
  335. ucmp(STRUCT_UTMP *u, STRUCT_UTMP *v)
  336. {
  337.     if (u->ut_time == v->ut_time)
  338.     return strncmp(u->ut_line, v->ut_line, sizeof(u->ut_line));
  339.     return u->ut_time - v->ut_time;
  340. }
  341.  
  342. /* initialize the user List */
  343.  
  344. /**/
  345. void
  346. readwtab(void)
  347. {
  348.     STRUCT_UTMP *uptr;
  349.     int wtabmax = 32;
  350.     FILE *in;
  351.  
  352.     wtabsz = 0;
  353.     if (!(in = fopen(UTMP_FILE, "r")))
  354.     return;
  355.     uptr = wtab = (STRUCT_UTMP *)zalloc(wtabmax * sizeof(STRUCT_UTMP));
  356.     while (fread(uptr, sizeof(STRUCT_UTMP), 1, in))
  357. #ifdef USER_PROCESS
  358.     if   (uptr->ut_type == USER_PROCESS)
  359. #else
  360.     if   (uptr->ut_name[0])
  361. #endif
  362.     {
  363.         uptr++;
  364.         if (++wtabsz == wtabmax)
  365.         uptr = (wtab = (STRUCT_UTMP *)realloc((void *) wtab, (wtabmax *= 2) *
  366.                               sizeof(STRUCT_UTMP))) + wtabsz;
  367.     }
  368.     fclose(in);
  369.  
  370.     if (wtabsz)
  371.     qsort((void *) wtab, wtabsz, sizeof(STRUCT_UTMP),
  372.                (int (*) _((const void *, const void *)))ucmp);
  373. }
  374.  
  375. /* Check for login/logout events; executed before *
  376.  * each prompt if WATCH is set                    */
  377.  
  378. /**/
  379. void
  380. dowatch(void)
  381. {
  382.     FILE *in;
  383.     STRUCT_UTMP *utab, *uptr, *wptr;
  384.     struct stat st;
  385.     char **s;
  386.     char *fmt;
  387.     int utabsz = 0, utabmax = wtabsz + 4;
  388.     int uct, wct;
  389.  
  390.     s = watch;
  391.     if (!(fmt = getsparam("WATCHFMT")))
  392.     fmt = DEFAULT_WATCHFMT;
  393.  
  394.     holdintr();
  395.     if (!wtab) {
  396.     readwtab();
  397.     noholdintr();
  398.     return;
  399.     }
  400.     if ((stat(UTMP_FILE, &st) == -1) || (st.st_mtime <= lastutmpcheck)) {
  401.     noholdintr();
  402.     return;
  403.     }
  404.     lastutmpcheck = st.st_mtime;
  405.     uptr = utab = (STRUCT_UTMP *) zalloc(utabmax * sizeof(STRUCT_UTMP));
  406.  
  407.     if (!(in = fopen(UTMP_FILE, "r"))) {
  408.     free(utab);
  409.     noholdintr();
  410.     return;
  411.     }
  412.     while (fread(uptr, sizeof *uptr, 1, in))
  413. #ifdef USER_PROCESS
  414.     if (uptr->ut_type == USER_PROCESS)
  415. #else
  416.     if (uptr->ut_name[0])
  417. #endif
  418.     {
  419.         uptr++;
  420.         if (++utabsz == utabmax)
  421.         uptr = (utab = (STRUCT_UTMP *)realloc((void *) utab, (utabmax *= 2) *
  422.                               sizeof(STRUCT_UTMP))) + utabsz;
  423.     }
  424.     fclose(in);
  425.     noholdintr();
  426.     if (errflag) {
  427.     free(utab);
  428.     return;
  429.     }
  430.     if (utabsz)
  431.     qsort((void *) utab, utabsz, sizeof(STRUCT_UTMP),
  432.                (int (*) _((const void *, const void *)))ucmp);
  433.  
  434.     wct = wtabsz;
  435.     uct = utabsz;
  436.     uptr = utab;
  437.     wptr = wtab;
  438.     if (errflag) {
  439.     free(utab);
  440.     return;
  441.     }
  442.     while ((uct || wct) && !errflag)
  443.     if (!uct || (wct && ucmp(uptr, wptr) > 0))
  444.         wct--, watchlog(0, wptr++, s, fmt);
  445.     else if (!wct || (uct && ucmp(uptr, wptr) < 0))
  446.         uct--, watchlog(1, uptr++, s, fmt);
  447.     else
  448.         uptr++, wptr++, wct--, uct--;
  449.     free(wtab);
  450.     wtab = utab;
  451.     wtabsz = utabsz;
  452.     fflush(stdout);
  453. }
  454.  
  455. /**/
  456. int
  457. bin_log(char *nam, char **argv, char *ops, int func)
  458. {
  459.     if (!watch)
  460.     return 1;
  461.     if (wtab)
  462.     free(wtab);
  463.     wtab = (STRUCT_UTMP *)zalloc(1);
  464.     wtabsz = 0;
  465.     lastutmpcheck = 0;
  466.     dowatch();
  467.     return 0;
  468. }
  469.  
  470.