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