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