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

Defined functions

debugwholist defined in line 397; used 2 times
dolog defined in line 561; never used
initwatch defined in line 120; used 1 times
print_who defined in line 426; used 3 times
rcsid defined in line 39; never used
resetwatch defined in line 140; used 1 times
watch_login defined in line 151; used 1 times

Defined variables

__ut defined in line 63; used 3 times
oid defined in line 397; never used
stlast defined in line 100; used 4 times
watch_period defined in line 99; used 5 times
wholist defined in line 98; used 16 times

Defined struct's

who defined in line 85; used 28 times

Defined macros

ANNOUNCE defined in line 112; used 4 times
CHANGED defined in line 110; used 2 times
OFFLINE defined in line 109; used 6 times
ONLINE defined in line 108; used 3 times
STMASK defined in line 111; used 2 times
UTHOSTLEN defined in line 71; used 5 times
UTLINLEN defined in line 66; used 4 times
UTNAMLEN defined in line 65; used 5 times
_PATH_UTMP defined in line 80; used 5 times
Last modified: 1996-11-28
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4091
Valid CSS Valid XHTML 1.0 Strict