122534Smckusick /* 222534Smckusick * Copyright (c) 1980 Regents of the University of California. 334586Sbostic * All rights reserved. 434586Sbostic * 542769Sbostic * %sccs.include.redist.c% 622534Smckusick */ 722534Smckusick 822534Smckusick #ifndef lint 922534Smckusick char copyright[] = 1022534Smckusick "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1122534Smckusick All rights reserved.\n"; 1234586Sbostic #endif /* not lint */ 1322534Smckusick 1422534Smckusick #ifndef lint 15*46661Sbostic static char sccsid[] = "@(#)sysline.c 5.17 (Berkeley) 02/25/91"; 1634586Sbostic #endif /* not lint */ 1722534Smckusick 1822534Smckusick /* 1922534Smckusick * sysline - system status display on 25th line of terminal 2022534Smckusick * j.k.foderaro 2122534Smckusick * 2222534Smckusick * Prints a variety of information on the special status line of terminals 2322534Smckusick * that have a status display capability. Cursor motions, status commands, 2422534Smckusick * etc. are gleamed from /etc/termcap. 2522534Smckusick * By default, all information is printed, and flags are given on the command 2622534Smckusick * line to disable the printing of information. The information and 2722534Smckusick * disabling flags are: 2822534Smckusick * 2922534Smckusick * flag what 3022534Smckusick * ----- ---- 3122534Smckusick * time of day 3222534Smckusick * load average and change in load average in the last 5 mins 3322534Smckusick * number of user logged on 3422534Smckusick * -p # of processes the users owns which are runnable and the 3522534Smckusick * number which are suspended. Processes whose parent is 1 3622534Smckusick * are not counted. 3722534Smckusick * -l users who've logged on and off. 3822534Smckusick * -m summarize new mail which has arrived 3922534Smckusick * 4022534Smckusick * <other flags> 4122534Smckusick * -r use non reverse video 4222534Smckusick * -c turn off 25th line for 5 seconds before redisplaying. 4322534Smckusick * -b beep once one the half hour, twice on the hour 4422534Smckusick * +N refresh display every N seconds. 4522534Smckusick * -i print pid first thing 4622534Smckusick * -e do simple print designed for an emacs buffer line 4722534Smckusick * -w do the right things for a window 4822534Smckusick * -h print hostname between time and load average 4922534Smckusick * -D print day/date before time of day 5022534Smckusick * -d debug mode - print status line data in human readable format 5122534Smckusick * -q quiet mode - don't output diagnostic messages 5222534Smckusick * -s print Short (left-justified) line if escapes not allowed 5322534Smckusick * -j Print left Justified line regardless 5422534Smckusick */ 5522534Smckusick 5622534Smckusick #define BSD4_2 /* for 4.2 BSD */ 5722534Smckusick #define WHO /* turn this on always */ 5822534Smckusick #define RWHO /* 4.1a or greater, with rwho */ 5922534Smckusick #define NEW_BOOTTIME /* 4.1c or greater */ 6022534Smckusick 6122534Smckusick #define NETPREFIX "ucb" 6222534Smckusick #define DEFDELAY 60 /* update status once per minute */ 6322534Smckusick /* 6422534Smckusick * if MAXLOAD is defined, then if the load average exceeded MAXLOAD 6522534Smckusick * then the process table will not be scanned and the log in/out data 6622534Smckusick * will not be checked. The purpose of this is to reduced the load 6722534Smckusick * on the system when it is loaded. 6822534Smckusick */ 6922534Smckusick #define MAXLOAD 6.0 7022534Smckusick 7122534Smckusick #include <sys/param.h> 7222534Smckusick #include <sys/time.h> 7322534Smckusick #include <sys/stat.h> 7422534Smckusick #include <sys/vtimes.h> 7522534Smckusick #include <sys/proc.h> 76*46661Sbostic #include <sys/ioctl.h> 77*46661Sbostic #include <signal.h> 78*46661Sbostic #include <fcntl.h> 79*46661Sbostic #include <utmp.h> 80*46661Sbostic #include <nlist.h> 8122534Smckusick #include <curses.h> 8222534Smckusick #undef nl 8322534Smckusick #ifdef TERMINFO 8422534Smckusick #include <term.h> 85*46661Sbostic #endif 86*46661Sbostic #include <stdarg.h> 87*46661Sbostic #include <unistd.h> 88*46661Sbostic #include <stdlib.h> 89*46661Sbostic #include <string.h> 90*46661Sbostic #include <stdio.h> 91*46661Sbostic #include <ctype.h> 9222534Smckusick 9322534Smckusick #ifdef RWHO 9424502Skarels #include <protocols/rwhod.h> 9524502Skarels 9622534Smckusick #define DOWN_THRESHOLD (11 * 60) 9722534Smckusick 9822534Smckusick struct remotehost { 9922534Smckusick char *rh_host; 10022534Smckusick int rh_file; 10122534Smckusick } remotehost[10]; 10222534Smckusick int nremotes = 0; 10322534Smckusick #endif RWHO 10422534Smckusick 10537905Sbostic #include "pathnames.h" 10637905Sbostic 10722534Smckusick struct nlist nl[] = { 108*46661Sbostic { "_boottime" }, 10922534Smckusick #define NL_BOOT 0 11022534Smckusick { "_proc" }, 11122534Smckusick #define NL_PROC 1 11222534Smckusick { "_nproc" }, 11338186Smckusick #define NL_NPROC 2 11422534Smckusick 0 11522534Smckusick }; 11622534Smckusick 11722534Smckusick /* stuff for the kernel */ 11837905Sbostic int kmem; /* file descriptor for _PATH_KMEM */ 11922534Smckusick struct proc *proc, *procNPROC; 12022534Smckusick int nproc; 12122534Smckusick int procadr; 12222534Smckusick double avenrun[3]; /* used for storing load averages */ 12322534Smckusick 12422534Smckusick /* 12522534Smckusick * In order to determine how many people are logged on and who has 12622534Smckusick * logged in or out, we read in the /etc/utmp file. We also keep track of 12722534Smckusick * the previous utmp file. 12822534Smckusick */ 12923748Sedward int ut = -1; /* the file descriptor */ 13022534Smckusick struct utmp *new, *old; 13122534Smckusick char *status; /* per tty status bits, see below */ 13222534Smckusick int nentries; /* number of utmp entries */ 13322534Smckusick /* string lengths for printing */ 13422534Smckusick #define LINESIZE (sizeof old->ut_line) 13522534Smckusick #define NAMESIZE (sizeof old->ut_name) 13622534Smckusick /* 13722534Smckusick * Status codes to say what has happened to a particular entry in utmp. 13822534Smckusick * NOCH means no change, ON means new person logged on, 13922534Smckusick * OFF means person logged off. 14022534Smckusick */ 14122534Smckusick #define NOCH 0 14222534Smckusick #define ON 0x1 14322534Smckusick #define OFF 0x2 14422534Smckusick 14522534Smckusick #ifdef WHO 14622534Smckusick char whofilename[100]; 14722534Smckusick char whofilename2[100]; 14822534Smckusick #endif 14922534Smckusick 15024502Skarels char hostname[MAXHOSTNAMELEN+1]; /* one more for null termination */ 15122534Smckusick char lockfilename[100]; /* if exists, will prevent us from running */ 15222534Smckusick 15322534Smckusick /* flags which determine which info is printed */ 15422534Smckusick int mailcheck = 1; /* m - do biff like checking of mail */ 15522534Smckusick int proccheck = 1; /* p - give information on processes */ 15622534Smckusick int logcheck = 1; /* l - tell who logs in and out */ 15722534Smckusick int hostprint = 0; /* h - print out hostname */ 15822534Smckusick int dateprint = 0; /* h - print out day/date */ 15922534Smckusick int quiet = 0; /* q - hush diagnostic messages */ 16022534Smckusick 16122534Smckusick /* flags which determine how things are printed */ 16222534Smckusick int clr_bet_ref = 0; /* c - clear line between refeshes */ 16322534Smckusick int reverse = 1; /* r - use reverse video */ 16422534Smckusick int shortline = 0; /* s - short (left-justified) if escapes not allowed */ 16522534Smckusick int leftline = 0; /* j - left-justified even if escapes allowed */ 16622534Smckusick 16722534Smckusick /* flags which have terminal do random things */ 16822534Smckusick int beep = 0; /* b - beep every half hour and twice every hour */ 16922534Smckusick int printid = 0; /* i - print pid of this process at startup */ 17022534Smckusick int synch = 1; /* synchronize with clock */ 17122534Smckusick 17222534Smckusick /* select output device (status display or straight output) */ 17322534Smckusick int emacs = 0; /* e - assume status display */ 17422534Smckusick int window = 0; /* w - window mode */ 17522534Smckusick int dbug = 0; /* d - debug */ 17622534Smckusick 17722534Smckusick /* 17822534Smckusick * used to turn off reverse video every REVOFF times 17922534Smckusick * in an attempt to not wear out the phospher. 18022534Smckusick */ 18122534Smckusick #define REVOFF 5 18222534Smckusick int revtime = 1; 18322534Smckusick 18422534Smckusick /* used by mail checker */ 18522534Smckusick off_t mailsize = 0; 18622534Smckusick off_t linebeg = 0; /* place where we last left off reading */ 18722534Smckusick 18822534Smckusick /* things used by the string routines */ 18922534Smckusick int chars; /* number of printable characters */ 19022534Smckusick char *sp; 19122534Smckusick char strarr[512]; /* big enough now? */ 19222534Smckusick /* flags to stringdump() */ 19322534Smckusick char sawmail; /* remember mail was seen to print bells */ 19422534Smckusick char mustclear; /* status line messed up */ 19522534Smckusick 19622534Smckusick /* strings which control status line display */ 19722534Smckusick #ifdef TERMINFO 19822534Smckusick char *rev_out, *rev_end, *arrows; 19922534Smckusick char *tparm(); 20022534Smckusick #else 20122534Smckusick char to_status_line[64]; 20222534Smckusick char from_status_line[64]; 20322534Smckusick char dis_status_line[64]; 20422534Smckusick char clr_eol[64]; 20522534Smckusick char rev_out[20], rev_end[20]; 20622534Smckusick char *arrows, *bell = "\007"; 20722534Smckusick int eslok; /* escapes on status line okay (reverse, cursor addressing) */ 20834586Sbostic int hasws = 0; /* is "ws" explicitly defined? */ 20922534Smckusick int columns; 21022534Smckusick #define tparm(cap, parm) tgoto((cap), 0, (parm)) 21122534Smckusick char *tgoto(); 21222534Smckusick #endif 21322534Smckusick 21422534Smckusick /* to deal with window size changes */ 21522534Smckusick #ifdef SIGWINCH 216*46661Sbostic void sigwinch(); 21722534Smckusick char winchanged; /* window size has changed since last update */ 21822534Smckusick #endif 21922534Smckusick 22022534Smckusick /* random globals */ 22122534Smckusick char *username; 22222534Smckusick char *ourtty; /* keep track of what tty we're on */ 22322534Smckusick struct stat stbuf, mstbuf; /* mstbuf for mail check only */ 22422534Smckusick unsigned delay = DEFDELAY; 22532535Sbostic uid_t uid; 22622534Smckusick double loadavg = 0.0; /* current load average */ 22722534Smckusick int users = 0; 22822534Smckusick 22922534Smckusick char *strcpy1(); 23022534Smckusick char *sysrup(); 23122534Smckusick int outc(); 23222534Smckusick int erroutc(); 23322534Smckusick 234*46661Sbostic main(argc, argv) 235*46661Sbostic int argc; 23622534Smckusick register char **argv; 23722534Smckusick { 23822534Smckusick register char *cp; 23922534Smckusick char *home; 240*46661Sbostic void clearbotl(); 24122534Smckusick 24222534Smckusick gethostname(hostname, sizeof hostname - 1); 24324747Sbloom if ((cp = index(hostname, '.')) != NULL) 24424747Sbloom *cp = '\0'; 245*46661Sbostic (void)setvbuf(stdout, (char *)NULL, _IOFBF, 0); 24622534Smckusick 24722534Smckusick for (argv++; *argv != 0; argv++) 24822534Smckusick switch (**argv) { 24922534Smckusick case '-': 25022534Smckusick for (cp = *argv + 1; *cp; cp++) { 25122534Smckusick switch(*cp) { 25222534Smckusick case 'r' : /* turn off reverse video */ 25322534Smckusick reverse = 0; 25422534Smckusick break; 25522534Smckusick case 'c': 25622534Smckusick clr_bet_ref = 1; 25722534Smckusick break; 25822534Smckusick case 'h': 25922534Smckusick hostprint = 1; 26022534Smckusick break; 26122534Smckusick case 'D': 26222534Smckusick dateprint = 1; 26322534Smckusick break; 26422534Smckusick #ifdef RWHO 26522534Smckusick case 'H': 26622534Smckusick if (argv[1] == 0) 26722534Smckusick break; 26822534Smckusick argv++; 26922534Smckusick if (strcmp(hostname, *argv) && 27022534Smckusick strcmp(&hostname[sizeof NETPREFIX - 1], *argv)) 27122534Smckusick remotehost[nremotes++].rh_host = *argv; 27222534Smckusick break; 27322534Smckusick #endif RWHO 27422534Smckusick case 'm': 27522534Smckusick mailcheck = 0; 27622534Smckusick break; 27722534Smckusick case 'p': 27822534Smckusick proccheck = 0; 27922534Smckusick break; 28022534Smckusick case 'l': 28122534Smckusick logcheck = 0; 28222534Smckusick break; 28322534Smckusick case 'b': 28422534Smckusick beep = 1; 28522534Smckusick break; 28622534Smckusick case 'i': 28722534Smckusick printid = 1; 28822534Smckusick break; 28922534Smckusick case 'w': 29022534Smckusick window = 1; 29122534Smckusick break; 29222534Smckusick case 'e': 29322534Smckusick emacs = 1; 29422534Smckusick break; 29522534Smckusick case 'd': 29622534Smckusick dbug = 1; 29722534Smckusick break; 29822534Smckusick case 'q': 29922534Smckusick quiet = 1; 30022534Smckusick break; 30122534Smckusick case 's': 30222534Smckusick shortline = 1; 30322534Smckusick break; 30422534Smckusick case 'j': 30522534Smckusick leftline = 1; 30622534Smckusick break; 30722534Smckusick default: 30822534Smckusick fprintf(stderr, 30922534Smckusick "sysline: bad flag: %c\n", *cp); 31022534Smckusick } 31122534Smckusick } 31222534Smckusick break; 31322534Smckusick case '+': 31422534Smckusick delay = atoi(*argv + 1); 31522534Smckusick if (delay < 10) 31622534Smckusick delay = 10; 31722534Smckusick else if (delay > 500) 31822534Smckusick delay = 500; 31922534Smckusick synch = 0; /* no more sync */ 32022534Smckusick break; 32122534Smckusick default: 32222534Smckusick fprintf(stderr, "sysline: illegal argument %s\n", 32322534Smckusick argv[0]); 32422534Smckusick } 32522534Smckusick if (emacs) { 32622534Smckusick reverse = 0; 32722534Smckusick columns = 79; 32822534Smckusick } else /* if not to emacs window, initialize terminal dependent info */ 32922534Smckusick initterm(); 33022534Smckusick #ifdef SIGWINCH 33122534Smckusick /* 33222534Smckusick * When the window size changes and we are the foreground 33322534Smckusick * process (true if -w), we get this signal. 33422534Smckusick */ 33522534Smckusick signal(SIGWINCH, sigwinch); 33622534Smckusick #endif 33722534Smckusick getwinsize(); /* get window size from ioctl */ 33822534Smckusick 33922534Smckusick /* immediately fork and let the parent die if not emacs mode */ 34022534Smckusick if (!emacs && !window && !dbug) { 34122534Smckusick if (fork()) 34222534Smckusick exit(0); 34322534Smckusick /* pgrp should take care of things, but ignore them anyway */ 34422534Smckusick signal(SIGINT, SIG_IGN); 34522534Smckusick signal(SIGQUIT, SIG_IGN); 34622534Smckusick signal(SIGTTOU, SIG_IGN); 34722534Smckusick } 34822534Smckusick /* 34922534Smckusick * When we logoff, init will do a "vhangup()" on this 35022534Smckusick * tty which turns off I/O access and sends a SIGHUP 35122534Smckusick * signal. We catch this and thereby clear the status 35222534Smckusick * display. Note that a bug in 4.1bsd caused the SIGHUP 35322534Smckusick * signal to be sent to the wrong process, so you had to 35422534Smckusick * `kill -HUP' yourself in your .logout file. 35522534Smckusick * Do the same thing for SIGTERM, which is the default kill 35622534Smckusick * signal. 35722534Smckusick */ 35822534Smckusick signal(SIGHUP, clearbotl); 35922534Smckusick signal(SIGTERM, clearbotl); 36022534Smckusick /* 36122534Smckusick * This is so kill -ALRM to force update won't screw us up.. 36222534Smckusick */ 36322534Smckusick signal(SIGALRM, SIG_IGN); 36422534Smckusick 36522534Smckusick uid = getuid(); 36622534Smckusick ourtty = ttyname(2); /* remember what tty we are on */ 36722534Smckusick if (printid) { 36822534Smckusick printf("%d\n", getpid()); 36922534Smckusick fflush(stdout); 37022534Smckusick } 37122534Smckusick dup2(2, 1); 37222534Smckusick 37322534Smckusick if ((home = getenv("HOME")) == 0) 37422534Smckusick home = ""; 37522534Smckusick strcpy1(strcpy1(whofilename, home), "/.who"); 37622534Smckusick strcpy1(strcpy1(whofilename2, home), "/.sysline"); 37722534Smckusick strcpy1(strcpy1(lockfilename, home), "/.syslinelock"); 37822534Smckusick 37937905Sbostic if ((kmem = open(_PATH_KMEM,0)) < 0) { 38037905Sbostic fprintf(stderr, "Can't open %s\n", _PATH_KMEM); 38122534Smckusick exit(1); 38222534Smckusick } 38322534Smckusick readnamelist(); 38422534Smckusick if (proccheck) 38522534Smckusick initprocread(); 38622534Smckusick if (mailcheck) 38722534Smckusick if ((username = getenv("USER")) == 0) 38822534Smckusick mailcheck = 0; 38922534Smckusick else { 39043861Sbostic chdir(_PATH_MAILDIR); 39122534Smckusick if (stat(username, &mstbuf) >= 0) 39222534Smckusick mailsize = mstbuf.st_size; 39322534Smckusick else 39422534Smckusick mailsize = 0; 39522534Smckusick } 39622534Smckusick 39722534Smckusick while (emacs || window || isloggedin()) 39822534Smckusick if (access(lockfilename, 0) >= 0) 39922534Smckusick sleep(60); 40022534Smckusick else { 40122534Smckusick prtinfo(); 40222534Smckusick sleep(delay); 40322534Smckusick if (clr_bet_ref) { 40422534Smckusick tputs(dis_status_line, 1, outc); 40522534Smckusick fflush(stdout); 40622534Smckusick sleep(5); 40722534Smckusick } 40822534Smckusick revtime = (1 + revtime) % REVOFF; 40922534Smckusick } 41022534Smckusick clearbotl(); 41122534Smckusick /*NOTREACHED*/ 41222534Smckusick } 41322534Smckusick 41422534Smckusick isloggedin() 41522534Smckusick { 41622534Smckusick /* 41722534Smckusick * you can tell if a person has logged out if the owner of 41822534Smckusick * the tty has changed 41922534Smckusick */ 42022534Smckusick struct stat statbuf; 42122534Smckusick 42222534Smckusick return fstat(2, &statbuf) == 0 && statbuf.st_uid == uid; 42322534Smckusick } 42422534Smckusick 42522534Smckusick readnamelist() 42622534Smckusick { 42722534Smckusick time_t bootime, clock, nintv, time(); 42822534Smckusick 42937905Sbostic nlist(_PATH_UNIX, nl); 43022534Smckusick if (nl[0].n_value == 0) { 43122534Smckusick if (!quiet) 43222534Smckusick fprintf(stderr, "No namelist\n"); 43322534Smckusick return; 43422534Smckusick } 43522534Smckusick lseek(kmem, (long)nl[NL_BOOT].n_value, 0); 43622534Smckusick read(kmem, &bootime, sizeof(bootime)); 43722534Smckusick (void) time(&clock); 43822534Smckusick nintv = clock - bootime; 43922534Smckusick if (nintv <= 0L || nintv > 60L*60L*24L*365L) { 44022534Smckusick if (!quiet) 44122534Smckusick fprintf(stderr, 44222534Smckusick "Time makes no sense... namelist must be wrong\n"); 44338186Smckusick nl[NL_PROC].n_value = 0; 44422534Smckusick } 44522534Smckusick } 44622534Smckusick 44723748Sedward readutmp(nflag) 44823748Sedward char nflag; 44922534Smckusick { 45023748Sedward static time_t lastmod; /* initially zero */ 45123748Sedward static off_t utmpsize; /* ditto */ 45222534Smckusick struct stat st; 45322534Smckusick 45437905Sbostic if (ut < 0 && (ut = open(_PATH_UTMP, 0)) < 0) { 45537905Sbostic fprintf(stderr, "sysline: Can't open %s.\n", _PATH_UTMP); 45622534Smckusick exit(1); 45722534Smckusick } 45823748Sedward if (fstat(ut, &st) < 0 || st.st_mtime == lastmod) 45922534Smckusick return 0; 46022534Smckusick lastmod = st.st_mtime; 46123748Sedward if (utmpsize != st.st_size) { 46223748Sedward utmpsize = st.st_size; 46323748Sedward nentries = utmpsize / sizeof (struct utmp); 46423748Sedward if (old == 0) { 46523748Sedward old = (struct utmp *)calloc(utmpsize, 1); 46623748Sedward new = (struct utmp *)calloc(utmpsize, 1); 46723748Sedward } else { 46823748Sedward old = (struct utmp *)realloc((char *)old, utmpsize); 46923748Sedward new = (struct utmp *)realloc((char *)new, utmpsize); 47023748Sedward free(status); 47123748Sedward } 47223748Sedward status = malloc(nentries * sizeof *status); 47323748Sedward if (old == 0 || new == 0 || status == 0) { 47423748Sedward fprintf(stderr, "sysline: Out of memory.\n"); 47523748Sedward exit(1); 47623748Sedward } 47723748Sedward } 47822534Smckusick lseek(ut, 0L, 0); 47923748Sedward (void) read(ut, (char *) (nflag ? new : old), utmpsize); 48022534Smckusick return 1; 48122534Smckusick } 48222534Smckusick 48322534Smckusick /* 48422534Smckusick * read in the process table locations and sizes, and allocate space 48522534Smckusick * for storing the process table. This is done only once. 48622534Smckusick */ 48722534Smckusick initprocread() 48822534Smckusick { 48922534Smckusick 49022534Smckusick if (nl[NL_PROC].n_value == 0) 49122534Smckusick return; 49222534Smckusick lseek(kmem, (long)nl[NL_PROC].n_value, 0); 49322534Smckusick read(kmem, &procadr, sizeof procadr); 49422534Smckusick lseek(kmem, (long)nl[NL_NPROC].n_value, 0); 49522534Smckusick read(kmem, &nproc, sizeof nproc); 49622534Smckusick if ((proc = (struct proc *) calloc(nproc, sizeof (struct proc))) == 0) { 49722534Smckusick fprintf(stderr, "Out of memory.\n"); 49822534Smckusick exit(1); 49922534Smckusick } 50022534Smckusick procNPROC = proc + nproc; 50122534Smckusick } 50222534Smckusick 50322534Smckusick /* 50422534Smckusick * read in the process table. This assumes that initprocread has alread been 50522534Smckusick * called to set up storage. 50622534Smckusick */ 50722534Smckusick readproctab() 50822534Smckusick { 50922534Smckusick 51022534Smckusick if (nl[NL_PROC].n_value == 0) 51122534Smckusick return (0); 51222534Smckusick lseek(kmem, (long)procadr, 0); 51322534Smckusick read(kmem, (char *)proc, nproc * sizeof (struct proc)); 51422534Smckusick return (1); 51522534Smckusick } 51622534Smckusick 51722534Smckusick prtinfo() 51822534Smckusick { 51922534Smckusick int on, off; 52022534Smckusick register i; 52122534Smckusick char fullprocess; 52222534Smckusick 52322534Smckusick stringinit(); 52422534Smckusick #ifdef SIGWINCH 52522534Smckusick if (winchanged) { 52622534Smckusick winchanged = 0; 52722534Smckusick getwinsize(); 52822534Smckusick mustclear = 1; 52922534Smckusick } 53022534Smckusick #endif 53122534Smckusick #ifdef WHO 53222534Smckusick /* check for file named .who in the home directory */ 53322534Smckusick whocheck(); 53422534Smckusick #endif 53522534Smckusick timeprint(); 53622534Smckusick /* 53722534Smckusick * if mail is seen, don't print rest of info, just the mail 53822534Smckusick * reverse new and old so that next time we run, we won't lose log 53922534Smckusick * in and out information 54022534Smckusick */ 54122534Smckusick if (mailcheck && (sawmail = mailseen())) 54222534Smckusick goto bottom; 54322534Smckusick #ifdef RWHO 54422534Smckusick for (i = 0; i < nremotes; i++) { 54522534Smckusick char *tmp; 54622534Smckusick 54722534Smckusick stringspace(); 54822534Smckusick tmp = sysrup(remotehost + i); 54922534Smckusick stringcat(tmp, strlen(tmp)); 55022534Smckusick } 55122534Smckusick #endif 55222534Smckusick /* 55322534Smckusick * print hostname info if requested 55422534Smckusick */ 55522534Smckusick if (hostprint) { 55622534Smckusick stringspace(); 55722534Smckusick stringcat(hostname, -1); 55822534Smckusick } 55922534Smckusick /* 56022534Smckusick * print load average and difference between current load average 56122534Smckusick * and the load average 5 minutes ago 56222534Smckusick */ 56338186Smckusick if (getloadavg(avenrun, 3) > 0) { 56422534Smckusick double diff; 56522534Smckusick 56622534Smckusick stringspace(); 56738186Smckusick 56822534Smckusick if ((diff = avenrun[0] - avenrun[1]) < 0.0) 56922534Smckusick stringprt("%.1f %.1f", avenrun[0], diff); 57022534Smckusick else 57122534Smckusick stringprt("%.1f +%.1f", avenrun[0], diff); 57222534Smckusick loadavg = avenrun[0]; /* remember load average */ 57322534Smckusick } 57422534Smckusick /* 57522534Smckusick * print log on and off information 57622534Smckusick */ 57722534Smckusick stringspace(); 57822534Smckusick fullprocess = 1; 57922534Smckusick #ifdef MAXLOAD 58022534Smckusick if (loadavg > MAXLOAD) 58122534Smckusick fullprocess = 0; /* too loaded to run */ 58222534Smckusick #endif 58322534Smckusick /* 58422534Smckusick * Read utmp file (logged in data) only if we are doing a full 58522534Smckusick * process, or if this is the first time and we are calculating 58622534Smckusick * the number of users. 58722534Smckusick */ 58822534Smckusick on = off = 0; 58922534Smckusick if (users == 0) { /* first time */ 59023748Sedward if (readutmp(0)) 59122534Smckusick for (i = 0; i < nentries; i++) 59222534Smckusick if (old[i].ut_name[0]) 59322534Smckusick users++; 59423748Sedward } else if (fullprocess && readutmp(1)) { 59522534Smckusick struct utmp *tmp; 59622534Smckusick 59722534Smckusick users = 0; 59822534Smckusick for (i = 0; i < nentries; i++) { 59922534Smckusick if (strncmp(old[i].ut_name, 60022534Smckusick new[i].ut_name, NAMESIZE) == 0) 60122534Smckusick status[i] = NOCH; 60222534Smckusick else if (old[i].ut_name[0] == '\0') { 60322534Smckusick status[i] = ON; 60422534Smckusick on++; 60522534Smckusick } else if (new[i].ut_name[0] == '\0') { 60622534Smckusick status[i] = OFF; 60722534Smckusick off++; 60822534Smckusick } else { 60922534Smckusick status[i] = ON | OFF; 61022534Smckusick on++; 61122534Smckusick off++; 61222534Smckusick } 61322534Smckusick if (new[i].ut_name[0]) 61422534Smckusick users++; 61522534Smckusick } 61622534Smckusick tmp = new; 61722534Smckusick new = old; 61822534Smckusick old = tmp; 61922534Smckusick } 62022534Smckusick /* 62122534Smckusick * Print: 62222534Smckusick * 1. number of users 62322534Smckusick * 2. a * for unread mail 62422534Smckusick * 3. a - if load is too high 62522534Smckusick * 4. number of processes running and stopped 62622534Smckusick */ 62722534Smckusick stringprt("%du", users); 62822534Smckusick if (mailsize > 0 && mstbuf.st_mtime >= mstbuf.st_atime) 62922534Smckusick stringcat("*", -1); 63022534Smckusick if (!fullprocess && (proccheck || logcheck)) 63122534Smckusick stringcat("-", -1); 63222534Smckusick if (fullprocess && proccheck && readproctab()) { 63322534Smckusick register struct proc *p; 63422534Smckusick int procrun, procstop; 63522534Smckusick 63622534Smckusick /* 63722534Smckusick * We are only interested in processes which have the same 63822534Smckusick * uid as us, and whose parent process id is not 1. 63922534Smckusick */ 64022534Smckusick procrun = procstop = 0; 64122534Smckusick for (p = proc; p < procNPROC; p++) { 64222534Smckusick if (p->p_stat == 0 || p->p_pgrp == 0 || 64322534Smckusick p->p_uid != uid || p->p_ppid == 1) 64422534Smckusick continue; 64522534Smckusick switch (p->p_stat) { 64622534Smckusick case SSTOP: 64722534Smckusick procstop++; 64822534Smckusick break; 64922534Smckusick case SSLEEP: 65022534Smckusick /* 65122534Smckusick * Sleep can mean waiting for a signal or just 65222534Smckusick * in a disk or page wait queue ready to run. 65322534Smckusick * We can tell if it is the later by the pri 65422534Smckusick * being negative. 65522534Smckusick */ 65622534Smckusick if (p->p_pri < PZERO) 65722534Smckusick procrun++; 65822534Smckusick break; 65922534Smckusick case SWAIT: 66022534Smckusick case SRUN: 66122534Smckusick case SIDL: 66222534Smckusick procrun++; 66322534Smckusick } 66422534Smckusick } 66522534Smckusick if (procrun > 0 || procstop > 0) { 66622534Smckusick stringspace(); 66722534Smckusick if (procrun > 0 && procstop > 0) 66822534Smckusick stringprt("%dr %ds", procrun, procstop); 66922534Smckusick else if (procrun > 0) 67022534Smckusick stringprt("%dr", procrun); 67122534Smckusick else 67222534Smckusick stringprt("%ds", procstop); 67322534Smckusick } 67422534Smckusick } 67522534Smckusick /* 67622534Smckusick * If anyone has logged on or off, and we are interested in it, 67722534Smckusick * print it out. 67822534Smckusick */ 67922534Smckusick if (logcheck) { 68022534Smckusick /* old and new have already been swapped */ 68122534Smckusick if (on) { 68222534Smckusick stringspace(); 68322534Smckusick stringcat("on:", -1); 68422534Smckusick for (i = 0; i < nentries; i++) 68522534Smckusick if (status[i] & ON) { 68622534Smckusick stringprt(" %.8s", old[i].ut_name); 68722534Smckusick ttyprint(old[i].ut_line); 68822534Smckusick } 68922534Smckusick } 69022534Smckusick if (off) { 69122534Smckusick stringspace(); 69222534Smckusick stringcat("off:", -1); 69322534Smckusick for (i = 0; i < nentries; i++) 69422534Smckusick if (status[i] & OFF) { 69522534Smckusick stringprt(" %.8s", new[i].ut_name); 69622534Smckusick ttyprint(new[i].ut_line); 69722534Smckusick } 69822534Smckusick } 69922534Smckusick } 70022534Smckusick bottom: 70122534Smckusick /* dump out what we know */ 70222534Smckusick stringdump(); 70322534Smckusick } 70422534Smckusick 70522534Smckusick timeprint() 70622534Smckusick { 70722534Smckusick long curtime; 70822534Smckusick struct tm *tp, *localtime(); 70922534Smckusick static int beepable = 1; 71022534Smckusick 71122534Smckusick /* always print time */ 71222534Smckusick time(&curtime); 71322534Smckusick tp = localtime(&curtime); 71422534Smckusick if (dateprint) 71522534Smckusick stringprt("%.11s", ctime(&curtime)); 71622534Smckusick stringprt("%d:%02d", tp->tm_hour > 12 ? tp->tm_hour - 12 : 71722534Smckusick (tp->tm_hour == 0 ? 12 : tp->tm_hour), tp->tm_min); 71822534Smckusick if (synch) /* sync with clock */ 71922534Smckusick delay = 60 - tp->tm_sec; 72022534Smckusick /* 72122534Smckusick * Beepable is used to insure that we get at most one set of beeps 72222534Smckusick * every half hour. 72322534Smckusick */ 72422534Smckusick if (beep) 72522534Smckusick if (beepable) { 72622534Smckusick if (tp->tm_min == 30) { 72722534Smckusick tputs(bell, 1, outc); 72822534Smckusick fflush(stdout); 72922534Smckusick beepable = 0; 73022534Smckusick } else if (tp->tm_min == 0) { 73122534Smckusick tputs(bell, 1, outc); 73222534Smckusick fflush(stdout); 73322534Smckusick sleep(2); 73422534Smckusick tputs(bell, 1, outc); 73522534Smckusick fflush(stdout); 73622534Smckusick beepable = 0; 73722534Smckusick } 73822534Smckusick } else 73922534Smckusick if (tp->tm_min != 0 && tp->tm_min != 30) 74022534Smckusick beepable = 1; 74122534Smckusick } 74222534Smckusick 74322534Smckusick /* 74422534Smckusick * whocheck -- check for file named .who and print it on the who line first 74522534Smckusick */ 74622534Smckusick whocheck() 74722534Smckusick { 74822534Smckusick int chss; 74922534Smckusick register char *p; 75022534Smckusick char buff[81]; 75122534Smckusick int whofile; 75222534Smckusick 75322534Smckusick if ((whofile = open(whofilename, 0)) < 0 && 75422534Smckusick (whofile = open(whofilename2, 0)) < 0) 75522534Smckusick return; 75622534Smckusick chss = read(whofile, buff, sizeof buff - 1); 75722534Smckusick close(whofile); 75822534Smckusick if (chss <= 0) 75922534Smckusick return; 76022534Smckusick buff[chss] = '\0'; 76122534Smckusick /* 76222534Smckusick * Remove all line feeds, and replace by spaces if they are within 76322534Smckusick * the message, else replace them by nulls. 76422534Smckusick */ 76522534Smckusick for (p = buff; *p;) 76622534Smckusick if (*p == '\n') 76722534Smckusick if (p[1]) 76822534Smckusick *p++ = ' '; 76922534Smckusick else 77022534Smckusick *p = '\0'; 77122534Smckusick else 77222534Smckusick p++; 77322534Smckusick stringcat(buff, p - buff); 77422534Smckusick stringspace(); 77522534Smckusick } 77622534Smckusick 77722534Smckusick /* 77822534Smckusick * ttyprint -- given the name of a tty, print in the string buffer its 77922534Smckusick * short name surrounded by parenthesis. 78022534Smckusick * ttyxx is printed as (xx) 78122534Smckusick * console is printed as (cty) 78222534Smckusick */ 78322534Smckusick ttyprint(name) 78422534Smckusick char *name; 78522534Smckusick { 78622534Smckusick char buff[11]; 78722534Smckusick 78822534Smckusick if (strncmp(name, "tty", 3) == 0) 78922534Smckusick stringprt("(%.*s)", LINESIZE - 3, name + 3); 79022534Smckusick else if (strcmp(name, "console") == 0) 79122534Smckusick stringcat("(cty)", -1); 79222534Smckusick else 79322534Smckusick stringprt("(%.*s)", LINESIZE, name); 79422534Smckusick } 79522534Smckusick 79622534Smckusick /* 79722534Smckusick * mail checking function 79822534Smckusick * returns 0 if no mail seen 79922534Smckusick */ 80022534Smckusick mailseen() 80122534Smckusick { 80222534Smckusick FILE *mfd; 80322534Smckusick register n; 80422534Smckusick register char *cp; 80522534Smckusick char lbuf[100], sendbuf[100], *bufend; 80622534Smckusick char seenspace; 80722534Smckusick int retval = 0; 80822534Smckusick 80922534Smckusick if (stat(username, &mstbuf) < 0) { 81022534Smckusick mailsize = 0; 81122534Smckusick return 0; 81222534Smckusick } 81322534Smckusick if (mstbuf.st_size <= mailsize || (mfd = fopen(username,"r")) == NULL) { 81422534Smckusick mailsize = mstbuf.st_size; 81522534Smckusick return 0; 81622534Smckusick } 81722534Smckusick fseek(mfd, mailsize, 0); 81822534Smckusick while ((n = readline(mfd, lbuf, sizeof lbuf)) >= 0 && 81922534Smckusick strncmp(lbuf, "From ", 5) != 0) 82022534Smckusick ; 82122534Smckusick if (n < 0) { 82234586Sbostic stringcat("Mail has just arrived", -1); 82322534Smckusick goto out; 82422534Smckusick } 82522534Smckusick retval = 1; 82622534Smckusick /* 82722534Smckusick * Found a From line, get second word, which is the sender, 82822534Smckusick * and print it. 82922534Smckusick */ 83022534Smckusick for (cp = lbuf + 5; *cp && *cp != ' '; cp++) /* skip to blank */ 83122534Smckusick ; 83222534Smckusick *cp = '\0'; /* terminate name */ 83322534Smckusick stringspace(); 83422534Smckusick stringprt("Mail from %s ", lbuf + 5); 83522534Smckusick /* 83622534Smckusick * Print subject, and skip over header. 83722534Smckusick */ 83822534Smckusick while ((n = readline(mfd, lbuf, sizeof lbuf)) > 0) 83922534Smckusick if (strncmp(lbuf, "Subject:", 8) == 0) 84022534Smckusick stringprt("on %s ", lbuf + 9); 84122534Smckusick if (!emacs) 84222534Smckusick stringcat(arrows, 2); 84322534Smckusick else 84422534Smckusick stringcat(": ", 2); 84522534Smckusick if (n < 0) /* already at eof */ 84622534Smckusick goto out; 84722534Smckusick /* 84822534Smckusick * Print as much of the letter as we can. 84922534Smckusick */ 85022534Smckusick cp = sendbuf; 85122534Smckusick if ((n = columns - chars) > sizeof sendbuf - 1) 85222534Smckusick n = sizeof sendbuf - 1; 85322534Smckusick bufend = cp + n; 85422534Smckusick seenspace = 0; 85522534Smckusick while ((n = readline(mfd, lbuf, sizeof lbuf)) >= 0) { 85622534Smckusick register char *rp; 85722534Smckusick 85822534Smckusick if (strncmp(lbuf, "From ", 5) == 0) 85922534Smckusick break; 86022534Smckusick if (cp >= bufend) 86122534Smckusick continue; 86222534Smckusick if (!seenspace) { 86322534Smckusick *cp++ = ' '; /* space before lines */ 86422534Smckusick seenspace = 1; 86522534Smckusick } 86622534Smckusick rp = lbuf; 86722534Smckusick while (*rp && cp < bufend) 86822534Smckusick if (isspace(*rp)) { 86922534Smckusick if (!seenspace) { 87022534Smckusick *cp++ = ' '; 87122534Smckusick seenspace = 1; 87222534Smckusick } 87322534Smckusick rp++; 87422534Smckusick } else { 87522534Smckusick *cp++ = *rp++; 87622534Smckusick seenspace = 0; 87722534Smckusick } 87822534Smckusick } 87922534Smckusick *cp = 0; 88022534Smckusick stringcat(sendbuf, -1); 88122534Smckusick /* 88222534Smckusick * Want to update write time so a star will 88322534Smckusick * appear after the number of users until the 88422534Smckusick * user reads his mail. 88522534Smckusick */ 88622534Smckusick out: 88722534Smckusick mailsize = linebeg; 88822534Smckusick fclose(mfd); 88922534Smckusick touch(username); 89022534Smckusick return retval; 89122534Smckusick } 89222534Smckusick 89322534Smckusick /* 89422534Smckusick * readline -- read a line from fp and store it in buf. 89522534Smckusick * return the number of characters read. 89622534Smckusick */ 89722534Smckusick readline(fp, buf, n) 89822534Smckusick register FILE *fp; 89922534Smckusick char *buf; 90022534Smckusick register n; 90122534Smckusick { 90222534Smckusick register c; 90322534Smckusick register char *cp = buf; 90422534Smckusick 90522534Smckusick linebeg = ftell(fp); /* remember loc where line begins */ 90622534Smckusick cp = buf; 90722534Smckusick while (--n > 0 && (c = getc(fp)) != EOF && c != '\n') 90822534Smckusick *cp++ = c; 90922534Smckusick *cp = 0; 91022534Smckusick if (c == EOF && cp - buf == 0) 91122534Smckusick return -1; 91222534Smckusick return cp - buf; 91322534Smckusick } 91422534Smckusick 91522534Smckusick 91622534Smckusick /* 91722534Smckusick * string hacking functions 91822534Smckusick */ 91922534Smckusick 92022534Smckusick stringinit() 92122534Smckusick { 92222534Smckusick sp = strarr; 92322534Smckusick chars = 0; 92422534Smckusick } 92522534Smckusick 92622534Smckusick /*VARARGS1*/ 927*46661Sbostic stringprt(fmt) 928*46661Sbostic char *fmt; 92922534Smckusick { 930*46661Sbostic va_list ap; 93122534Smckusick char tempbuf[150]; 93222534Smckusick 933*46661Sbostic va_start(ap, fmt); 934*46661Sbostic (void)vsnprintf(tempbuf, sizeof(tempbuf), fmt, ap); 935*46661Sbostic va_end(ap); 93632501Sbostic stringcat(tempbuf, -1); 93722534Smckusick } 93822534Smckusick 93922534Smckusick stringdump() 94022534Smckusick { 94122534Smckusick char bigbuf[sizeof strarr + 200]; 94222534Smckusick register char *bp = bigbuf; 94322534Smckusick register int i; 94422534Smckusick 94522534Smckusick if (!emacs) { 94622534Smckusick if (sawmail) 94722534Smckusick bp = strcpy1(bp, bell); 94822534Smckusick if (eslok) 94922534Smckusick bp = strcpy1(bp, tparm(to_status_line, 95022534Smckusick leftline ? 0 : columns - chars)); 95122534Smckusick else { 95222534Smckusick bp = strcpy1(bp, to_status_line); 95322534Smckusick if (!shortline && !leftline) 95422534Smckusick for (i = columns - chars; --i >= 0;) 95522534Smckusick *bp++ = ' '; 95622534Smckusick } 95722534Smckusick if (reverse && revtime != 0) 95822534Smckusick bp = strcpy1(bp, rev_out); 95922534Smckusick } 96022534Smckusick *sp = 0; 96122534Smckusick bp = strcpy1(bp, strarr); 96222534Smckusick if (!emacs) { 96322534Smckusick if (reverse) 96422534Smckusick bp = strcpy1(bp, rev_end); 96522534Smckusick bp = strcpy1(bp, from_status_line); 96622534Smckusick if (sawmail) 96722534Smckusick bp = strcpy1(strcpy1(bp, bell), bell); 96822534Smckusick *bp = 0; 96922534Smckusick tputs(bigbuf, 1, outc); 97022534Smckusick if (mustclear) { 97122534Smckusick mustclear = 0; 97222534Smckusick tputs(clr_eol, 1, outc); 97322534Smckusick } 97422534Smckusick if (dbug) 97522534Smckusick putchar('\n'); 97622534Smckusick fflush(stdout); 97722534Smckusick } else 97822534Smckusick write(2, bigbuf, bp - bigbuf); 97922534Smckusick } 98022534Smckusick 98122534Smckusick stringspace() 98222534Smckusick { 98322534Smckusick if (reverse && revtime != 0) { 98422534Smckusick #ifdef TERMINFO 98522534Smckusick stringcat(rev_end, 98622534Smckusick magic_cookie_glitch <= 0 ? 0 : magic_cookie_glitch); 98722534Smckusick stringcat(" ", 1); 98822534Smckusick stringcat(rev_out, 98922534Smckusick magic_cookie_glitch <= 0 ? 0 : magic_cookie_glitch); 99022534Smckusick #else 99122534Smckusick stringcat(rev_end, 0); 99222534Smckusick stringcat(" ", 1); 99322534Smckusick stringcat(rev_out, 0); 99422534Smckusick #endif TERMINFO 99522534Smckusick } else 99622534Smckusick stringcat(" ", 1); 99722534Smckusick } 99822534Smckusick 99922534Smckusick /* 100022534Smckusick * stringcat :: concatenate the characters in string str to the list we are 100122534Smckusick * building to send out. 100222534Smckusick * str - the string to print. may contain funny (terminal control) chars. 100322534Smckusick * n - the number of printable characters in the string 100422534Smckusick * or if -1 then str is all printable so we can truncate it, 100522534Smckusick * otherwise don't print only half a string. 100622534Smckusick */ 100722534Smckusick stringcat(str, n) 100822534Smckusick register char *str; 100922534Smckusick register n; 101022534Smckusick { 101122534Smckusick register char *p = sp; 101222534Smckusick 101322534Smckusick if (n < 0) { /* truncate */ 101422534Smckusick n = columns - chars; 101522534Smckusick while ((*p++ = *str++) && --n >= 0) 101622534Smckusick ; 101722534Smckusick p--; 101822534Smckusick chars += p - sp; 101922534Smckusick sp = p; 102022534Smckusick } else if (chars + n <= columns) { /* don't truncate */ 102122534Smckusick while (*p++ = *str++) 102222534Smckusick ; 102322534Smckusick chars += n; 102422534Smckusick sp = p - 1; 102522534Smckusick } 102622534Smckusick } 102722534Smckusick 102822534Smckusick /* 102922534Smckusick * touch :: update the modify time of a file. 103022534Smckusick */ 103122534Smckusick touch(name) 103222534Smckusick char *name; /* name of file */ 103322534Smckusick { 103422534Smckusick register fd; 103522534Smckusick char buf; 103622534Smckusick 103722534Smckusick if ((fd = open(name, 2)) >= 0) { 103822534Smckusick read(fd, &buf, 1); /* get first byte */ 103922534Smckusick lseek(fd, 0L, 0); /* go to beginning */ 104022534Smckusick write(fd, &buf, 1); /* and rewrite first byte */ 104122534Smckusick close(fd); 104222534Smckusick } 104322534Smckusick } 104422534Smckusick 104522534Smckusick 104622534Smckusick /* 104722534Smckusick * clearbotl :: clear bottom line. 104822534Smckusick * called when process quits or is killed. 104922534Smckusick * it clears the bottom line of the terminal. 105022534Smckusick */ 105122534Smckusick clearbotl() 105222534Smckusick { 105322534Smckusick register int fd; 1054*46661Sbostic void sigexit(); 105522534Smckusick 1056*46661Sbostic signal(SIGALRM, sigexit); 105722534Smckusick alarm(30); /* if can't open in 30 secs, just die */ 105822534Smckusick if (!emacs && (fd = open(ourtty, 1)) >= 0) { 105922534Smckusick write(fd, dis_status_line, strlen(dis_status_line)); 106022534Smckusick close(fd); 106122534Smckusick } 106222534Smckusick #ifdef PROF 106337905Sbostic if (chdir(_PATH_SYSLINE) < 0) 106437905Sbostic (void) chdir(_PATH_TMP); 106522534Smckusick #endif 106622534Smckusick exit(0); 106722534Smckusick } 106822534Smckusick 106922534Smckusick #ifdef TERMINFO 107022534Smckusick initterm() 107122534Smckusick { 107222534Smckusick static char standbuf[40]; 107322534Smckusick 107422534Smckusick setupterm(0, 1, 0); 107522534Smckusick if (!window && !has_status_line) { 107622534Smckusick /* not an appropriate terminal */ 107722534Smckusick if (!quiet) 107822534Smckusick fprintf(stderr, "sysline: no status capability for %s\n", 107922534Smckusick getenv("TERM")); 108022534Smckusick exit(1); 108122534Smckusick } 108222534Smckusick if (window || status_line_esc_ok) { 108322534Smckusick if (set_attributes) { 108422534Smckusick /* reverse video mode */ 108522534Smckusick strcpy(standbuf, 108622534Smckusick tparm(set_attributes,0,0,1,0,0,0,0,0,0)); 108722534Smckusick rev_out = standbuf; 108822534Smckusick rev_end = exit_attribute_mode; 108922534Smckusick } else if (enter_standout_mode && exit_standout_mode) { 109022534Smckusick rev_out = enter_standout_mode; 109122534Smckusick rev_end = exit_standout_mode; 109222534Smckusick } else 109322534Smckusick rev_out = rev_end = ""; 109422534Smckusick } else 109522534Smckusick rev_out = rev_end = ""; 109622534Smckusick columns--; /* avoid cursor wraparound */ 109722534Smckusick } 109822534Smckusick 109922534Smckusick #else /* TERMCAP */ 110022534Smckusick 110122534Smckusick initterm() 110222534Smckusick { 110322534Smckusick char *term, *cp; 110422534Smckusick static char tbuf[1024]; 110522534Smckusick char is2[40]; 110622534Smckusick extern char *UP; 110722534Smckusick 110822534Smckusick if ((term = getenv("TERM")) == NULL) { 110922534Smckusick if (!quiet) 111022534Smckusick fprintf(stderr, 111122534Smckusick "sysline: No TERM variable in enviroment\n"); 111222534Smckusick exit(1); 111322534Smckusick } 111422534Smckusick if (tgetent(tbuf, term) <= 0) { 111522534Smckusick if (!quiet) 111622534Smckusick fprintf(stderr, 111722534Smckusick "sysline: Unknown terminal type: %s\n", term); 111822534Smckusick exit(1); 111922534Smckusick } 112022534Smckusick if (!window && tgetflag("hs") <= 0) { 112122534Smckusick if (!strncmp(term, "h19", 3)) { 112222534Smckusick /* for upward compatability with h19sys */ 112322534Smckusick strcpy(to_status_line, 112422534Smckusick "\033j\033x5\033x1\033Y8%+ \033o"); 112522534Smckusick strcpy(from_status_line, "\033k\033y5"); 112622534Smckusick strcpy(dis_status_line, "\033y1"); 112722534Smckusick strcpy(rev_out, "\033p"); 112822534Smckusick strcpy(rev_end, "\033q"); 112922534Smckusick arrows = "\033Fhh\033G"; 113022534Smckusick columns = 80; 113122534Smckusick UP = "\b"; 113222534Smckusick return; 113322534Smckusick } 113422534Smckusick if (!quiet) 113522534Smckusick fprintf(stderr, 113622534Smckusick "sysline: No status capability for %s\n", term); 113722534Smckusick exit(1); 113822534Smckusick } 113922534Smckusick cp = is2; 114022534Smckusick if (tgetstr("i2", &cp) != NULL) { 114122534Smckusick /* someday tset will do this */ 114222534Smckusick tputs(is2, 1, erroutc); 114322534Smckusick fflush(stdout); 114422534Smckusick } 114522534Smckusick 114622534Smckusick /* the "-1" below is to avoid cursor wraparound problems */ 114730978Sbostic columns = tgetnum("ws"); 114834586Sbostic hasws = columns >= 0; 114934586Sbostic if (!hasws) 115030978Sbostic columns = tgetnum("co"); 115130978Sbostic columns -= 1; 115222534Smckusick if (window) { 115322534Smckusick strcpy(to_status_line, "\r"); 115422534Smckusick cp = dis_status_line; /* use the clear line sequence */ 115522534Smckusick *cp++ = '\r'; 115622534Smckusick tgetstr("ce", &cp); 115725792Skarels if (leftline) 115825792Skarels strcpy(from_status_line, dis_status_line + 1); 115925792Skarels else 116025792Skarels strcpy(from_status_line, ""); 116122534Smckusick } else { 116222534Smckusick cp = to_status_line; 116322534Smckusick tgetstr("ts", &cp); 116422534Smckusick cp = from_status_line; 116522534Smckusick tgetstr("fs", &cp); 116622534Smckusick cp = dis_status_line; 116722534Smckusick tgetstr("ds", &cp); 116822534Smckusick eslok = tgetflag("es"); 116922534Smckusick } 117022534Smckusick if (eslok || window) { 117122534Smckusick cp = rev_out; 117222534Smckusick tgetstr("so", &cp); 117322534Smckusick cp = rev_end; 117422534Smckusick tgetstr("se", &cp); 117522534Smckusick cp = clr_eol; 117622534Smckusick tgetstr("ce", &cp); 117722534Smckusick } else 117822534Smckusick reverse = 0; /* turn off reverse video */ 117922534Smckusick UP = "\b"; 118022534Smckusick if (!strncmp(term, "h19", 3)) 118122534Smckusick arrows = "\033Fhh\033G"; /* "two tiny graphic arrows" */ 118222534Smckusick else 118322534Smckusick arrows = "->"; 118422534Smckusick } 118522534Smckusick #endif TERMINFO 118622534Smckusick 118722534Smckusick #ifdef RWHO 118822534Smckusick char * 118922534Smckusick sysrup(hp) 119022534Smckusick register struct remotehost *hp; 119122534Smckusick { 119222534Smckusick char filename[100]; 119322534Smckusick struct whod wd; 119425368Sbloom #define WHOD_HDR_SIZE (sizeof (wd) - sizeof (wd.wd_we)) 119522534Smckusick static char buffer[50]; 119622534Smckusick time_t now; 119722534Smckusick 119822534Smckusick /* 119922534Smckusick * rh_file is initially 0. 120022534Smckusick * This is ok since standard input is assumed to exist. 120122534Smckusick */ 120222534Smckusick if (hp->rh_file == 0) { 120322534Smckusick /* 120422534Smckusick * Try rwho hostname file, and if that fails try ucbhostname. 120522534Smckusick */ 120637905Sbostic (void) strcpy1(strcpy1(filename, _PATH_RWHO), hp->rh_host); 120722534Smckusick if ((hp->rh_file = open(filename, 0)) < 0) { 120837905Sbostic (void) strcpy1(strcpy1(strcpy1(filename, _PATH_RWHO), 120922534Smckusick NETPREFIX), hp->rh_host); 121022534Smckusick hp->rh_file = open(filename, 0); 121122534Smckusick } 121222534Smckusick } 121330978Sbostic if (hp->rh_file < 0) { 121430978Sbostic (void) sprintf(buffer, "%s?", hp->rh_host); 121530978Sbostic return(buffer); 121630978Sbostic } 121722534Smckusick (void) lseek(hp->rh_file, (off_t)0, 0); 121830978Sbostic if (read(hp->rh_file, (char *)&wd, WHOD_HDR_SIZE) != WHOD_HDR_SIZE) { 121930978Sbostic (void) sprintf(buffer, "%s ?", hp->rh_host); 122030978Sbostic return(buffer); 122130978Sbostic } 122222534Smckusick (void) time(&now); 122322534Smckusick if (now - wd.wd_recvtime > DOWN_THRESHOLD) { 122422534Smckusick long interval; 122522534Smckusick long days, hours, minutes; 122622534Smckusick 122722534Smckusick interval = now - wd.wd_recvtime; 122822534Smckusick minutes = (interval + 59) / 60; /* round to minutes */ 122922534Smckusick hours = minutes / 60; /* extract hours from minutes */ 123022534Smckusick minutes %= 60; /* remove hours from minutes */ 123122534Smckusick days = hours / 24; /* extract days from hours */ 123222534Smckusick hours %= 24; /* remove days from hours */ 123322534Smckusick if (days > 7 || days < 0) 123422534Smckusick (void) sprintf(buffer, "%s down", hp->rh_host); 123522534Smckusick else if (days > 0) 123622534Smckusick (void) sprintf(buffer, "%s %d+%d:%02d", 123722534Smckusick hp->rh_host, days, hours, minutes); 123822534Smckusick else 123922534Smckusick (void) sprintf(buffer, "%s %d:%02d", 124022534Smckusick hp->rh_host, hours, minutes); 124122534Smckusick } else 124222534Smckusick (void) sprintf(buffer, "%s %.1f", 124322534Smckusick hp->rh_host, wd.wd_loadav[0]/100.0); 124422534Smckusick return buffer; 124522534Smckusick } 124622534Smckusick #endif RWHO 124722534Smckusick 124822534Smckusick getwinsize() 124922534Smckusick { 125022534Smckusick #ifdef TIOCGWINSZ 125122534Smckusick struct winsize winsize; 125222534Smckusick 125322534Smckusick /* the "-1" below is to avoid cursor wraparound problems */ 125434586Sbostic if (!hasws && ioctl(2, TIOCGWINSZ, (char *)&winsize) >= 0 && 125534586Sbostic winsize.ws_col != 0) 125622534Smckusick columns = winsize.ws_col - 1; 125722534Smckusick #endif 125822534Smckusick } 125922534Smckusick 126022534Smckusick #ifdef SIGWINCH 1261*46661Sbostic void 126222534Smckusick sigwinch() 126322534Smckusick { 126422534Smckusick winchanged++; 126522534Smckusick } 126622534Smckusick #endif 126722534Smckusick 1268*46661Sbostic void 1269*46661Sbostic sigexit() 1270*46661Sbostic { 1271*46661Sbostic exit(1); 1272*46661Sbostic } 1273*46661Sbostic 127422534Smckusick char * 127522534Smckusick strcpy1(p, q) 127622534Smckusick register char *p, *q; 127722534Smckusick { 127822534Smckusick 127922534Smckusick while (*p++ = *q++) 128022534Smckusick ; 128122534Smckusick return p - 1; 128222534Smckusick } 128322534Smckusick 128422534Smckusick outc(c) 128522534Smckusick char c; 128622534Smckusick { 128722534Smckusick if (dbug) 128822534Smckusick printf("%s", unctrl(c)); 128922534Smckusick else 129022534Smckusick putchar(c); 129122534Smckusick } 129222534Smckusick 129322534Smckusick erroutc(c) 129422534Smckusick char c; 129522534Smckusick { 129622534Smckusick if (dbug) 129722534Smckusick fprintf(stderr, "%s", unctrl(c)); 129822534Smckusick else 129922534Smckusick putc(c, stderr); 130022534Smckusick } 1301