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