1: static char rcsid[]
   2:   = "$Header: /usr/src/ucb/sysline/RCS/sysline.c,v 1.2 83/02/08 16:20:50 jkf Exp $";
   3: 
   4: /*
   5:  * sysline - system status display on 25th line of terminal
   6:  * j.k.foderaro
   7:  *
   8:  * Prints a variety of information on the special status line of terminals
   9:  * that have a status display capability.  Cursor motions, status commands,
  10:  * etc. are gleamed from /etc/termcap.
  11:  * By default, all information is printed, and flags are given on the command
  12:  * line to disable the printing of information.  The information and
  13:  * disabling flags are:
  14:  *
  15:  *  flag	what
  16:  *  -----	----
  17:  *		time of day
  18:  *		load average and change in load average in the last 5 mins
  19:  *		number of user logged on
  20:  *   -p		# of processes the users owns which are runnable and the
  21:  *		  number which are suspended.  Processes whose parent is 1
  22:  *		  are not counted.
  23:  *   -l		users who've logged on and off.
  24:  *   -m		summarize new mail which has arrived
  25:  *
  26:  *  <other flags>
  27:  *   -r		use non reverse video
  28:  *   -c		turn off 25th line for 5 seconds before redisplaying.
  29:  *   -b		beep once one the half hour, twice on the hour
  30:  *   +N		refresh display every N seconds.
  31:  *   -i		print pid first thing
  32:  *   -e		do simple print designed for an emacs buffer line
  33:  *   -h		print hostname between time and load average
  34:  *   -D		print day/date before time of day
  35:  *   -d		debug mode - print status line data in human readable format
  36:  *   -q		quiet mode - don't output diagnostic messages
  37:  *   -s		print Short (left-justified) line if escapes not allowed
  38:  *   -j		Print left Justified line regardless
  39:  *
  40:  */
  41: 
  42: /* turn this on always */
  43: #define WHO
  44: 
  45: /* turn this on if you are on running 4.1a or greater (i.e. a system
  46:    with the gethostname() function */
  47: #define HOSTNAME
  48: 
  49: /* turn this on if you are running on vmunix */
  50: /* #define VMUNIX */
  51: 
  52: /* turn this on if you are running on 2.9 BSD */
  53: #define TWO_NINE
  54: 
  55: /* turn this on if you are running on 4.1c or greater */
  56: /* # define NEW_BOOTTIME */
  57: 
  58: #include <sys/param.h>
  59: #include <signal.h>
  60: #include <stdio.h>
  61: #include <utmp.h>
  62: #include <ctype.h>
  63: #include <unctrl.h>
  64: #include <time.h>
  65: #include <sys/stat.h>
  66: #ifdef VMUNIX
  67: #include <nlist.h>
  68: #include <sys/vtimes.h>
  69: #include <sys/proc.h>
  70: #endif
  71: #ifdef pdp11
  72: #include <a.out.h>
  73: #include <sys/proc.h>
  74: #define strcmpn strncmp
  75: #endif
  76: #ifdef TERMINFO
  77: #include <curses.h>
  78: #include <term.h>
  79: #endif
  80: 
  81: #ifdef VMUNIX
  82: #define MAXUSERS 100
  83: #else
  84: #define MAXUSERS 40
  85: #endif
  86: #define DEFDELAY 60 /* update status once per minute */
  87: #define MAILDIR "/usr/spool/mail"
  88: 
  89: /* if MaxLoad is defined, then if the load average exceeded MaxLoad
  90:  * then the process table will not be scanned and the log in/out data
  91:  * will not be checked.   The purpose of this is to reduced the load
  92:  * on the system when it is loaded.
  93:  */
  94: #define MaxLoad 6.0
  95: 
  96: 
  97: struct nlist nl[] =
  98: #ifdef NEW_BOOTTIME
  99:   { { "_boottime" },    /* After 4.1a the label changed to "boottime" */
 100: #else
 101:   { { "_bootime" }, /* Under 4.1a and earlier it is "bootime" */
 102: #endif
 103: #define NL_BOOT 0
 104:     { "_proc" },
 105: #define NL_PROC 1
 106:     { "_avenrun" },
 107: #define NL_AVEN 2
 108: #ifdef VMUNIX
 109:     { "_nproc" },
 110: #define NL_NPROC 3
 111: #endif
 112: #ifdef  TWO_NINE
 113:     { "_nproc" },
 114: #define NL_NPROC 3
 115: #endif
 116:     { 0 }};
 117: 
 118: struct proc *pr;
 119: int nproc;
 120: unsigned procadr;
 121: 
 122: double avenrun[3];  /* used for storing load averages */
 123: 
 124: int kmem;       /* file pointers for memory */
 125: int ut;
 126: int users, nentries;
 127: 
 128: #ifdef WHO
 129: char whofilename[100];
 130: #endif
 131: 
 132: #ifdef HOSTNAME
 133: char hostname[32];
 134: #endif
 135: 
 136: char lockfilename[100]; /* if exists, will prevent us from running */
 137: 
 138: /* flags which determine which info is printed */
 139: int mailcheck = 1;  /* m - do biff like checking of mail 	*/
 140: int proccheck = 1;  /* p - give information on processes	*/
 141: int logcheck  = 1;  /* l - tell who logs in and out		*/
 142: int hostprint = 0;  /* h - print out hostname		*/
 143: int dateprint = 0;  /* h - print out day/date		*/
 144: int quiet     = 0;  /* q - hush diagnostic messages		*/
 145: 
 146: /* flags which determine how things are printed */
 147: int clr_bet_ref = 0;    /* c - clear line between refeshes 	*/
 148: int reverse     = 1;    /* r - use reverse video 		*/
 149: int shortline   = 0;    /* s - short (left-justified) if escapes not allowed */
 150: int leftline    = 0;    /* j - left-justified even if escapes allowed */
 151: int sawmail;    /* remember mail was seen to print bells	*/
 152: 
 153: /* flags which have terminal do random things	*/
 154: int beep      = 0;  /* b - beep every half hour and twice every hour */
 155: int synch     = 1;  /* synchronize with clock		*/
 156: int printid   = 0;  /* print pid of this process at startup */
 157: 
 158: /*
 159:  * used to turn off reverse video every REVOFF times
 160:  * in an attempt to not wear out the phospher.
 161:  */
 162: #define REVOFF 5
 163: int revtime = 1;
 164: 
 165: /* select output device (status display or straight output (emacs window)) */
 166: int emacs = 0;      /* assume status display */
 167: int dbug = 0;
 168: 
 169: /* used by mail checker */
 170: off_t mailsize = 0;
 171: off_t linebeg = 0;      /* place where we last left off reading */
 172: 
 173: /* globals */
 174: int mailprocessed;
 175: char *username;
 176: struct stat stbuf, mstbuf;  /* mstbuf for mail check only */
 177: char *ourtty,*ttyname();    /* keep track of what tty we're on */
 178: char *getenv();
 179: char *tparm(), *tgoto();
 180: unsigned delay = DEFDELAY;
 181: int chars;
 182: short uid;
 183: double loadavg = 0.0;       /* current load average */
 184: int fullprocess;
 185: int users = 0;
 186: 
 187: /* strings which control status line display */
 188: #ifdef  TERMINFO
 189: 
 190: char    *rev_out, *rev_end, *arrows;
 191: 
 192: #else   /* TERMCAP */
 193: 
 194: char    to_status_line[30];
 195: char    from_status_line[20];
 196: char    dis_status_line[20];
 197: char    rev_out[20], rev_end[20];
 198: char    *arrows, *bell = "\007";
 199: int eslok;  /* escapes on status line okay (reverse, cursor addressing) */
 200: int columns;
 201: #endif
 202: 
 203: /*
 204:  * In order to determine how many people are logged on and who has
 205:  * logged in or out, we read in the /etc/utmp file. We also keep track of
 206:  * the previous utmp file.
 207:  */
 208: struct utmp uts[2][MAXUSERS];
 209: 
 210: outc(c)
 211: char c;
 212: {
 213:     if (dbug)
 214:         printf("%s", unctrl(c));
 215:     else putchar(c);
 216: }
 217: 
 218: erroutc(c)
 219: char c;
 220: {
 221:     if (dbug)
 222:         fprintf(stderr,"%s", unctrl(c));
 223:     else fputc(c,stderr);
 224: }
 225: 
 226: main(argc,argv)
 227: char **argv;
 228: {
 229:     register new,old,tmp;
 230:     int clearbotl();
 231:     char *cp;
 232:     extern char _sobuf[];
 233: 
 234: 
 235:     setbuf(stdout, _sobuf);
 236:     signal(SIGINT,SIG_IGN);
 237:     signal(SIGQUIT,SIG_IGN);
 238:     signal(SIGALRM,SIG_IGN);
 239: #ifdef VMUNIX
 240:     signal(SIGTTOU,SIG_IGN);
 241: #endif
 242:     /*
 243:      * When we logoff, init will do a "vhangup()" on this
 244:      * tty which turns off I/O access and sends a SIGHUP
 245:      * signal.  We catch this and thereby clear the status
 246:      * display.  Note that a bug in 4.1bsd caused the SIGHUP
 247:      * signal to be sent to the wrong process, so you had to
 248:      * `kill -HUP' yourself in your .logout file.
 249:      */
 250:     signal(SIGHUP,clearbotl);
 251: 
 252:     argv++;
 253:     while(--argc > 0) {
 254:     switch(argv[0][0]) {
 255:         case '-': for(cp = &argv[0][1]; *cp ; cp++)
 256:               {
 257:             switch(*cp) {
 258:             case 'r' : reverse = 0; /* turn off reverse video */
 259:                    break;
 260:             case 'c':  clr_bet_ref = 1;
 261:                    break;
 262:             case 'h':  hostprint = 1;
 263:                    break;
 264:             case 'D':  dateprint = 1;
 265:                    break;
 266:             case 'm':  mailcheck = 0;
 267:                    break;
 268:             case 'p':  proccheck = 0;
 269:                    break;
 270:             case 'l':  logcheck = 0;
 271:                    break;
 272:             case 'b':  beep = 1;
 273:                    break;
 274:             case 'i':  printid = 1;
 275:                    break;
 276:             case 'e':  emacs = 1;
 277:                    break;
 278:             case 'd':  dbug = 1;
 279:                    signal(SIGINT, SIG_DFL);
 280:                    signal(SIGQUIT, SIG_DFL);
 281:                    break;
 282:             case 'q':  quiet = 1;
 283:                    break;
 284:             case 's':  shortline = 1;
 285:                    break;
 286:             case 'j':  leftline = 1;
 287:                    break;
 288:             default:   fprintf(stderr,"sysline: bad flag: %c\n",*cp);
 289:             }
 290:               }
 291:               break;
 292:         case '+': delay = atoi(&argv[0][1]);
 293:                   if((delay <= 10) || (delay > 500)) delay = DEFDELAY;
 294:               synch = 0;    /* no more sync */
 295:               break;
 296:         default:  fprintf(stderr,"sysline: illegal argument %s\n",argv[0]);
 297:     }
 298:     argv++;
 299:     }
 300:     if(emacs) {
 301:     columns = 80;
 302:     } else {
 303:         /* if not to emacs window, initialize terminal dependent info */
 304:     initterm();
 305:     }
 306: 
 307:     /* immediately fork and let the parent die if not emacs mode */
 308:     if(!emacs && !dbug && fork()) exit(0);
 309:     uid = getuid();
 310: 
 311:     ourtty = ttyname(2);    /* remember what tty we are on */
 312:     if(printid) { printf("%d\n",getpid()); fflush(stdout);}
 313:     close(1);
 314:     dup2(2, 1);
 315: 
 316:     strcpy(whofilename,getenv("HOME"));
 317:     strcat(whofilename,"/.who");
 318: 
 319:     strcpy(lockfilename,getenv("HOME"));
 320:     strcat(lockfilename,"/.syslinelock");
 321: 
 322: #ifdef HOSTNAME
 323:     if( hostprint ) gethostname(hostname,sizeof(hostname));
 324: #endif
 325: 
 326:     if((ut = open("/etc/utmp",0)) < 0)
 327:     {
 328:     fprintf(stderr,"Can't open utmp");
 329:     exit(1);
 330:     }
 331: 
 332:     if((kmem = open("/dev/kmem",0)) < 0)
 333:     {
 334:     fprintf(stderr,"Can't open kmem");
 335:     exit(1);
 336:     }
 337: 
 338:     /* read in namelist in order to get location of symbols */
 339:     readnamelist();
 340: 
 341:     if(proccheck) initprocread();
 342: 
 343:     if(mailcheck)
 344:     {
 345:     chdir(MAILDIR);
 346:     username = getenv("USER");
 347:     if(stat(username,&mstbuf) != -1)
 348:     {
 349:         mailsize = mstbuf.st_size;
 350:     }
 351:     else mailsize = 0;
 352:     }
 353: 
 354:     old = 0;
 355:     new = 1;
 356: 
 357:     while(emacs || isloggedin())
 358:     {
 359:     if(access(lockfilename,0))
 360:     {
 361:         mailprocessed = 0;
 362:         prtinfo(old,new);
 363:         sleep(delay);
 364:         if(clr_bet_ref)
 365:         {
 366:         tputs(dis_status_line, 1, outc);
 367:         fflush(stdout);
 368:         sleep(5);
 369:         }
 370:         revtime = (1 + revtime) % REVOFF;
 371: 
 372:         /*
 373: 	     * if we have processed mail, then dont switch utmp pointers
 374: 	     * since we havent printed the people whove logged in and out
 375: 	     */
 376:         if(!mailprocessed || !fullprocess)
 377:         {
 378:         tmp = old;
 379:         old = new;
 380:         new = tmp;
 381:         }
 382:     } else sleep(60);
 383:     }
 384:     clearbotl();
 385:     /* NOTREACHED */
 386: }
 387: 
 388: isloggedin()
 389: {
 390:    /*
 391:     * you can tell if a person has logged out if the owner of
 392:     * the tty has changed
 393:     */
 394:     struct stat statbuf;
 395:     if(fstat(2,&statbuf) == 0)
 396:     {
 397:     if(statbuf.st_uid == uid) return(1);
 398:     }
 399:     return(0);  /* not logged in */
 400: }
 401: 
 402: 
 403: readnamelist()
 404: {
 405:     time_t bootime, clock, nintv, time();
 406: 
 407: #ifdef pdp11
 408:     nlist("/unix",nl);
 409: #else
 410:     nlist("/vmunix",nl);
 411: #endif
 412:     if(nl[0].n_value == 0) {
 413:         if (!quiet)
 414:         fprintf(stderr, "No namelist\n");
 415:         return;
 416:     }
 417:     lseek(kmem, (long)nl[NL_BOOT].n_value, 0);
 418:     read(kmem, &bootime, sizeof(bootime));
 419:     (void) time(&clock);
 420:     nintv = clock - bootime;
 421:     if (nintv <= 0L || nintv > 60L*60L*24L*365L) {
 422:        if (!quiet)
 423:         fprintf(stderr, "Time makes no sense... namelist must be wrong\n");
 424:        nl[NL_PROC].n_value = nl[NL_AVEN].n_value = 0;
 425:     }
 426: }
 427: 
 428: readutmp(n)
 429: {
 430:     lseek(ut,0L,0);
 431:     nentries = read(ut,&uts[n][0],MAXUSERS*sizeof(struct utmp))
 432:                / sizeof(struct utmp);
 433: }
 434: 
 435: /*
 436:  * read in the process table locations and sizes, and allocate space
 437:  * for storing the process table.  This is done only once.
 438:  */
 439: initprocread()
 440: {
 441:     if (nl[NL_PROC].n_value == 0) return;
 442: #ifdef VMUNIX
 443:     lseek(kmem,(long)nl[NL_PROC].n_value,0);
 444:     read(kmem,&procadr,sizeof(procadr));
 445:     lseek(kmem,(long)nl[NL_NPROC].n_value,0);
 446:     read(kmem,&nproc,sizeof(nproc));
 447: #endif
 448: #ifdef pdp11
 449:     procadr = nl[NL_PROC].n_value;
 450: #ifdef  TWO_NINE
 451:     lseek(kmem,(long)nl[NL_NPROC].n_value,0);
 452:     read(kmem,&nproc,sizeof(nproc));
 453: #else
 454:     nproc = NPROC;  /* from param.h */
 455: #endif
 456: #endif
 457:     pr = (struct proc *) calloc(nproc,sizeof(struct proc));
 458:     if (pr == (struct proc *) NULL) {
 459:         if (!quiet)
 460:             fprintf(stderr,"Not enough memory for proc search\n");
 461:         nl[NL_PROC].n_value = 0;
 462:     }
 463: }
 464: 
 465: /*
 466:  * read in the process table.  This assumes that initprocread has alread been
 467:  * called to set up storage.
 468:  */
 469: readproctab()
 470: {
 471:     if (nl[NL_PROC].n_value == 0) return(0);
 472:     /* printf("There are %d entries beginning at %x\n",nproc,procadr); */
 473:     lseek(kmem,(long)procadr,0);
 474:     read(kmem,pr,nproc * sizeof(struct proc));
 475:     return(1);
 476: }
 477: 
 478: /*
 479:  * codes to say what has happened to a particular entry in utmp
 480:  * NOCH means no change, ON means new person logged on,
 481:  * OFF means person logged off.
 482:  */
 483: #define NOCH 0;
 484: #define ON 0x1
 485: #define OFF 0x2
 486: 
 487: prtinfo(old,new)
 488: int old,new;
 489: {
 490:     int procrun,procstop;
 491:     int on,off;
 492:     int status[MAXUSERS];
 493:     register int i;
 494:     double diff;
 495: 
 496:     stringinit();
 497: 
 498: #ifdef WHO
 499:     /* check for file named .who in the home directory */
 500:     whocheck();
 501: #endif
 502: 
 503:     timeprint();
 504: 
 505:     /*
 506: 	 * if mail is seen, don't print rest of info, just the mail
 507: 	 * reverse new and old so that next time we run, we won't lose log
 508: 	 * in and out information
 509: 	 */
 510:     if(mailcheck && (sawmail = mailseen()) )
 511:     {
 512:         mailprocessed = 1;
 513:         goto bottom;
 514:     }
 515: 
 516: #ifdef HOSTNAME
 517:     /*
 518: 	 * print hostname info if requested
 519: 	 */
 520:     if(hostprint)
 521:     {
 522:         stringspace();
 523:         stringcat(hostname,strlen(hostname),1);
 524:     }
 525: #endif
 526: 
 527:     /*
 528: 	 * print load average and difference between current load average
 529: 	 * and the load average 5 minutes ago
 530: 	 */
 531:     if (nl[NL_AVEN].n_value != 0) {
 532:         stringspace();
 533: #ifdef VMUNIX
 534:         lseek(kmem,(long)nl[NL_AVEN].n_value,0);
 535:         read(kmem,avenrun,sizeof(avenrun));
 536: #endif
 537: #ifdef pdp11
 538:         loadav(avenrun);
 539: #endif
 540:         stringprt("%.1f ",avenrun[0]);
 541:         if((diff = avenrun[0] - avenrun[1]) < 0.0)
 542:              stringprt("%.1f",diff);
 543:         else stringprt("+%.1f",diff);
 544:         loadavg = avenrun[0];   /* remember load average */
 545:     }
 546: 
 547:     /*
 548: 	 * print log on and off information
 549: 	 */
 550:     stringspace();
 551: 
 552:     fullprocess = 1;
 553: 
 554: #ifdef MaxLoad
 555:     if(loadavg > MaxLoad) fullprocess = 0;  /* too loaded to run */
 556: #endif
 557:     /* read utmp file (logged in data) only if we are doing a full
 558: 	   process or if this is the first time and we are calculating
 559: 	   the number of users
 560: 	 */
 561:     if(fullprocess || (users == 0)) readutmp(new);
 562: 
 563: 
 564:     /*
 565: 	 * make a pass through utmp, checking if person has logged off
 566: 	 * or on.  Results are stored in status[]
 567: 	 */
 568:     on = off = 0;
 569:     /* only do this if it hasn't been done yet (users == 0) or
 570: 	 * if the load average is low enough to permit it
 571: 	 */
 572:     if(fullprocess || (users == 0 ))
 573:     {
 574:         users = 0;
 575:         for(i=0 ; i < nentries ; i++)
 576:         {
 577:         if(strcmpn(uts[old][i].ut_name,uts[new][i].ut_name,8) != 0)
 578:         {
 579:             if(uts[old][i].ut_name[0] == '\0')
 580:             {
 581:             status[i] = ON;
 582:             on++;
 583:             }
 584:             else if (uts[new][i].ut_name[0] == '\0')
 585:             {
 586:             status[i] = OFF;
 587:             off++;
 588:             }
 589:             else {
 590:             status[i] = ON | OFF;
 591:             on++;
 592:             off++;
 593:             }
 594:         }
 595:         else status[i] = NOCH;
 596: 
 597:         if(uts[new][i].ut_name[0]) users++;
 598:         }
 599:     }
 600: 
 601:     /* at this point we know how many users there are */
 602:     stringprt("%du",users);
 603: 
 604:     /* if there is any unread mail, put out a star */
 605:     /* fprintf(stderr,"mailsz:%d,mtime:%d,atime:%d\n",
 606: 		mailsize,mstbuf.st_mtime,mstbuf.st_atime); */
 607:     if((mailsize > 0) && (mstbuf.st_mtime >= mstbuf.st_atime))
 608:         stringcat("*",1,1);
 609: 
 610:     /* if the load is too high, then we indicate that with a - sign */
 611:     if(!fullprocess && (proccheck || logcheck)) stringcat("-",1,1);
 612: 
 613:     /* if we are to check on number of process running, do so now */
 614:     if(fullprocess && proccheck && readproctab())
 615:     {
 616:         /*
 617: 	     * we are only interested in processes which have the same
 618: 	     * uid as us, and whose parent process id is not 1.
 619: 	     */
 620:         procrun = procstop = 0;
 621:         for(i=0; i < nproc ; i++)
 622:         {
 623:         if((pr[i].p_stat == 0) || (pr[i].p_pgrp == 0)) continue;
 624:         if((pr[i].p_uid == uid) && (pr[i].p_ppid != 1))
 625:         {
 626:             /* printf("found pid %d, stat=%o\n", pr[i].p_pid, pr[i].p_stat); */
 627:             switch (pr[i].p_stat) {
 628: 
 629:             case SSTOP:
 630:                 procstop++;
 631:                 break;
 632: 
 633:             case SSLEEP:
 634:                 /*
 635: 			     * sleep can mean waiting for a signal or just
 636: 			     * in a disk or page wait queue ready to run.
 637: 			     * We can tell if it is the later by the pri being
 638: 			     * negative
 639: 			     */
 640:                 if (pr[i].p_pri < PZERO) procrun++;
 641:                 break;
 642: 
 643:             case SWAIT:
 644:             case SRUN:
 645:             case SIDL:
 646:                 procrun++;
 647: 
 648:             }
 649:         }
 650:         }
 651: 
 652:         if((procrun > 0) || (procstop > 0))
 653:         {
 654:         stringspace();
 655:         if((procrun > 0) && (procstop > 0))
 656:         {
 657:            stringprt("%dr",procrun);
 658:            stringprt(" %ds",procstop);
 659:         }
 660:         else if(procrun > 0) stringprt("%dr",procrun);
 661:              else stringprt("%ds",procstop);
 662:         }
 663:     }
 664: 
 665:     /*
 666: 	 * if anyone has logged on or off, and we are interested in it,
 667: 	 * print it out
 668: 	 */
 669:     if(logcheck && on)
 670:     {
 671:         stringspace();
 672:         stringprt("on:",on);
 673:         for(i = 0 ; i < nentries ; i++)
 674:         {
 675:         if(status[i] & ON)
 676:         {
 677:             stringprt(" %.8s",uts[new][i].ut_name);
 678:             ttyprint(uts[new][i].ut_line);
 679:         }
 680:         }
 681:     }
 682: 
 683:     /*
 684: 	 * check for people logging off if we are intereste
 685: 	 */
 686:     if(logcheck && off)
 687:     {
 688:         stringspace();
 689:         stringprt("off:",off);
 690:         for(i = 0 ; i < nentries ; i++)
 691:         {
 692:         if(status[i] & OFF)
 693:         {
 694:             stringprt(" %.8s",uts[old][i].ut_name);
 695:             ttyprint(uts[old][i].ut_line);
 696:         }
 697:         }
 698:     }
 699: bottom:
 700:     /* dump out what we know */
 701:     stringdump();
 702: }
 703: 
 704: timeprint()
 705: {
 706:     long curtime;
 707:     struct tm *tp, *localtime();
 708:     static int beepable=0;
 709: 
 710:     /* always print time */
 711:     time(&curtime);
 712:     tp = localtime(&curtime);
 713: 
 714:     if (dateprint)
 715:         stringprt("%.11s", ctime(&curtime));
 716:     stringprt("%d:",(tp->tm_hour > 12 ? tp->tm_hour - 12
 717:                      : (tp->tm_hour == 0 ? 12 : tp->tm_hour)));
 718:     stringprt("%02d",tp->tm_min);
 719: 
 720:     if(synch) delay = 60 - tp->tm_sec;  /* sync with clock */
 721: 
 722:     /* beepable is used to insure that we get at most one set of beeps
 723: 	    every half hour */
 724:     if(beep && beepable && (tp->tm_min == 30))
 725:     {
 726:         tputs(bell, 1, outc); fflush(stdout);
 727:         beepable = 0;
 728:     }
 729:     else if(beep && beepable && (tp->tm_min == 00))
 730:     {
 731:         tputs(bell, 1, outc); fflush(stdout);
 732:         sleep(2);
 733:         tputs(bell, 1, outc); fflush(stdout);
 734:         beepable = 0;
 735:     }
 736:     else if(beep && ((tp->tm_min != 00) || (tp->tm_min != 30)))
 737:         beepable = 1;
 738: 
 739: }
 740: 
 741: /*
 742:  * whocheck -- check for file named .who and print it on the who line first
 743:  */
 744: whocheck()
 745: {
 746:     register wf,i,chss;
 747:     char buff[81];
 748: 
 749:     if((wf = open(whofilename,0)) >= 0)
 750:     {
 751:     chss = read(wf,buff,80);
 752:     if(chss == 0)
 753:     {
 754:         close(wf);
 755:         return;
 756:     }
 757:     buff[chss] = '\0';
 758:     /*
 759: 	 * remove all line feeds, and replace by spaces if they are within
 760: 	 * the message, else replace them by nulls.
 761: 	 */
 762:     for(i = chss; i >= 0; i--)
 763:     {
 764:         if(buff[i] == '\n')
 765:         {
 766:         if(buff[i+1]) buff[i] = ' ';
 767:         else buff[i] = '\0';
 768:         }
 769:     }
 770:     stringprt("%s",buff);
 771:     stringspace();
 772:     close(wf);
 773:     }
 774: }
 775: 
 776: /*
 777:  * ttyprint -- given the name of a tty, print in the string buffer its
 778:  * short name surrounded by parenthesis.
 779:  * ttyxx is printed as (xx)
 780:  * console is printed as (cty)
 781:  */
 782: ttyprint(name)
 783: char *name;
 784: {
 785:     char buff[10];
 786: 
 787:     if(strcmpn(name,"tty",3)==0)
 788:     {
 789:     sprintf(buff,"(%s)",name+3);
 790:     }
 791:     else if(strcmp(name,"console")== 0)
 792:     {
 793:     sprintf(buff,"(cty)");
 794:     }
 795:     else sprintf(buff,"(%s)",name);
 796: 
 797:     stringcat(buff,strlen(buff),0);
 798: }
 799: 
 800: /*
 801:  * mail checking function
 802:  * returns 0 if no mail seen
 803:  */
 804: mailseen()
 805: {
 806:     FILE *mfd;
 807:     int retval = 0;
 808:     int chs,initchs;
 809:     register char *rp,*cp;
 810:     char lbuf[100], sendbuf[100];
 811:     int toprint,seenspace = 0;
 812: 
 813:     if(stat(username,&mstbuf) != -1)
 814:     {
 815:     if((mstbuf.st_size > mailsize) && ((mfd=fopen(username,"r")) != NULL))
 816:     {
 817:         /* fprintf(stderr,"Mail gotten was %db, now %db\n",
 818: 				 mailsize,stbuf.st_size); */
 819:         fseek(mfd,mailsize,0);
 820:         while((initchs = readline(mfd, lbuf, sizeof(lbuf))) != EOF)
 821:         {
 822:         if(strcmpn(lbuf,"From",4) == 0)
 823:         {
 824:             cp = lbuf+5;    /* start after the From */
 825:             while(*cp && (*++cp != ' ')); /* skip to blank */
 826:             *cp = '\0';     /* terminate name */
 827:             stringspace();
 828:             /*  if(!emacs) stringcat(bell,0,0);   BELL MOVED */
 829:             sprintf(sendbuf,"Mail from %s ",lbuf+5);
 830:             stringcat(sendbuf,strlen(sendbuf),0);
 831:             /* print message preceeded by little arrow */
 832:             /* skip over the headers and look for blank line */
 833:             while(((chs = readline(mfd, lbuf, sizeof(lbuf))) != EOF) && (chs != 0))
 834:                 if(strcmpn(lbuf,"Subject",7)==0)
 835:                 {
 836:                 sprintf(sendbuf,"on %s",lbuf+9);
 837:                 stringcat(sendbuf,strlen(sendbuf),1);
 838:             }
 839:             if(!emacs) stringcat(arrows,2,0);
 840:             else stringcat(" : ",3,0);
 841: 
 842:             if(chs != EOF)
 843:             {
 844:             cp = sendbuf;
 845:             toprint = columns - chars; /* space left on line */
 846:             lbuf[0] = '\0';
 847:             while((chs = readline(mfd, lbuf, sizeof(lbuf))) != EOF)
 848:             {
 849:                 if(toprint > 0)
 850:                 {
 851:                 *cp++ = ' ';    /* space before lines */
 852:                 toprint--;
 853:                 }
 854:                 rp = lbuf;
 855:                 if(strcmpn(lbuf,"From",4) == 0) break;
 856:                 while(*rp && (toprint > 0))
 857:                 {
 858:                 if(isspace(*rp))
 859:                 {
 860:                     if(!seenspace)
 861:                     {
 862:                     *cp++ = ' ';
 863:                     seenspace = 1;
 864:                     toprint--;
 865:                     }
 866:                 }
 867:                 else {
 868:                     *cp++ = *rp;
 869:                     seenspace = 0;
 870:                     toprint--;
 871:                 }
 872:                 rp++;
 873:                 }
 874:             }
 875:             *cp = '\0';
 876:             stringcat(sendbuf,strlen(sendbuf),1);
 877:             /*  if(!emacs) stringcat(bell,0,0);   BELL MOVED */
 878:             retval = 1;
 879:             }
 880:         break;
 881:         }
 882:         }
 883:         if(initchs == EOF)
 884:         {
 885:         stringprt("Mail has just arrived",chs);
 886:         }
 887:     /*
 888: 	 * want to update write time  so a star will
 889: 	 * appear after the number of users until the
 890: 	 * user reads his mail
 891: 	 */
 892:     mailsize = linebeg;
 893:     touch(username,mfd);
 894:     fclose(mfd);
 895:     }
 896:     else mailsize = mstbuf.st_size;
 897:     }
 898:     else mailsize = 0;
 899:     return(retval);
 900: }
 901: 
 902: /*
 903:  * readline -- read a line from fp and store it in buf.
 904:  * return the number of characters read.
 905:  */
 906: readline(fp, buf, maxch)
 907: FILE *fp;
 908: char *buf;
 909: {
 910:     register char *cp, ch;
 911:     int size = maxch;
 912:     long ftell();
 913: 
 914:     linebeg = ftell(fp);        /* remember loc where line begins */
 915:     cp = buf;
 916:     while(((ch=getc(fp)) != EOF) && (ch != '\n') && (size-- > 0)) *cp++ = ch;
 917:     *cp = '\0';
 918:     if((size == maxch) && (ch == EOF)) return (EOF);
 919:     else return(maxch - size);
 920: }
 921: 
 922: 
 923: /* string hacking functions */
 924: 
 925: int eol;    /* non zero when we have hit the end of line */
 926: char *sp;
 927: char strarr[120];
 928: 
 929: stringinit()
 930: {
 931:     sp = strarr;
 932:     chars = 0;
 933:     eol = 0;
 934: }
 935: 
 936: stringprt(format,value)
 937: char *format;
 938: {
 939:     char tempbuf[150];
 940:     int bufsiz;
 941: 
 942:     sprintf(tempbuf,format,value);
 943:     bufsiz = strlen(tempbuf);
 944:     stringcat(tempbuf,bufsiz,0);
 945: }
 946: 
 947: stringdump()
 948: {
 949:     char bigbuf[200];
 950:     register char *cp;
 951:     register int i;
 952:     char blanks[80];
 953: 
 954:     *sp = '\0';
 955:     bigbuf[0] = 0;
 956:     if(!emacs) {
 957:     if (sawmail) strcat(bigbuf, bell);
 958:     if (eslok) {
 959:         if(!leftline)
 960:             cp = tparm(to_status_line, columns - chars);
 961:         else
 962:             cp = tparm(to_status_line, 0);
 963:         strcat(bigbuf, cp);
 964:     } else {
 965:         strcat(bigbuf, to_status_line);
 966:         if (!shortline & !leftline) {
 967:         for (i=0; i < (columns-chars); i++)
 968:             blanks[i] = ' ';
 969:         blanks[columns-chars] = '\0';
 970:         strcat(bigbuf, blanks);
 971:         }
 972:     }
 973:     if(reverse && !(revtime == 0)) strcat(bigbuf, rev_out);
 974:     }
 975:     strcat(bigbuf,strarr);
 976:     if (!emacs) {
 977:     if (reverse) strcat(bigbuf, rev_end);
 978:     strcat(bigbuf, from_status_line);
 979:     if (sawmail) {
 980:         strcat(bigbuf, bell);
 981:         strcat(bigbuf, bell);
 982:     }
 983:     tputs(bigbuf, 1, outc);
 984:     if (dbug) putchar('\n');
 985:     fflush(stdout);
 986:     } else
 987:     write(2,bigbuf,strlen(bigbuf));
 988: }
 989: 
 990: stringspace()
 991: {
 992:     if(!emacs && reverse && !(revtime == 0)) {
 993: #ifdef TERMINFO
 994:     stringcat(rev_end, magic_cookie_glitch<=0?0:magic_cookie_glitch, 0);
 995:     stringcat(" ",1,0);
 996:     stringcat(rev_out, magic_cookie_glitch<=0?0:magic_cookie_glitch, 0);
 997: #else
 998:     stringcat(rev_end,0,0);
 999:     stringcat(" ",1,0);
1000:     stringcat(rev_out,0,0);
1001: #endif
1002:     } else stringcat(" ",1,0);
1003: }
1004: 
1005: /*
1006:  * stringcat :: concatenate the characters in string str to the list we are
1007:  * 	        building to send out.
1008:  *
1009:  * the three args are
1010:  *    str - the string to print. may contain funny (terminal control) chars.
1011:  *    chrs - the number of printable characters in the string
1012:  *    trunc - a flag which is non zero if we should truncate strings which
1013:  *   	      don't fit.  If this is 0 then if a string doesn't completely
1014:  *	      fit it wont' be printed, this prevents us from getting 1/2
1015:  *	      way through an escape sequence.
1016:  */
1017: stringcat(str,chrs,trunc)
1018: char *str;
1019: {
1020: 
1021:     if((chrs == 0) || (!eol && chars + chrs <= columns)
1022:                || (!eol && trunc && (chars < columns)))
1023:     {
1024:     while(*sp++ = *str++)
1025:         if(trunc)
1026:         {
1027:         if(++chars >= columns)  /* check for trunc */
1028:         {
1029:             eol = 1;
1030:             return;
1031:         }
1032:         }
1033:     sp--;
1034:     if(!trunc) chars += chrs;
1035:     }
1036:     else eol = 1;
1037: }
1038: 
1039: /*
1040:  * touch :: update the modify time of a file.
1041:  */
1042: touch(name,filedes)
1043: char *name;     /* name of file */
1044: FILE *filedes;      /* already open for read file descriptor */
1045: {
1046:     register fd;
1047:     char buf[1];
1048: 
1049:     lseek(fileno(filedes),0L,0);
1050:     read(fileno(filedes),buf,1);    /* get first byte */
1051:     if((fd = open(name,2)) >= 0)    /* open in append mode */
1052:     {
1053:         lseek(fd,0L,0);     /* go to beginning */
1054:         write(fd,buf,1);        /* and rewrite first byte */
1055:         close(fd);
1056:     }
1057: }
1058: 
1059: 
1060: /*
1061:  * clearbotl :: clear bottom line.
1062:  * called when process quits or is killed.
1063:  * it clears the bottom line of the terminal.
1064:  */
1065: clearbotl()
1066: {
1067:     register int fd;
1068:     int exit();
1069: 
1070:     signal(SIGALRM,exit);
1071:     alarm(30);  /* if can't open in 30 secs, just die */
1072:     if( !emacs && (fd = open(ourtty,1)) >=0)
1073:     {
1074:         write(fd,dis_status_line,strlen(dis_status_line));
1075:         close(fd);
1076:     }
1077:     exit(0);
1078: }
1079: 
1080: #ifdef TERMINFO
1081: initterm()
1082: {
1083:     static char standbuf[40];
1084: 
1085:     setupterm(0, 1, 0);
1086:     if (!has_status_line) {
1087:         /* not an appropriate terminal */
1088:         if (!quiet)
1089:            fprintf(stderr, "sysline: no status capability for %s\n",
1090:             getenv("TERM"));
1091:         exit(1);
1092:     }
1093:     if (status_line_esc_ok) {
1094:         if (set_attributes) {
1095:             /* reverse video mode */
1096:             strcpy(standbuf, tparm(set_attributes,0,0,1,0,0,0,0,0,0));
1097:             rev_out = standbuf;
1098:             rev_end = exit_attribute_mode;
1099:         } else if (enter_standout_mode && exit_standout_mode) {
1100:             rev_out = enter_standout_mode;
1101:             rev_end = exit_standout_mode;
1102:         } else {
1103:             rev_out = rev_end = "";
1104:         }
1105:     } else
1106:         rev_out = rev_end = "";
1107:     columns--;  /* avoid cursor wraparound */
1108: }
1109: 
1110: #else   /* TERMCAP */
1111: 
1112: initterm()
1113: {
1114:     char *term, *cp;
1115:     char tbuf[1024], is2[40];
1116:     extern char *UP;
1117: 
1118:     if ((term=getenv("TERM")) == NULL) {
1119:         if (!quiet)
1120:            fprintf(stderr, "sysline: No TERM variable in enviroment\n");
1121:         exit(1);
1122:     }
1123:     if (tgetent(tbuf, term) <= 0) {
1124:         if (!quiet)
1125:            fprintf(stderr, "sysline: Unknown terminal type: %s\n", term);
1126:         exit(1);
1127:     }
1128:     if (tgetflag("hs") <= 0) {
1129:         if (!strcmpn(term, "h19", 3)) {
1130:             /* for upward compatability with h19sys */
1131:             strcpy(to_status_line, "\033j\033x5\033x1\033Y8%+ \033o");
1132:             strcpy(from_status_line, "\033k\033y5");
1133:             strcpy(dis_status_line, "\033y1");
1134:             strcpy(rev_out, "\033p");
1135:             strcpy(rev_end, "\033q");
1136:             arrows = "\033Fhh\033G";
1137:             columns = 80;
1138:             UP = "\b";
1139:             return;
1140:         }
1141:         if (!quiet)
1142:            fprintf(stderr, "sysline: No status capability for %s\n", term);
1143:         exit(1);
1144:     }
1145:     cp = is2;
1146:     if (tgetstr("i2", &cp) != NULL) {
1147:         /* someday tset will do this */
1148:         tputs(is2, 1, erroutc);
1149:         fflush(stdout);
1150:     }
1151: 
1152:     /* the "-1" below is to avoid cursor wraparound problems */
1153:     columns = tgetnum("co") - 1;
1154:     cp = to_status_line;
1155:     tgetstr("ts", &cp);
1156:     cp = from_status_line;
1157:     tgetstr("fs", &cp);
1158:     cp = dis_status_line;
1159:     tgetstr("ds", &cp);
1160:     eslok = tgetflag("es");
1161:     if (eslok) {
1162:         cp = rev_out;
1163:         tgetstr("so", &cp);
1164:         cp = rev_end;
1165:         tgetstr("se", &cp);
1166:     } else {
1167:         reverse = 0;    /* turn off reverse video */
1168:     };
1169:     UP = "\b";
1170:     if (!strcmpn(term, "h19", 3))
1171:         arrows = "\033Fhh\033G";    /* "two tiny graphic arrows" */
1172:     else
1173:         arrows = "->";
1174: }
1175: 
1176: char *
1177: tparm(cap, parm)
1178: char *cap;
1179: int parm;
1180: {
1181:     return tgoto(cap, 0, parm);
1182: }
1183: #endif

Defined functions

clearbotl defined in line 1065; used 3 times
erroutc defined in line 218; used 1 times
initprocread defined in line 439; used 1 times
initterm defined in line 1112; used 1 times
isloggedin defined in line 388; used 1 times
mailseen defined in line 804; used 1 times
main defined in line 226; never used
outc defined in line 210; used 5 times
prtinfo defined in line 487; used 1 times
readline defined in line 906; used 3 times
readnamelist defined in line 403; used 1 times
readproctab defined in line 469; used 1 times
readutmp defined in line 428; used 1 times
stringcat defined in line 1017; used 17 times
stringdump defined in line 947; used 1 times
stringinit defined in line 929; used 1 times
stringprt defined in line 936; used 17 times
stringspace defined in line 990; used 8 times
timeprint defined in line 704; used 1 times
touch defined in line 1042; used 1 times
tparm defined in line 1176; used 4 times
ttyprint defined in line 782; used 2 times
whocheck defined in line 744; used 1 times

Defined variables

arrows defined in line 198; used 4 times
avenrun defined in line 122; used 7 times
beep defined in line 154; used 4 times
bell defined in line 198; used 6 times
chars defined in line 181; used 9 times
clr_bet_ref defined in line 147; used 2 times
columns defined in line 200; used 11 times
dateprint defined in line 143; used 2 times
dbug defined in line 167; used 5 times
delay defined in line 180; used 6 times
dis_status_line defined in line 196; used 5 times
emacs defined in line 166; used 9 times
eol defined in line 925; used 5 times
eslok defined in line 199; used 3 times
from_status_line defined in line 195; used 3 times
fullprocess defined in line 184; used 7 times
hostname defined in line 133; used 4 times
hostprint defined in line 142; used 3 times
kmem defined in line 124; used 13 times
leftline defined in line 150; used 3 times
linebeg defined in line 171; used 2 times
loadavg defined in line 183; used 2 times
lockfilename defined in line 136; used 3 times
logcheck defined in line 141; used 4 times
mailcheck defined in line 139; used 3 times
mailprocessed defined in line 174; used 3 times
mailsize defined in line 170; used 8 times
mstbuf defined in line 176; used 7 times
nentries defined in line 126; used 4 times
nl defined in line 97; never used
nproc defined in line 119; used 8 times
ourtty defined in line 177; used 2 times
pr defined in line 118; used 9 times
printid defined in line 156; used 2 times
procadr defined in line 120; used 4 times
proccheck defined in line 140; used 4 times
quiet defined in line 144; used 8 times
rcsid defined in line 1; never used
rev_end defined in line 197; used 9 times
rev_out defined in line 197; used 9 times
reverse defined in line 148; used 5 times
revtime defined in line 163; used 4 times
sawmail defined in line 151; used 3 times
shortline defined in line 149; used 2 times
sp defined in line 926; used 4 times
stbuf defined in line 176; never used
strarr defined in line 927; used 2 times
synch defined in line 155; used 2 times
to_status_line defined in line 194; used 5 times
uid defined in line 182; used 3 times
username defined in line 175; used 5 times
users defined in line 185; used 5 times
ut defined in line 125; used 3 times
uts defined in line 208; used 10 times
whofilename defined in line 129; used 3 times

Defined macros

DEFDELAY defined in line 86; used 2 times
HOSTNAME defined in line 47; used 3 times
MAILDIR defined in line 87; used 1 times
MAXUSERS defined in line 84; used 3 times
MaxLoad defined in line 94; used 2 times
NL_AVEN defined in line 107; used 3 times
NL_BOOT defined in line 103; used 1 times
NL_NPROC defined in line 114; used 2 times
NL_PROC defined in line 105; used 6 times
NOCH defined in line 483; used 1 times
OFF defined in line 485; used 3 times
ON defined in line 484; used 3 times
REVOFF defined in line 162; used 1 times
TWO_NINE defined in line 53; used 2 times
WHO defined in line 43; used 2 times
strcmpn defined in line 74; used 7 times
Last modified: 1983-05-26
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3734
Valid CSS Valid XHTML 1.0 Strict