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