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