Commit | Line | Data |
---|---|---|
e1e8d3ca KM |
1 | /* |
2 | * Copyright (c) 1980 Regents of the University of California. | |
f9e4427b KB |
3 | * All rights reserved. |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
9c50374f KB |
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. | |
e1e8d3ca KM |
16 | */ |
17 | ||
18 | #ifndef lint | |
19 | char copyright[] = | |
20 | "@(#) Copyright (c) 1980 Regents of the University of California.\n\ | |
21 | All rights reserved.\n"; | |
f9e4427b | 22 | #endif /* not lint */ |
e1e8d3ca KM |
23 | |
24 | #ifndef lint | |
b528bd5e | 25 | static char sccsid[] = "@(#)sysline.c 5.13 (Berkeley) %G%"; |
f9e4427b | 26 | #endif /* not lint */ |
e1e8d3ca KM |
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 */ | |
e1e8d3ca KM |
75 | /* |
76 | * if MAXLOAD is defined, then if the load average exceeded MAXLOAD | |
77 | * then the process table will not be scanned and the log in/out data | |
78 | * will not be checked. The purpose of this is to reduced the load | |
79 | * on the system when it is loaded. | |
80 | */ | |
81 | #define MAXLOAD 6.0 | |
82 | ||
83 | #include <stdio.h> | |
84 | #include <sys/param.h> | |
85 | #include <sys/signal.h> | |
86 | #include <utmp.h> | |
87 | #include <ctype.h> | |
88 | #ifndef BSD4_2 | |
89 | #include <unctrl.h> | |
90 | #endif | |
91 | #include <sys/time.h> | |
92 | #include <sys/stat.h> | |
93 | #ifdef VMUNIX | |
94 | #include <nlist.h> | |
95 | #include <sys/vtimes.h> | |
96 | #include <sys/proc.h> | |
97 | #endif | |
98 | #ifdef pdp11 | |
99 | #include <a.out.h> | |
100 | #include <sys/proc.h> | |
101 | #endif | |
102 | #include <curses.h> | |
103 | #undef nl | |
104 | #ifdef TERMINFO | |
105 | #include <term.h> | |
106 | #endif TERMINFO | |
107 | ||
108 | #ifdef RWHO | |
6efb822a MK |
109 | #include <protocols/rwhod.h> |
110 | ||
e1e8d3ca | 111 | #define DOWN_THRESHOLD (11 * 60) |
e1e8d3ca | 112 | |
e1e8d3ca KM |
113 | struct remotehost { |
114 | char *rh_host; | |
115 | int rh_file; | |
116 | } remotehost[10]; | |
117 | int nremotes = 0; | |
118 | #endif RWHO | |
119 | ||
b528bd5e KB |
120 | #include "pathnames.h" |
121 | ||
e1e8d3ca KM |
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 */ | |
b528bd5e | 141 | int kmem; /* file descriptor for _PATH_KMEM */ |
e1e8d3ca KM |
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 | */ | |
4874204a | 152 | int ut = -1; /* the file descriptor */ |
e1e8d3ca KM |
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 | |
6efb822a | 174 | char hostname[MAXHOSTNAMELEN+1]; /* one more for null termination */ |
e1e8d3ca KM |
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) */ | |
f9e4427b | 234 | int hasws = 0; /* is "ws" explicitly defined? */ |
e1e8d3ca KM |
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; | |
658d7227 | 251 | uid_t uid; |
e1e8d3ca KM |
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; | |
897f1e78 | 270 | extern char *index(); |
e1e8d3ca | 271 | |
e1e8d3ca KM |
272 | #ifdef HOSTNAME |
273 | gethostname(hostname, sizeof hostname - 1); | |
897f1e78 JB |
274 | if ((cp = index(hostname, '.')) != NULL) |
275 | *cp = '\0'; | |
e1e8d3ca KM |
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 | ||
b528bd5e KB |
412 | if ((kmem = open(_PATH_KMEM,0)) < 0) { |
413 | fprintf(stderr, "Can't open %s\n", _PATH_KMEM); | |
e1e8d3ca KM |
414 | exit(1); |
415 | } | |
416 | readnamelist(); | |
417 | if (proccheck) | |
418 | initprocread(); | |
e1e8d3ca KM |
419 | if (mailcheck) |
420 | if ((username = getenv("USER")) == 0) | |
421 | mailcheck = 0; | |
422 | else { | |
b528bd5e | 423 | chdir(_PATH_MBOX); |
e1e8d3ca KM |
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 | ||
b528bd5e | 462 | nlist(_PATH_UNIX, nl); |
e1e8d3ca KM |
463 | if (nl[0].n_value == 0) { |
464 | if (!quiet) | |
465 | fprintf(stderr, "No namelist\n"); | |
466 | return; | |
467 | } | |
468 | lseek(kmem, (long)nl[NL_BOOT].n_value, 0); | |
469 | read(kmem, &bootime, sizeof(bootime)); | |
470 | (void) time(&clock); | |
471 | nintv = clock - bootime; | |
472 | if (nintv <= 0L || nintv > 60L*60L*24L*365L) { | |
473 | if (!quiet) | |
474 | fprintf(stderr, | |
475 | "Time makes no sense... namelist must be wrong\n"); | |
476 | nl[NL_PROC].n_value = nl[NL_AVEN].n_value = 0; | |
477 | } | |
478 | } | |
479 | ||
4874204a EW |
480 | readutmp(nflag) |
481 | char nflag; | |
e1e8d3ca | 482 | { |
4874204a EW |
483 | static time_t lastmod; /* initially zero */ |
484 | static off_t utmpsize; /* ditto */ | |
e1e8d3ca KM |
485 | struct stat st; |
486 | ||
b528bd5e KB |
487 | if (ut < 0 && (ut = open(_PATH_UTMP, 0)) < 0) { |
488 | fprintf(stderr, "sysline: Can't open %s.\n", _PATH_UTMP); | |
e1e8d3ca KM |
489 | exit(1); |
490 | } | |
4874204a | 491 | if (fstat(ut, &st) < 0 || st.st_mtime == lastmod) |
e1e8d3ca KM |
492 | return 0; |
493 | lastmod = st.st_mtime; | |
4874204a EW |
494 | if (utmpsize != st.st_size) { |
495 | utmpsize = st.st_size; | |
496 | nentries = utmpsize / sizeof (struct utmp); | |
497 | if (old == 0) { | |
498 | old = (struct utmp *)calloc(utmpsize, 1); | |
499 | new = (struct utmp *)calloc(utmpsize, 1); | |
500 | } else { | |
501 | old = (struct utmp *)realloc((char *)old, utmpsize); | |
502 | new = (struct utmp *)realloc((char *)new, utmpsize); | |
503 | free(status); | |
504 | } | |
505 | status = malloc(nentries * sizeof *status); | |
506 | if (old == 0 || new == 0 || status == 0) { | |
507 | fprintf(stderr, "sysline: Out of memory.\n"); | |
508 | exit(1); | |
509 | } | |
510 | } | |
e1e8d3ca | 511 | lseek(ut, 0L, 0); |
4874204a | 512 | (void) read(ut, (char *) (nflag ? new : old), utmpsize); |
e1e8d3ca KM |
513 | return 1; |
514 | } | |
515 | ||
516 | /* | |
517 | * read in the process table locations and sizes, and allocate space | |
518 | * for storing the process table. This is done only once. | |
519 | */ | |
520 | initprocread() | |
521 | { | |
522 | ||
523 | if (nl[NL_PROC].n_value == 0) | |
524 | return; | |
525 | #ifdef VMUNIX | |
526 | lseek(kmem, (long)nl[NL_PROC].n_value, 0); | |
527 | read(kmem, &procadr, sizeof procadr); | |
528 | lseek(kmem, (long)nl[NL_NPROC].n_value, 0); | |
529 | read(kmem, &nproc, sizeof nproc); | |
530 | #endif | |
531 | #ifdef pdp11 | |
532 | procadr = nl[NL_PROC].n_value; | |
533 | nproc = NPROC; /* from param.h */ | |
534 | #endif | |
535 | if ((proc = (struct proc *) calloc(nproc, sizeof (struct proc))) == 0) { | |
536 | fprintf(stderr, "Out of memory.\n"); | |
537 | exit(1); | |
538 | } | |
539 | procNPROC = proc + nproc; | |
540 | } | |
541 | ||
542 | /* | |
543 | * read in the process table. This assumes that initprocread has alread been | |
544 | * called to set up storage. | |
545 | */ | |
546 | readproctab() | |
547 | { | |
548 | ||
549 | if (nl[NL_PROC].n_value == 0) | |
550 | return (0); | |
551 | lseek(kmem, (long)procadr, 0); | |
552 | read(kmem, (char *)proc, nproc * sizeof (struct proc)); | |
553 | return (1); | |
554 | } | |
555 | ||
556 | prtinfo() | |
557 | { | |
558 | int on, off; | |
559 | register i; | |
560 | char fullprocess; | |
561 | ||
562 | stringinit(); | |
563 | #ifdef SIGWINCH | |
564 | if (winchanged) { | |
565 | winchanged = 0; | |
566 | getwinsize(); | |
567 | mustclear = 1; | |
568 | } | |
569 | #endif | |
570 | #ifdef WHO | |
571 | /* check for file named .who in the home directory */ | |
572 | whocheck(); | |
573 | #endif | |
574 | timeprint(); | |
575 | /* | |
576 | * if mail is seen, don't print rest of info, just the mail | |
577 | * reverse new and old so that next time we run, we won't lose log | |
578 | * in and out information | |
579 | */ | |
580 | if (mailcheck && (sawmail = mailseen())) | |
581 | goto bottom; | |
582 | #ifdef HOSTNAME | |
583 | #ifdef RWHO | |
584 | for (i = 0; i < nremotes; i++) { | |
585 | char *tmp; | |
586 | ||
587 | stringspace(); | |
588 | tmp = sysrup(remotehost + i); | |
589 | stringcat(tmp, strlen(tmp)); | |
590 | } | |
591 | #endif | |
592 | /* | |
593 | * print hostname info if requested | |
594 | */ | |
595 | if (hostprint) { | |
596 | stringspace(); | |
597 | stringcat(hostname, -1); | |
598 | } | |
599 | #endif | |
600 | /* | |
601 | * print load average and difference between current load average | |
602 | * and the load average 5 minutes ago | |
603 | */ | |
604 | if (nl[NL_AVEN].n_value != 0) { | |
605 | double diff; | |
606 | ||
607 | stringspace(); | |
608 | #ifdef VMUNIX | |
609 | lseek(kmem, (long)nl[NL_AVEN].n_value, 0); | |
610 | read(kmem, avenrun, sizeof avenrun); | |
611 | #endif | |
612 | #ifdef pdp11 | |
613 | loadav(avenrun); | |
614 | #endif | |
615 | if ((diff = avenrun[0] - avenrun[1]) < 0.0) | |
616 | stringprt("%.1f %.1f", avenrun[0], diff); | |
617 | else | |
618 | stringprt("%.1f +%.1f", avenrun[0], diff); | |
619 | loadavg = avenrun[0]; /* remember load average */ | |
620 | } | |
621 | /* | |
622 | * print log on and off information | |
623 | */ | |
624 | stringspace(); | |
625 | fullprocess = 1; | |
626 | #ifdef MAXLOAD | |
627 | if (loadavg > MAXLOAD) | |
628 | fullprocess = 0; /* too loaded to run */ | |
629 | #endif | |
630 | /* | |
631 | * Read utmp file (logged in data) only if we are doing a full | |
632 | * process, or if this is the first time and we are calculating | |
633 | * the number of users. | |
634 | */ | |
635 | on = off = 0; | |
636 | if (users == 0) { /* first time */ | |
4874204a | 637 | if (readutmp(0)) |
e1e8d3ca KM |
638 | for (i = 0; i < nentries; i++) |
639 | if (old[i].ut_name[0]) | |
640 | users++; | |
4874204a | 641 | } else if (fullprocess && readutmp(1)) { |
e1e8d3ca KM |
642 | struct utmp *tmp; |
643 | ||
644 | users = 0; | |
645 | for (i = 0; i < nentries; i++) { | |
646 | if (strncmp(old[i].ut_name, | |
647 | new[i].ut_name, NAMESIZE) == 0) | |
648 | status[i] = NOCH; | |
649 | else if (old[i].ut_name[0] == '\0') { | |
650 | status[i] = ON; | |
651 | on++; | |
652 | } else if (new[i].ut_name[0] == '\0') { | |
653 | status[i] = OFF; | |
654 | off++; | |
655 | } else { | |
656 | status[i] = ON | OFF; | |
657 | on++; | |
658 | off++; | |
659 | } | |
660 | if (new[i].ut_name[0]) | |
661 | users++; | |
662 | } | |
663 | tmp = new; | |
664 | new = old; | |
665 | old = tmp; | |
666 | } | |
667 | /* | |
668 | * Print: | |
669 | * 1. number of users | |
670 | * 2. a * for unread mail | |
671 | * 3. a - if load is too high | |
672 | * 4. number of processes running and stopped | |
673 | */ | |
674 | stringprt("%du", users); | |
675 | if (mailsize > 0 && mstbuf.st_mtime >= mstbuf.st_atime) | |
676 | stringcat("*", -1); | |
677 | if (!fullprocess && (proccheck || logcheck)) | |
678 | stringcat("-", -1); | |
679 | if (fullprocess && proccheck && readproctab()) { | |
680 | register struct proc *p; | |
681 | int procrun, procstop; | |
682 | ||
683 | /* | |
684 | * We are only interested in processes which have the same | |
685 | * uid as us, and whose parent process id is not 1. | |
686 | */ | |
687 | procrun = procstop = 0; | |
688 | for (p = proc; p < procNPROC; p++) { | |
689 | if (p->p_stat == 0 || p->p_pgrp == 0 || | |
690 | p->p_uid != uid || p->p_ppid == 1) | |
691 | continue; | |
692 | switch (p->p_stat) { | |
693 | case SSTOP: | |
694 | procstop++; | |
695 | break; | |
696 | case SSLEEP: | |
697 | /* | |
698 | * Sleep can mean waiting for a signal or just | |
699 | * in a disk or page wait queue ready to run. | |
700 | * We can tell if it is the later by the pri | |
701 | * being negative. | |
702 | */ | |
703 | if (p->p_pri < PZERO) | |
704 | procrun++; | |
705 | break; | |
706 | case SWAIT: | |
707 | case SRUN: | |
708 | case SIDL: | |
709 | procrun++; | |
710 | } | |
711 | } | |
712 | if (procrun > 0 || procstop > 0) { | |
713 | stringspace(); | |
714 | if (procrun > 0 && procstop > 0) | |
715 | stringprt("%dr %ds", procrun, procstop); | |
716 | else if (procrun > 0) | |
717 | stringprt("%dr", procrun); | |
718 | else | |
719 | stringprt("%ds", procstop); | |
720 | } | |
721 | } | |
722 | /* | |
723 | * If anyone has logged on or off, and we are interested in it, | |
724 | * print it out. | |
725 | */ | |
726 | if (logcheck) { | |
727 | /* old and new have already been swapped */ | |
728 | if (on) { | |
729 | stringspace(); | |
730 | stringcat("on:", -1); | |
731 | for (i = 0; i < nentries; i++) | |
732 | if (status[i] & ON) { | |
733 | stringprt(" %.8s", old[i].ut_name); | |
734 | ttyprint(old[i].ut_line); | |
735 | } | |
736 | } | |
737 | if (off) { | |
738 | stringspace(); | |
739 | stringcat("off:", -1); | |
740 | for (i = 0; i < nentries; i++) | |
741 | if (status[i] & OFF) { | |
742 | stringprt(" %.8s", new[i].ut_name); | |
743 | ttyprint(new[i].ut_line); | |
744 | } | |
745 | } | |
746 | } | |
747 | bottom: | |
748 | /* dump out what we know */ | |
749 | stringdump(); | |
750 | } | |
751 | ||
752 | timeprint() | |
753 | { | |
754 | long curtime; | |
755 | struct tm *tp, *localtime(); | |
756 | static int beepable = 1; | |
757 | ||
758 | /* always print time */ | |
759 | time(&curtime); | |
760 | tp = localtime(&curtime); | |
761 | if (dateprint) | |
762 | stringprt("%.11s", ctime(&curtime)); | |
763 | stringprt("%d:%02d", tp->tm_hour > 12 ? tp->tm_hour - 12 : | |
764 | (tp->tm_hour == 0 ? 12 : tp->tm_hour), tp->tm_min); | |
765 | if (synch) /* sync with clock */ | |
766 | delay = 60 - tp->tm_sec; | |
767 | /* | |
768 | * Beepable is used to insure that we get at most one set of beeps | |
769 | * every half hour. | |
770 | */ | |
771 | if (beep) | |
772 | if (beepable) { | |
773 | if (tp->tm_min == 30) { | |
774 | tputs(bell, 1, outc); | |
775 | fflush(stdout); | |
776 | beepable = 0; | |
777 | } else if (tp->tm_min == 0) { | |
778 | tputs(bell, 1, outc); | |
779 | fflush(stdout); | |
780 | sleep(2); | |
781 | tputs(bell, 1, outc); | |
782 | fflush(stdout); | |
783 | beepable = 0; | |
784 | } | |
785 | } else | |
786 | if (tp->tm_min != 0 && tp->tm_min != 30) | |
787 | beepable = 1; | |
788 | } | |
789 | ||
790 | /* | |
791 | * whocheck -- check for file named .who and print it on the who line first | |
792 | */ | |
793 | whocheck() | |
794 | { | |
795 | int chss; | |
796 | register char *p; | |
797 | char buff[81]; | |
798 | int whofile; | |
799 | ||
800 | if ((whofile = open(whofilename, 0)) < 0 && | |
801 | (whofile = open(whofilename2, 0)) < 0) | |
802 | return; | |
803 | chss = read(whofile, buff, sizeof buff - 1); | |
804 | close(whofile); | |
805 | if (chss <= 0) | |
806 | return; | |
807 | buff[chss] = '\0'; | |
808 | /* | |
809 | * Remove all line feeds, and replace by spaces if they are within | |
810 | * the message, else replace them by nulls. | |
811 | */ | |
812 | for (p = buff; *p;) | |
813 | if (*p == '\n') | |
814 | if (p[1]) | |
815 | *p++ = ' '; | |
816 | else | |
817 | *p = '\0'; | |
818 | else | |
819 | p++; | |
820 | stringcat(buff, p - buff); | |
821 | stringspace(); | |
822 | } | |
823 | ||
824 | /* | |
825 | * ttyprint -- given the name of a tty, print in the string buffer its | |
826 | * short name surrounded by parenthesis. | |
827 | * ttyxx is printed as (xx) | |
828 | * console is printed as (cty) | |
829 | */ | |
830 | ttyprint(name) | |
831 | char *name; | |
832 | { | |
833 | char buff[11]; | |
834 | ||
835 | if (strncmp(name, "tty", 3) == 0) | |
836 | stringprt("(%.*s)", LINESIZE - 3, name + 3); | |
837 | else if (strcmp(name, "console") == 0) | |
838 | stringcat("(cty)", -1); | |
839 | else | |
840 | stringprt("(%.*s)", LINESIZE, name); | |
841 | } | |
842 | ||
843 | /* | |
844 | * mail checking function | |
845 | * returns 0 if no mail seen | |
846 | */ | |
847 | mailseen() | |
848 | { | |
849 | FILE *mfd; | |
850 | register n; | |
851 | register char *cp; | |
852 | char lbuf[100], sendbuf[100], *bufend; | |
853 | char seenspace; | |
854 | int retval = 0; | |
855 | ||
856 | if (stat(username, &mstbuf) < 0) { | |
857 | mailsize = 0; | |
858 | return 0; | |
859 | } | |
860 | if (mstbuf.st_size <= mailsize || (mfd = fopen(username,"r")) == NULL) { | |
861 | mailsize = mstbuf.st_size; | |
862 | return 0; | |
863 | } | |
864 | fseek(mfd, mailsize, 0); | |
865 | while ((n = readline(mfd, lbuf, sizeof lbuf)) >= 0 && | |
866 | strncmp(lbuf, "From ", 5) != 0) | |
867 | ; | |
868 | if (n < 0) { | |
f9e4427b | 869 | stringcat("Mail has just arrived", -1); |
e1e8d3ca KM |
870 | goto out; |
871 | } | |
872 | retval = 1; | |
873 | /* | |
874 | * Found a From line, get second word, which is the sender, | |
875 | * and print it. | |
876 | */ | |
877 | for (cp = lbuf + 5; *cp && *cp != ' '; cp++) /* skip to blank */ | |
878 | ; | |
879 | *cp = '\0'; /* terminate name */ | |
880 | stringspace(); | |
881 | stringprt("Mail from %s ", lbuf + 5); | |
882 | /* | |
883 | * Print subject, and skip over header. | |
884 | */ | |
885 | while ((n = readline(mfd, lbuf, sizeof lbuf)) > 0) | |
886 | if (strncmp(lbuf, "Subject:", 8) == 0) | |
887 | stringprt("on %s ", lbuf + 9); | |
888 | if (!emacs) | |
889 | stringcat(arrows, 2); | |
890 | else | |
891 | stringcat(": ", 2); | |
892 | if (n < 0) /* already at eof */ | |
893 | goto out; | |
894 | /* | |
895 | * Print as much of the letter as we can. | |
896 | */ | |
897 | cp = sendbuf; | |
898 | if ((n = columns - chars) > sizeof sendbuf - 1) | |
899 | n = sizeof sendbuf - 1; | |
900 | bufend = cp + n; | |
901 | seenspace = 0; | |
902 | while ((n = readline(mfd, lbuf, sizeof lbuf)) >= 0) { | |
903 | register char *rp; | |
904 | ||
905 | if (strncmp(lbuf, "From ", 5) == 0) | |
906 | break; | |
907 | if (cp >= bufend) | |
908 | continue; | |
909 | if (!seenspace) { | |
910 | *cp++ = ' '; /* space before lines */ | |
911 | seenspace = 1; | |
912 | } | |
913 | rp = lbuf; | |
914 | while (*rp && cp < bufend) | |
915 | if (isspace(*rp)) { | |
916 | if (!seenspace) { | |
917 | *cp++ = ' '; | |
918 | seenspace = 1; | |
919 | } | |
920 | rp++; | |
921 | } else { | |
922 | *cp++ = *rp++; | |
923 | seenspace = 0; | |
924 | } | |
925 | } | |
926 | *cp = 0; | |
927 | stringcat(sendbuf, -1); | |
928 | /* | |
929 | * Want to update write time so a star will | |
930 | * appear after the number of users until the | |
931 | * user reads his mail. | |
932 | */ | |
933 | out: | |
934 | mailsize = linebeg; | |
935 | fclose(mfd); | |
936 | touch(username); | |
937 | return retval; | |
938 | } | |
939 | ||
940 | /* | |
941 | * readline -- read a line from fp and store it in buf. | |
942 | * return the number of characters read. | |
943 | */ | |
944 | readline(fp, buf, n) | |
945 | register FILE *fp; | |
946 | char *buf; | |
947 | register n; | |
948 | { | |
949 | register c; | |
950 | register char *cp = buf; | |
951 | ||
952 | linebeg = ftell(fp); /* remember loc where line begins */ | |
953 | cp = buf; | |
954 | while (--n > 0 && (c = getc(fp)) != EOF && c != '\n') | |
955 | *cp++ = c; | |
956 | *cp = 0; | |
957 | if (c == EOF && cp - buf == 0) | |
958 | return -1; | |
959 | return cp - buf; | |
960 | } | |
961 | ||
962 | ||
963 | /* | |
964 | * string hacking functions | |
965 | */ | |
966 | ||
967 | stringinit() | |
968 | { | |
969 | sp = strarr; | |
970 | chars = 0; | |
971 | } | |
972 | ||
973 | /*VARARGS1*/ | |
974 | stringprt(format, a, b, c) | |
975 | char *format; | |
976 | { | |
977 | char tempbuf[150]; | |
978 | ||
06eef7c4 KB |
979 | (void)sprintf(tempbuf, format, a, b, c); |
980 | stringcat(tempbuf, -1); | |
e1e8d3ca KM |
981 | } |
982 | ||
983 | stringdump() | |
984 | { | |
985 | char bigbuf[sizeof strarr + 200]; | |
986 | register char *bp = bigbuf; | |
987 | register int i; | |
988 | ||
989 | if (!emacs) { | |
990 | if (sawmail) | |
991 | bp = strcpy1(bp, bell); | |
992 | if (eslok) | |
993 | bp = strcpy1(bp, tparm(to_status_line, | |
994 | leftline ? 0 : columns - chars)); | |
995 | else { | |
996 | bp = strcpy1(bp, to_status_line); | |
997 | if (!shortline && !leftline) | |
998 | for (i = columns - chars; --i >= 0;) | |
999 | *bp++ = ' '; | |
1000 | } | |
1001 | if (reverse && revtime != 0) | |
1002 | bp = strcpy1(bp, rev_out); | |
1003 | } | |
1004 | *sp = 0; | |
1005 | bp = strcpy1(bp, strarr); | |
1006 | if (!emacs) { | |
1007 | if (reverse) | |
1008 | bp = strcpy1(bp, rev_end); | |
1009 | bp = strcpy1(bp, from_status_line); | |
1010 | if (sawmail) | |
1011 | bp = strcpy1(strcpy1(bp, bell), bell); | |
1012 | *bp = 0; | |
1013 | tputs(bigbuf, 1, outc); | |
1014 | if (mustclear) { | |
1015 | mustclear = 0; | |
1016 | tputs(clr_eol, 1, outc); | |
1017 | } | |
1018 | if (dbug) | |
1019 | putchar('\n'); | |
1020 | fflush(stdout); | |
1021 | } else | |
1022 | write(2, bigbuf, bp - bigbuf); | |
1023 | } | |
1024 | ||
1025 | stringspace() | |
1026 | { | |
1027 | if (reverse && revtime != 0) { | |
1028 | #ifdef TERMINFO | |
1029 | stringcat(rev_end, | |
1030 | magic_cookie_glitch <= 0 ? 0 : magic_cookie_glitch); | |
1031 | stringcat(" ", 1); | |
1032 | stringcat(rev_out, | |
1033 | magic_cookie_glitch <= 0 ? 0 : magic_cookie_glitch); | |
1034 | #else | |
1035 | stringcat(rev_end, 0); | |
1036 | stringcat(" ", 1); | |
1037 | stringcat(rev_out, 0); | |
1038 | #endif TERMINFO | |
1039 | } else | |
1040 | stringcat(" ", 1); | |
1041 | } | |
1042 | ||
1043 | /* | |
1044 | * stringcat :: concatenate the characters in string str to the list we are | |
1045 | * building to send out. | |
1046 | * str - the string to print. may contain funny (terminal control) chars. | |
1047 | * n - the number of printable characters in the string | |
1048 | * or if -1 then str is all printable so we can truncate it, | |
1049 | * otherwise don't print only half a string. | |
1050 | */ | |
1051 | stringcat(str, n) | |
1052 | register char *str; | |
1053 | register n; | |
1054 | { | |
1055 | register char *p = sp; | |
1056 | ||
1057 | if (n < 0) { /* truncate */ | |
1058 | n = columns - chars; | |
1059 | while ((*p++ = *str++) && --n >= 0) | |
1060 | ; | |
1061 | p--; | |
1062 | chars += p - sp; | |
1063 | sp = p; | |
1064 | } else if (chars + n <= columns) { /* don't truncate */ | |
1065 | while (*p++ = *str++) | |
1066 | ; | |
1067 | chars += n; | |
1068 | sp = p - 1; | |
1069 | } | |
1070 | } | |
1071 | ||
1072 | /* | |
1073 | * touch :: update the modify time of a file. | |
1074 | */ | |
1075 | touch(name) | |
1076 | char *name; /* name of file */ | |
1077 | { | |
1078 | register fd; | |
1079 | char buf; | |
1080 | ||
1081 | if ((fd = open(name, 2)) >= 0) { | |
1082 | read(fd, &buf, 1); /* get first byte */ | |
1083 | lseek(fd, 0L, 0); /* go to beginning */ | |
1084 | write(fd, &buf, 1); /* and rewrite first byte */ | |
1085 | close(fd); | |
1086 | } | |
1087 | } | |
1088 | ||
1089 | ||
1090 | /* | |
1091 | * clearbotl :: clear bottom line. | |
1092 | * called when process quits or is killed. | |
1093 | * it clears the bottom line of the terminal. | |
1094 | */ | |
1095 | clearbotl() | |
1096 | { | |
1097 | register int fd; | |
1098 | int exit(); | |
1099 | ||
1100 | signal(SIGALRM, exit); | |
1101 | alarm(30); /* if can't open in 30 secs, just die */ | |
1102 | if (!emacs && (fd = open(ourtty, 1)) >= 0) { | |
1103 | write(fd, dis_status_line, strlen(dis_status_line)); | |
1104 | close(fd); | |
1105 | } | |
1106 | #ifdef PROF | |
b528bd5e KB |
1107 | if (chdir(_PATH_SYSLINE) < 0) |
1108 | (void) chdir(_PATH_TMP); | |
e1e8d3ca KM |
1109 | #endif |
1110 | exit(0); | |
1111 | } | |
1112 | ||
1113 | #ifdef TERMINFO | |
1114 | initterm() | |
1115 | { | |
1116 | static char standbuf[40]; | |
1117 | ||
1118 | setupterm(0, 1, 0); | |
1119 | if (!window && !has_status_line) { | |
1120 | /* not an appropriate terminal */ | |
1121 | if (!quiet) | |
1122 | fprintf(stderr, "sysline: no status capability for %s\n", | |
1123 | getenv("TERM")); | |
1124 | exit(1); | |
1125 | } | |
1126 | if (window || status_line_esc_ok) { | |
1127 | if (set_attributes) { | |
1128 | /* reverse video mode */ | |
1129 | strcpy(standbuf, | |
1130 | tparm(set_attributes,0,0,1,0,0,0,0,0,0)); | |
1131 | rev_out = standbuf; | |
1132 | rev_end = exit_attribute_mode; | |
1133 | } else if (enter_standout_mode && exit_standout_mode) { | |
1134 | rev_out = enter_standout_mode; | |
1135 | rev_end = exit_standout_mode; | |
1136 | } else | |
1137 | rev_out = rev_end = ""; | |
1138 | } else | |
1139 | rev_out = rev_end = ""; | |
1140 | columns--; /* avoid cursor wraparound */ | |
1141 | } | |
1142 | ||
1143 | #else /* TERMCAP */ | |
1144 | ||
1145 | initterm() | |
1146 | { | |
1147 | char *term, *cp; | |
1148 | static char tbuf[1024]; | |
1149 | char is2[40]; | |
1150 | extern char *UP; | |
1151 | ||
1152 | if ((term = getenv("TERM")) == NULL) { | |
1153 | if (!quiet) | |
1154 | fprintf(stderr, | |
1155 | "sysline: No TERM variable in enviroment\n"); | |
1156 | exit(1); | |
1157 | } | |
1158 | if (tgetent(tbuf, term) <= 0) { | |
1159 | if (!quiet) | |
1160 | fprintf(stderr, | |
1161 | "sysline: Unknown terminal type: %s\n", term); | |
1162 | exit(1); | |
1163 | } | |
1164 | if (!window && tgetflag("hs") <= 0) { | |
1165 | if (!strncmp(term, "h19", 3)) { | |
1166 | /* for upward compatability with h19sys */ | |
1167 | strcpy(to_status_line, | |
1168 | "\033j\033x5\033x1\033Y8%+ \033o"); | |
1169 | strcpy(from_status_line, "\033k\033y5"); | |
1170 | strcpy(dis_status_line, "\033y1"); | |
1171 | strcpy(rev_out, "\033p"); | |
1172 | strcpy(rev_end, "\033q"); | |
1173 | arrows = "\033Fhh\033G"; | |
1174 | columns = 80; | |
1175 | UP = "\b"; | |
1176 | return; | |
1177 | } | |
1178 | if (!quiet) | |
1179 | fprintf(stderr, | |
1180 | "sysline: No status capability for %s\n", term); | |
1181 | exit(1); | |
1182 | } | |
1183 | cp = is2; | |
1184 | if (tgetstr("i2", &cp) != NULL) { | |
1185 | /* someday tset will do this */ | |
1186 | tputs(is2, 1, erroutc); | |
1187 | fflush(stdout); | |
1188 | } | |
1189 | ||
1190 | /* the "-1" below is to avoid cursor wraparound problems */ | |
42f1384d | 1191 | columns = tgetnum("ws"); |
f9e4427b KB |
1192 | hasws = columns >= 0; |
1193 | if (!hasws) | |
42f1384d KB |
1194 | columns = tgetnum("co"); |
1195 | columns -= 1; | |
e1e8d3ca KM |
1196 | if (window) { |
1197 | strcpy(to_status_line, "\r"); | |
e1e8d3ca KM |
1198 | cp = dis_status_line; /* use the clear line sequence */ |
1199 | *cp++ = '\r'; | |
1200 | tgetstr("ce", &cp); | |
e2e4d5a4 MK |
1201 | if (leftline) |
1202 | strcpy(from_status_line, dis_status_line + 1); | |
1203 | else | |
1204 | strcpy(from_status_line, ""); | |
e1e8d3ca KM |
1205 | } else { |
1206 | cp = to_status_line; | |
1207 | tgetstr("ts", &cp); | |
1208 | cp = from_status_line; | |
1209 | tgetstr("fs", &cp); | |
1210 | cp = dis_status_line; | |
1211 | tgetstr("ds", &cp); | |
1212 | eslok = tgetflag("es"); | |
1213 | } | |
1214 | if (eslok || window) { | |
1215 | cp = rev_out; | |
1216 | tgetstr("so", &cp); | |
1217 | cp = rev_end; | |
1218 | tgetstr("se", &cp); | |
1219 | cp = clr_eol; | |
1220 | tgetstr("ce", &cp); | |
1221 | } else | |
1222 | reverse = 0; /* turn off reverse video */ | |
1223 | UP = "\b"; | |
1224 | if (!strncmp(term, "h19", 3)) | |
1225 | arrows = "\033Fhh\033G"; /* "two tiny graphic arrows" */ | |
1226 | else | |
1227 | arrows = "->"; | |
1228 | } | |
1229 | #endif TERMINFO | |
1230 | ||
1231 | #ifdef pdp11 | |
1232 | loadav(ap) | |
1233 | double ap[]; | |
1234 | { | |
1235 | register int i; | |
1236 | short s_avenrun[3]; | |
1237 | ||
1238 | lseek(kmem, (long)nl[NL_AVEN].n_value, 0); | |
1239 | read(kmem, s_avenrun, sizeof(s_avenrun)); | |
1240 | for (i=0; i < (sizeof(s_avenrun)/sizeof(s_avenrun[0])); i++) | |
1241 | ap[i] = s_avenrun[i] / 256.0; | |
1242 | } | |
1243 | #endif | |
1244 | ||
1245 | #ifdef RWHO | |
1246 | char * | |
1247 | sysrup(hp) | |
1248 | register struct remotehost *hp; | |
1249 | { | |
1250 | char filename[100]; | |
1251 | struct whod wd; | |
45ac4a67 | 1252 | #define WHOD_HDR_SIZE (sizeof (wd) - sizeof (wd.wd_we)) |
e1e8d3ca KM |
1253 | static char buffer[50]; |
1254 | time_t now; | |
1255 | ||
1256 | /* | |
1257 | * rh_file is initially 0. | |
1258 | * This is ok since standard input is assumed to exist. | |
1259 | */ | |
1260 | if (hp->rh_file == 0) { | |
1261 | /* | |
1262 | * Try rwho hostname file, and if that fails try ucbhostname. | |
1263 | */ | |
b528bd5e | 1264 | (void) strcpy1(strcpy1(filename, _PATH_RWHO), hp->rh_host); |
e1e8d3ca | 1265 | if ((hp->rh_file = open(filename, 0)) < 0) { |
b528bd5e | 1266 | (void) strcpy1(strcpy1(strcpy1(filename, _PATH_RWHO), |
e1e8d3ca KM |
1267 | NETPREFIX), hp->rh_host); |
1268 | hp->rh_file = open(filename, 0); | |
1269 | } | |
1270 | } | |
42f1384d KB |
1271 | if (hp->rh_file < 0) { |
1272 | (void) sprintf(buffer, "%s?", hp->rh_host); | |
1273 | return(buffer); | |
1274 | } | |
e1e8d3ca | 1275 | (void) lseek(hp->rh_file, (off_t)0, 0); |
42f1384d KB |
1276 | if (read(hp->rh_file, (char *)&wd, WHOD_HDR_SIZE) != WHOD_HDR_SIZE) { |
1277 | (void) sprintf(buffer, "%s ?", hp->rh_host); | |
1278 | return(buffer); | |
1279 | } | |
e1e8d3ca KM |
1280 | (void) time(&now); |
1281 | if (now - wd.wd_recvtime > DOWN_THRESHOLD) { | |
1282 | long interval; | |
1283 | long days, hours, minutes; | |
1284 | ||
1285 | interval = now - wd.wd_recvtime; | |
1286 | minutes = (interval + 59) / 60; /* round to minutes */ | |
1287 | hours = minutes / 60; /* extract hours from minutes */ | |
1288 | minutes %= 60; /* remove hours from minutes */ | |
1289 | days = hours / 24; /* extract days from hours */ | |
1290 | hours %= 24; /* remove days from hours */ | |
1291 | if (days > 7 || days < 0) | |
1292 | (void) sprintf(buffer, "%s down", hp->rh_host); | |
1293 | else if (days > 0) | |
1294 | (void) sprintf(buffer, "%s %d+%d:%02d", | |
1295 | hp->rh_host, days, hours, minutes); | |
1296 | else | |
1297 | (void) sprintf(buffer, "%s %d:%02d", | |
1298 | hp->rh_host, hours, minutes); | |
1299 | } else | |
1300 | (void) sprintf(buffer, "%s %.1f", | |
1301 | hp->rh_host, wd.wd_loadav[0]/100.0); | |
1302 | return buffer; | |
1303 | } | |
1304 | #endif RWHO | |
1305 | ||
1306 | getwinsize() | |
1307 | { | |
1308 | #ifdef TIOCGWINSZ | |
1309 | struct winsize winsize; | |
1310 | ||
1311 | /* the "-1" below is to avoid cursor wraparound problems */ | |
f9e4427b KB |
1312 | if (!hasws && ioctl(2, TIOCGWINSZ, (char *)&winsize) >= 0 && |
1313 | winsize.ws_col != 0) | |
e1e8d3ca KM |
1314 | columns = winsize.ws_col - 1; |
1315 | #endif | |
1316 | } | |
1317 | ||
1318 | #ifdef SIGWINCH | |
1319 | sigwinch() | |
1320 | { | |
1321 | winchanged++; | |
1322 | } | |
1323 | #endif | |
1324 | ||
1325 | char * | |
1326 | strcpy1(p, q) | |
1327 | register char *p, *q; | |
1328 | { | |
1329 | ||
1330 | while (*p++ = *q++) | |
1331 | ; | |
1332 | return p - 1; | |
1333 | } | |
1334 | ||
1335 | outc(c) | |
1336 | char c; | |
1337 | { | |
1338 | if (dbug) | |
1339 | printf("%s", unctrl(c)); | |
1340 | else | |
1341 | putchar(c); | |
1342 | } | |
1343 | ||
1344 | erroutc(c) | |
1345 | char c; | |
1346 | { | |
1347 | if (dbug) | |
1348 | fprintf(stderr, "%s", unctrl(c)); | |
1349 | else | |
1350 | putc(c, stderr); | |
1351 | } |