home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / zsh / Source / src / watch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-07  |  8.7 KB  |  444 lines

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