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*46968Sbostic static char sccsid[] = "@(#)sysline.c 5.18 (Berkeley) 03/04/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>
7646661Sbostic #include <sys/ioctl.h>
7746661Sbostic #include <signal.h>
7846661Sbostic #include <fcntl.h>
7946661Sbostic #include <utmp.h>
8046661Sbostic #include <nlist.h>
8122534Smckusick #include <curses.h>
8222534Smckusick #undef nl
8322534Smckusick #ifdef TERMINFO
8422534Smckusick #include <term.h>
8546661Sbostic #endif
8646661Sbostic #include <stdarg.h>
8746661Sbostic #include <unistd.h>
8846661Sbostic #include <stdlib.h>
8946661Sbostic #include <string.h>
9046661Sbostic #include <stdio.h>
9146661Sbostic #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[] = {
10846661Sbostic { "_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
21646661Sbostic 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
main(argc,argv)23446661Sbostic main(argc, argv)
23546661Sbostic int argc;
23622534Smckusick register char **argv;
23722534Smckusick {
23822534Smckusick register char *cp;
23922534Smckusick char *home;
24046661Sbostic void clearbotl();
24122534Smckusick
24222534Smckusick gethostname(hostname, sizeof hostname - 1);
24324747Sbloom if ((cp = index(hostname, '.')) != NULL)
24424747Sbloom *cp = '\0';
24546661Sbostic (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
isloggedin()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
readnamelist()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
readutmp(nflag)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 */
initprocread()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 */
readproctab()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
prtinfo()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
timeprint()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 */
whocheck()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 */
ttyprint(name)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 */
mailseen()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 */
readline(fp,buf,n)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
stringinit()92022534Smckusick stringinit()
92122534Smckusick {
92222534Smckusick sp = strarr;
92322534Smckusick chars = 0;
92422534Smckusick }
92522534Smckusick
92622534Smckusick /*VARARGS1*/
stringprt(fmt)92746661Sbostic stringprt(fmt)
92846661Sbostic char *fmt;
92922534Smckusick {
93046661Sbostic va_list ap;
93122534Smckusick char tempbuf[150];
93222534Smckusick
93346661Sbostic va_start(ap, fmt);
93446661Sbostic (void)vsnprintf(tempbuf, sizeof(tempbuf), fmt, ap);
93546661Sbostic va_end(ap);
93632501Sbostic stringcat(tempbuf, -1);
93722534Smckusick }
93822534Smckusick
stringdump()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
stringspace()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 */
stringcat(str,n)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 */
touch(name)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 */
1051*46968Sbostic void
clearbotl()105222534Smckusick clearbotl()
105322534Smckusick {
105422534Smckusick register int fd;
105546661Sbostic void sigexit();
105622534Smckusick
105746661Sbostic signal(SIGALRM, sigexit);
105822534Smckusick alarm(30); /* if can't open in 30 secs, just die */
105922534Smckusick if (!emacs && (fd = open(ourtty, 1)) >= 0) {
106022534Smckusick write(fd, dis_status_line, strlen(dis_status_line));
106122534Smckusick close(fd);
106222534Smckusick }
106322534Smckusick #ifdef PROF
106437905Sbostic if (chdir(_PATH_SYSLINE) < 0)
106537905Sbostic (void) chdir(_PATH_TMP);
106622534Smckusick #endif
106722534Smckusick exit(0);
106822534Smckusick }
106922534Smckusick
107022534Smckusick #ifdef TERMINFO
initterm()107122534Smckusick initterm()
107222534Smckusick {
107322534Smckusick static char standbuf[40];
107422534Smckusick
107522534Smckusick setupterm(0, 1, 0);
107622534Smckusick if (!window && !has_status_line) {
107722534Smckusick /* not an appropriate terminal */
107822534Smckusick if (!quiet)
107922534Smckusick fprintf(stderr, "sysline: no status capability for %s\n",
108022534Smckusick getenv("TERM"));
108122534Smckusick exit(1);
108222534Smckusick }
108322534Smckusick if (window || status_line_esc_ok) {
108422534Smckusick if (set_attributes) {
108522534Smckusick /* reverse video mode */
108622534Smckusick strcpy(standbuf,
108722534Smckusick tparm(set_attributes,0,0,1,0,0,0,0,0,0));
108822534Smckusick rev_out = standbuf;
108922534Smckusick rev_end = exit_attribute_mode;
109022534Smckusick } else if (enter_standout_mode && exit_standout_mode) {
109122534Smckusick rev_out = enter_standout_mode;
109222534Smckusick rev_end = exit_standout_mode;
109322534Smckusick } else
109422534Smckusick rev_out = rev_end = "";
109522534Smckusick } else
109622534Smckusick rev_out = rev_end = "";
109722534Smckusick columns--; /* avoid cursor wraparound */
109822534Smckusick }
109922534Smckusick
110022534Smckusick #else /* TERMCAP */
110122534Smckusick
initterm()110222534Smckusick initterm()
110322534Smckusick {
110422534Smckusick char *term, *cp;
110522534Smckusick static char tbuf[1024];
110622534Smckusick char is2[40];
110722534Smckusick extern char *UP;
110822534Smckusick
110922534Smckusick if ((term = getenv("TERM")) == NULL) {
111022534Smckusick if (!quiet)
111122534Smckusick fprintf(stderr,
111222534Smckusick "sysline: No TERM variable in enviroment\n");
111322534Smckusick exit(1);
111422534Smckusick }
111522534Smckusick if (tgetent(tbuf, term) <= 0) {
111622534Smckusick if (!quiet)
111722534Smckusick fprintf(stderr,
111822534Smckusick "sysline: Unknown terminal type: %s\n", term);
111922534Smckusick exit(1);
112022534Smckusick }
112122534Smckusick if (!window && tgetflag("hs") <= 0) {
112222534Smckusick if (!strncmp(term, "h19", 3)) {
112322534Smckusick /* for upward compatability with h19sys */
112422534Smckusick strcpy(to_status_line,
112522534Smckusick "\033j\033x5\033x1\033Y8%+ \033o");
112622534Smckusick strcpy(from_status_line, "\033k\033y5");
112722534Smckusick strcpy(dis_status_line, "\033y1");
112822534Smckusick strcpy(rev_out, "\033p");
112922534Smckusick strcpy(rev_end, "\033q");
113022534Smckusick arrows = "\033Fhh\033G";
113122534Smckusick columns = 80;
113222534Smckusick UP = "\b";
113322534Smckusick return;
113422534Smckusick }
113522534Smckusick if (!quiet)
113622534Smckusick fprintf(stderr,
113722534Smckusick "sysline: No status capability for %s\n", term);
113822534Smckusick exit(1);
113922534Smckusick }
114022534Smckusick cp = is2;
114122534Smckusick if (tgetstr("i2", &cp) != NULL) {
114222534Smckusick /* someday tset will do this */
114322534Smckusick tputs(is2, 1, erroutc);
114422534Smckusick fflush(stdout);
114522534Smckusick }
114622534Smckusick
114722534Smckusick /* the "-1" below is to avoid cursor wraparound problems */
114830978Sbostic columns = tgetnum("ws");
114934586Sbostic hasws = columns >= 0;
115034586Sbostic if (!hasws)
115130978Sbostic columns = tgetnum("co");
115230978Sbostic columns -= 1;
115322534Smckusick if (window) {
115422534Smckusick strcpy(to_status_line, "\r");
115522534Smckusick cp = dis_status_line; /* use the clear line sequence */
115622534Smckusick *cp++ = '\r';
115722534Smckusick tgetstr("ce", &cp);
115825792Skarels if (leftline)
115925792Skarels strcpy(from_status_line, dis_status_line + 1);
116025792Skarels else
116125792Skarels strcpy(from_status_line, "");
116222534Smckusick } else {
116322534Smckusick cp = to_status_line;
116422534Smckusick tgetstr("ts", &cp);
116522534Smckusick cp = from_status_line;
116622534Smckusick tgetstr("fs", &cp);
116722534Smckusick cp = dis_status_line;
116822534Smckusick tgetstr("ds", &cp);
116922534Smckusick eslok = tgetflag("es");
117022534Smckusick }
117122534Smckusick if (eslok || window) {
117222534Smckusick cp = rev_out;
117322534Smckusick tgetstr("so", &cp);
117422534Smckusick cp = rev_end;
117522534Smckusick tgetstr("se", &cp);
117622534Smckusick cp = clr_eol;
117722534Smckusick tgetstr("ce", &cp);
117822534Smckusick } else
117922534Smckusick reverse = 0; /* turn off reverse video */
118022534Smckusick UP = "\b";
118122534Smckusick if (!strncmp(term, "h19", 3))
118222534Smckusick arrows = "\033Fhh\033G"; /* "two tiny graphic arrows" */
118322534Smckusick else
118422534Smckusick arrows = "->";
118522534Smckusick }
118622534Smckusick #endif TERMINFO
118722534Smckusick
118822534Smckusick #ifdef RWHO
118922534Smckusick char *
sysrup(hp)119022534Smckusick sysrup(hp)
119122534Smckusick register struct remotehost *hp;
119222534Smckusick {
119322534Smckusick char filename[100];
119422534Smckusick struct whod wd;
119525368Sbloom #define WHOD_HDR_SIZE (sizeof (wd) - sizeof (wd.wd_we))
119622534Smckusick static char buffer[50];
119722534Smckusick time_t now;
119822534Smckusick
119922534Smckusick /*
120022534Smckusick * rh_file is initially 0.
120122534Smckusick * This is ok since standard input is assumed to exist.
120222534Smckusick */
120322534Smckusick if (hp->rh_file == 0) {
120422534Smckusick /*
120522534Smckusick * Try rwho hostname file, and if that fails try ucbhostname.
120622534Smckusick */
120737905Sbostic (void) strcpy1(strcpy1(filename, _PATH_RWHO), hp->rh_host);
120822534Smckusick if ((hp->rh_file = open(filename, 0)) < 0) {
120937905Sbostic (void) strcpy1(strcpy1(strcpy1(filename, _PATH_RWHO),
121022534Smckusick NETPREFIX), hp->rh_host);
121122534Smckusick hp->rh_file = open(filename, 0);
121222534Smckusick }
121322534Smckusick }
121430978Sbostic if (hp->rh_file < 0) {
121530978Sbostic (void) sprintf(buffer, "%s?", hp->rh_host);
121630978Sbostic return(buffer);
121730978Sbostic }
121822534Smckusick (void) lseek(hp->rh_file, (off_t)0, 0);
121930978Sbostic if (read(hp->rh_file, (char *)&wd, WHOD_HDR_SIZE) != WHOD_HDR_SIZE) {
122030978Sbostic (void) sprintf(buffer, "%s ?", hp->rh_host);
122130978Sbostic return(buffer);
122230978Sbostic }
122322534Smckusick (void) time(&now);
122422534Smckusick if (now - wd.wd_recvtime > DOWN_THRESHOLD) {
122522534Smckusick long interval;
122622534Smckusick long days, hours, minutes;
122722534Smckusick
122822534Smckusick interval = now - wd.wd_recvtime;
122922534Smckusick minutes = (interval + 59) / 60; /* round to minutes */
123022534Smckusick hours = minutes / 60; /* extract hours from minutes */
123122534Smckusick minutes %= 60; /* remove hours from minutes */
123222534Smckusick days = hours / 24; /* extract days from hours */
123322534Smckusick hours %= 24; /* remove days from hours */
123422534Smckusick if (days > 7 || days < 0)
123522534Smckusick (void) sprintf(buffer, "%s down", hp->rh_host);
123622534Smckusick else if (days > 0)
123722534Smckusick (void) sprintf(buffer, "%s %d+%d:%02d",
123822534Smckusick hp->rh_host, days, hours, minutes);
123922534Smckusick else
124022534Smckusick (void) sprintf(buffer, "%s %d:%02d",
124122534Smckusick hp->rh_host, hours, minutes);
124222534Smckusick } else
124322534Smckusick (void) sprintf(buffer, "%s %.1f",
124422534Smckusick hp->rh_host, wd.wd_loadav[0]/100.0);
124522534Smckusick return buffer;
124622534Smckusick }
124722534Smckusick #endif RWHO
124822534Smckusick
getwinsize()124922534Smckusick getwinsize()
125022534Smckusick {
125122534Smckusick #ifdef TIOCGWINSZ
125222534Smckusick struct winsize winsize;
125322534Smckusick
125422534Smckusick /* the "-1" below is to avoid cursor wraparound problems */
125534586Sbostic if (!hasws && ioctl(2, TIOCGWINSZ, (char *)&winsize) >= 0 &&
125634586Sbostic winsize.ws_col != 0)
125722534Smckusick columns = winsize.ws_col - 1;
125822534Smckusick #endif
125922534Smckusick }
126022534Smckusick
126122534Smckusick #ifdef SIGWINCH
126246661Sbostic void
sigwinch()126322534Smckusick sigwinch()
126422534Smckusick {
126522534Smckusick winchanged++;
126622534Smckusick }
126722534Smckusick #endif
126822534Smckusick
126946661Sbostic void
sigexit()127046661Sbostic sigexit()
127146661Sbostic {
127246661Sbostic exit(1);
127346661Sbostic }
127446661Sbostic
127522534Smckusick char *
strcpy1(p,q)127622534Smckusick strcpy1(p, q)
127722534Smckusick register char *p, *q;
127822534Smckusick {
127922534Smckusick
128022534Smckusick while (*p++ = *q++)
128122534Smckusick ;
128222534Smckusick return p - 1;
128322534Smckusick }
128422534Smckusick
outc(c)128522534Smckusick outc(c)
128622534Smckusick char c;
128722534Smckusick {
128822534Smckusick if (dbug)
128922534Smckusick printf("%s", unctrl(c));
129022534Smckusick else
129122534Smckusick putchar(c);
129222534Smckusick }
129322534Smckusick
erroutc(c)129422534Smckusick erroutc(c)
129522534Smckusick char c;
129622534Smckusick {
129722534Smckusick if (dbug)
129822534Smckusick fprintf(stderr, "%s", unctrl(c));
129922534Smckusick else
130022534Smckusick putc(c, stderr);
130122534Smckusick }
1302