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