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