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