1 | char *copyright = |
---|
2 | "Copyright (c) 1984 through 1996, William LeFebvre"; |
---|
3 | |
---|
4 | /* |
---|
5 | * Top users/processes display for Unix |
---|
6 | * Version 3 |
---|
7 | * |
---|
8 | * This program may be freely redistributed, |
---|
9 | * but this entire comment MUST remain intact. |
---|
10 | * |
---|
11 | * Copyright (c) 1984, 1989, William LeFebvre, Rice University |
---|
12 | * Copyright (c) 1989 - 1994, William LeFebvre, Northwestern University |
---|
13 | * Copyright (c) 1994, 1995, William LeFebvre, Argonne National Laboratory |
---|
14 | * Copyright (c) 1996, William LeFebvre, Group sys Consulting |
---|
15 | */ |
---|
16 | |
---|
17 | /* |
---|
18 | * See the file "Changes" for information on version-to-version changes. |
---|
19 | */ |
---|
20 | |
---|
21 | /* |
---|
22 | * This file contains "main" and other high-level routines. |
---|
23 | */ |
---|
24 | |
---|
25 | /* |
---|
26 | * The following preprocessor variables, when defined, are used to |
---|
27 | * distinguish between different Unix implementations: |
---|
28 | * |
---|
29 | * SIGHOLD - use SVR4 sighold function when defined |
---|
30 | * SIGRELSE - use SVR4 sigrelse function when defined |
---|
31 | * FD_SET - macros FD_SET and FD_ZERO are used when defined |
---|
32 | */ |
---|
33 | |
---|
34 | #include "os.h" |
---|
35 | #include <signal.h> |
---|
36 | #include <setjmp.h> |
---|
37 | #include <ctype.h> |
---|
38 | #include <sys/time.h> |
---|
39 | |
---|
40 | /* includes specific to top */ |
---|
41 | #include "display.h" /* interface to display package */ |
---|
42 | #include "screen.h" /* interface to screen package */ |
---|
43 | #include "top.h" |
---|
44 | #include "top.local.h" |
---|
45 | #include "boolean.h" |
---|
46 | #include "machine.h" |
---|
47 | #include "utils.h" |
---|
48 | |
---|
49 | /* Size of the stdio buffer given to stdout */ |
---|
50 | #define Buffersize 2048 |
---|
51 | |
---|
52 | /* The buffer that stdio will use */ |
---|
53 | char stdoutbuf[Buffersize]; |
---|
54 | |
---|
55 | /* build Signal masks */ |
---|
56 | #define Smask(s) (1 << ((s) - 1)) |
---|
57 | |
---|
58 | /* for getopt: */ |
---|
59 | extern int optind; |
---|
60 | extern char *optarg; |
---|
61 | |
---|
62 | /* imported from screen.c */ |
---|
63 | extern int overstrike; |
---|
64 | |
---|
65 | /* signal handling routines */ |
---|
66 | sigret_t leave(); |
---|
67 | sigret_t onalrm(); |
---|
68 | sigret_t tstop(); |
---|
69 | #ifdef SIGWINCH |
---|
70 | sigret_t winch(); |
---|
71 | #endif |
---|
72 | |
---|
73 | /* internal routines */ |
---|
74 | void quit(); |
---|
75 | |
---|
76 | /* values which need to be accessed by signal handlers */ |
---|
77 | static int max_topn; /* maximum displayable processes */ |
---|
78 | |
---|
79 | /* miscellaneous things */ |
---|
80 | char *myname = "top"; |
---|
81 | jmp_buf jmp_int; |
---|
82 | |
---|
83 | /* routines that don't return int */ |
---|
84 | |
---|
85 | char *username(); |
---|
86 | char *ctime(); |
---|
87 | char *kill_procs(); |
---|
88 | char *renice_procs(); |
---|
89 | |
---|
90 | #ifdef ORDER |
---|
91 | extern int (*proc_compares[])(); |
---|
92 | #else |
---|
93 | extern int proc_compare(); |
---|
94 | #endif |
---|
95 | time_t time(); |
---|
96 | |
---|
97 | caddr_t get_process_info(); |
---|
98 | |
---|
99 | /* different routines for displaying the user's identification */ |
---|
100 | /* (values assigned to get_userid) */ |
---|
101 | char *username(); |
---|
102 | char *itoa7(); |
---|
103 | |
---|
104 | /* display routines that need to be predeclared */ |
---|
105 | int i_loadave(); |
---|
106 | int u_loadave(); |
---|
107 | int i_procstates(); |
---|
108 | int u_procstates(); |
---|
109 | int i_cpustates(); |
---|
110 | int u_cpustates(); |
---|
111 | int i_memory(); |
---|
112 | int u_memory(); |
---|
113 | int i_message(); |
---|
114 | int u_message(); |
---|
115 | int i_header(); |
---|
116 | int u_header(); |
---|
117 | int i_process(); |
---|
118 | int u_process(); |
---|
119 | |
---|
120 | /* pointers to display routines */ |
---|
121 | int (*d_loadave)() = i_loadave; |
---|
122 | int (*d_procstates)() = i_procstates; |
---|
123 | int (*d_cpustates)() = i_cpustates; |
---|
124 | int (*d_memory)() = i_memory; |
---|
125 | int (*d_message)() = i_message; |
---|
126 | int (*d_header)() = i_header; |
---|
127 | int (*d_process)() = i_process; |
---|
128 | |
---|
129 | |
---|
130 | main(argc, argv) |
---|
131 | |
---|
132 | int argc; |
---|
133 | char *argv[]; |
---|
134 | |
---|
135 | { |
---|
136 | register int i; |
---|
137 | register int active_procs; |
---|
138 | register int change; |
---|
139 | |
---|
140 | struct system_info system_info; |
---|
141 | struct statics statics; |
---|
142 | caddr_t processes; |
---|
143 | |
---|
144 | static char tempbuf1[50]; |
---|
145 | static char tempbuf2[50]; |
---|
146 | int old_sigmask; /* only used for BSD-style signals */ |
---|
147 | int topn = Default_TOPN; |
---|
148 | int delay = Default_DELAY; |
---|
149 | int displays = 0; /* indicates unspecified */ |
---|
150 | time_t curr_time; |
---|
151 | char *(*get_userid)() = username; |
---|
152 | char *uname_field = "USERNAME"; |
---|
153 | char *header_text; |
---|
154 | char *env_top; |
---|
155 | char **preset_argv; |
---|
156 | int preset_argc = 0; |
---|
157 | char **av; |
---|
158 | int ac; |
---|
159 | char dostates = No; |
---|
160 | char do_unames = Yes; |
---|
161 | char interactive = Maybe; |
---|
162 | char warnings = 0; |
---|
163 | #if Default_TOPN == Infinity |
---|
164 | char topn_specified = No; |
---|
165 | #endif |
---|
166 | char ch; |
---|
167 | char *iptr; |
---|
168 | char no_command = 1; |
---|
169 | struct timeval timeout; |
---|
170 | struct process_select ps; |
---|
171 | #ifdef ORDER |
---|
172 | char *order_name = NULL; |
---|
173 | int order_index = 0; |
---|
174 | #endif |
---|
175 | #ifndef FD_SET |
---|
176 | /* FD_SET and friends are not present: fake it */ |
---|
177 | typedef int fd_set; |
---|
178 | #define FD_ZERO(x) (*(x) = 0) |
---|
179 | #define FD_SET(f, x) (*(x) = 1<<f) |
---|
180 | #endif |
---|
181 | fd_set readfds; |
---|
182 | |
---|
183 | #ifdef ORDER |
---|
184 | static char command_chars[] = "\f qh?en#sdkriIuo"; |
---|
185 | #else |
---|
186 | static char command_chars[] = "\f qh?en#sdkriIu"; |
---|
187 | #endif |
---|
188 | /* these defines enumerate the "strchr"s of the commands in command_chars */ |
---|
189 | #define CMD_redraw 0 |
---|
190 | #define CMD_update 1 |
---|
191 | #define CMD_quit 2 |
---|
192 | #define CMD_help1 3 |
---|
193 | #define CMD_help2 4 |
---|
194 | #define CMD_OSLIMIT 4 /* terminals with OS can only handle commands */ |
---|
195 | #define CMD_errors 5 /* less than or equal to CMD_OSLIMIT */ |
---|
196 | #define CMD_number1 6 |
---|
197 | #define CMD_number2 7 |
---|
198 | #define CMD_delay 8 |
---|
199 | #define CMD_displays 9 |
---|
200 | #define CMD_kill 10 |
---|
201 | #define CMD_renice 11 |
---|
202 | #define CMD_idletog 12 |
---|
203 | #define CMD_idletog2 13 |
---|
204 | #define CMD_user 14 |
---|
205 | #ifdef ORDER |
---|
206 | #define CMD_order 15 |
---|
207 | #endif |
---|
208 | |
---|
209 | /* set the buffer for stdout */ |
---|
210 | #ifdef DEBUG |
---|
211 | extern FILE *debug; |
---|
212 | debug = fopen("debug.run", "w"); |
---|
213 | setbuffer(stdout, NULL, 0); |
---|
214 | #else |
---|
215 | setbuffer(stdout, stdoutbuf, Buffersize); |
---|
216 | #endif |
---|
217 | |
---|
218 | /* get our name */ |
---|
219 | if (argc > 0) |
---|
220 | { |
---|
221 | if ((myname = strrchr(argv[0], '/')) == 0) |
---|
222 | { |
---|
223 | myname = argv[0]; |
---|
224 | } |
---|
225 | else |
---|
226 | { |
---|
227 | myname++; |
---|
228 | } |
---|
229 | } |
---|
230 | |
---|
231 | /* initialize some selection options */ |
---|
232 | ps.idle = Yes; |
---|
233 | ps.system = No; |
---|
234 | ps.uid = -1; |
---|
235 | ps.command = NULL; |
---|
236 | |
---|
237 | /* get preset options from the environment */ |
---|
238 | if ((env_top = getenv("TOP")) != NULL) |
---|
239 | { |
---|
240 | av = preset_argv = argparse(env_top, &preset_argc); |
---|
241 | ac = preset_argc; |
---|
242 | |
---|
243 | /* set the dummy argument to an explanatory message, in case |
---|
244 | getopt encounters a bad argument */ |
---|
245 | preset_argv[0] = "while processing environment"; |
---|
246 | } |
---|
247 | |
---|
248 | /* process options */ |
---|
249 | do { |
---|
250 | /* if we're done doing the presets, then process the real arguments */ |
---|
251 | if (preset_argc == 0) |
---|
252 | { |
---|
253 | ac = argc; |
---|
254 | av = argv; |
---|
255 | |
---|
256 | /* this should keep getopt happy... */ |
---|
257 | optind = 1; |
---|
258 | } |
---|
259 | |
---|
260 | while ((i = getopt(ac, av, "SIbinquvs:d:U:o:")) != EOF) |
---|
261 | { |
---|
262 | switch(i) |
---|
263 | { |
---|
264 | case 'v': /* show version number */ |
---|
265 | fprintf(stderr, "%s: version %s\n", |
---|
266 | myname, version_string()); |
---|
267 | exit(1); |
---|
268 | break; |
---|
269 | |
---|
270 | case 'u': /* toggle uid/username display */ |
---|
271 | do_unames = !do_unames; |
---|
272 | break; |
---|
273 | |
---|
274 | case 'U': /* display only username's processes */ |
---|
275 | if ((ps.uid = userid(optarg)) == -1) |
---|
276 | { |
---|
277 | fprintf(stderr, "%s: unknown user\n", optarg); |
---|
278 | exit(1); |
---|
279 | } |
---|
280 | break; |
---|
281 | |
---|
282 | case 'S': /* show system processes */ |
---|
283 | ps.system = !ps.system; |
---|
284 | break; |
---|
285 | |
---|
286 | case 'I': /* show idle processes */ |
---|
287 | ps.idle = !ps.idle; |
---|
288 | break; |
---|
289 | |
---|
290 | case 'i': /* go interactive regardless */ |
---|
291 | interactive = Yes; |
---|
292 | break; |
---|
293 | |
---|
294 | case 'n': /* batch, or non-interactive */ |
---|
295 | case 'b': |
---|
296 | interactive = No; |
---|
297 | break; |
---|
298 | |
---|
299 | case 'd': /* number of displays to show */ |
---|
300 | if ((i = atoiwi(optarg)) == Invalid || i == 0) |
---|
301 | { |
---|
302 | fprintf(stderr, |
---|
303 | "%s: warning: display count should be positive -- option ignored\n", |
---|
304 | myname); |
---|
305 | warnings++; |
---|
306 | } |
---|
307 | else |
---|
308 | { |
---|
309 | displays = i; |
---|
310 | } |
---|
311 | break; |
---|
312 | |
---|
313 | case 's': |
---|
314 | if ((delay = atoi(optarg)) < 0 || (delay == 0 && getuid() != 0)) |
---|
315 | { |
---|
316 | fprintf(stderr, |
---|
317 | "%s: warning: seconds delay should be positive -- using default\n", |
---|
318 | myname); |
---|
319 | delay = Default_DELAY; |
---|
320 | warnings++; |
---|
321 | } |
---|
322 | break; |
---|
323 | |
---|
324 | case 'q': /* be quick about it */ |
---|
325 | /* only allow this if user is really root */ |
---|
326 | if (getuid() == 0) |
---|
327 | { |
---|
328 | /* be very un-nice! */ |
---|
329 | (void) nice(-20); |
---|
330 | } |
---|
331 | else |
---|
332 | { |
---|
333 | fprintf(stderr, |
---|
334 | "%s: warning: `-q' option can only be used by root\n", |
---|
335 | myname); |
---|
336 | warnings++; |
---|
337 | } |
---|
338 | break; |
---|
339 | |
---|
340 | case 'o': /* select sort order */ |
---|
341 | #ifdef ORDER |
---|
342 | order_name = optarg; |
---|
343 | #else |
---|
344 | fprintf(stderr, |
---|
345 | "%s: this platform does not support arbitrary ordering. Sorry.\n", |
---|
346 | myname); |
---|
347 | warnings++; |
---|
348 | #endif |
---|
349 | break; |
---|
350 | |
---|
351 | default: |
---|
352 | fprintf(stderr, "\ |
---|
353 | Top version %s\n\ |
---|
354 | Usage: %s [-ISbinqu] [-d x] [-s x] [-o field] [-U username] [number]\n", |
---|
355 | version_string(), myname); |
---|
356 | exit(1); |
---|
357 | } |
---|
358 | } |
---|
359 | |
---|
360 | /* get count of top processes to display (if any) */ |
---|
361 | if (optind < ac) |
---|
362 | { |
---|
363 | if ((topn = atoiwi(av[optind])) == Invalid) |
---|
364 | { |
---|
365 | fprintf(stderr, |
---|
366 | "%s: warning: process display count should be non-negative -- using default\n", |
---|
367 | myname); |
---|
368 | warnings++; |
---|
369 | } |
---|
370 | #if Default_TOPN == Infinity |
---|
371 | else |
---|
372 | { |
---|
373 | topn_specified = Yes; |
---|
374 | } |
---|
375 | #endif |
---|
376 | } |
---|
377 | |
---|
378 | /* tricky: remember old value of preset_argc & set preset_argc = 0 */ |
---|
379 | i = preset_argc; |
---|
380 | preset_argc = 0; |
---|
381 | |
---|
382 | /* repeat only if we really did the preset arguments */ |
---|
383 | } while (i != 0); |
---|
384 | |
---|
385 | /* set constants for username/uid display correctly */ |
---|
386 | if (!do_unames) |
---|
387 | { |
---|
388 | uname_field = " UID "; |
---|
389 | get_userid = itoa7; |
---|
390 | } |
---|
391 | |
---|
392 | /* initialize the kernel memory interface */ |
---|
393 | if (machine_init(&statics) == -1) |
---|
394 | { |
---|
395 | exit(1); |
---|
396 | } |
---|
397 | |
---|
398 | #ifdef ORDER |
---|
399 | /* determine sorting order index, if necessary */ |
---|
400 | if (order_name != NULL) |
---|
401 | { |
---|
402 | if ((order_index = string_index(order_name, statics.order_names)) == -1) |
---|
403 | { |
---|
404 | char **pp; |
---|
405 | |
---|
406 | fprintf(stderr, "%s: '%s' is not a recognized sorting order.\n", |
---|
407 | myname, order_name); |
---|
408 | fprintf(stderr, "\tTry one of these:"); |
---|
409 | pp = statics.order_names; |
---|
410 | while (*pp != NULL) |
---|
411 | { |
---|
412 | fprintf(stderr, " %s", *pp++); |
---|
413 | } |
---|
414 | fputc('\n', stderr); |
---|
415 | exit(1); |
---|
416 | } |
---|
417 | } |
---|
418 | #endif |
---|
419 | |
---|
420 | #ifdef no_initialization_needed |
---|
421 | /* initialize the hashing stuff */ |
---|
422 | if (do_unames) |
---|
423 | { |
---|
424 | init_hash(); |
---|
425 | } |
---|
426 | #endif |
---|
427 | |
---|
428 | /* initialize termcap */ |
---|
429 | init_termcap(interactive); |
---|
430 | |
---|
431 | /* get the string to use for the process area header */ |
---|
432 | header_text = format_header(uname_field); |
---|
433 | |
---|
434 | /* initialize display interface */ |
---|
435 | if ((max_topn = display_init(&statics)) == -1) |
---|
436 | { |
---|
437 | fprintf(stderr, "%s: can't allocate sufficient memory\n", myname); |
---|
438 | exit(4); |
---|
439 | } |
---|
440 | |
---|
441 | /* print warning if user requested more processes than we can display */ |
---|
442 | if (topn > max_topn) |
---|
443 | { |
---|
444 | fprintf(stderr, |
---|
445 | "%s: warning: this terminal can only display %d processes.\n", |
---|
446 | myname, max_topn); |
---|
447 | warnings++; |
---|
448 | } |
---|
449 | |
---|
450 | /* adjust for topn == Infinity */ |
---|
451 | if (topn == Infinity) |
---|
452 | { |
---|
453 | /* |
---|
454 | * For smart terminals, infinity really means everything that can |
---|
455 | * be displayed, or Largest. |
---|
456 | * On dumb terminals, infinity means every process in the system! |
---|
457 | * We only really want to do that if it was explicitly specified. |
---|
458 | * This is always the case when "Default_TOPN != Infinity". But if |
---|
459 | * topn wasn't explicitly specified and we are on a dumb terminal |
---|
460 | * and the default is Infinity, then (and only then) we use |
---|
461 | * "Nominal_TOPN" instead. |
---|
462 | */ |
---|
463 | #if Default_TOPN == Infinity |
---|
464 | topn = smart_terminal ? Largest : |
---|
465 | (topn_specified ? Largest : Nominal_TOPN); |
---|
466 | #else |
---|
467 | topn = Largest; |
---|
468 | #endif |
---|
469 | } |
---|
470 | |
---|
471 | /* set header display accordingly */ |
---|
472 | display_header(topn > 0); |
---|
473 | |
---|
474 | /* determine interactive state */ |
---|
475 | if (interactive == Maybe) |
---|
476 | { |
---|
477 | interactive = smart_terminal; |
---|
478 | } |
---|
479 | |
---|
480 | /* if # of displays not specified, fill it in */ |
---|
481 | if (displays == 0) |
---|
482 | { |
---|
483 | displays = smart_terminal ? Infinity : 1; |
---|
484 | } |
---|
485 | |
---|
486 | /* hold interrupt signals while setting up the screen and the handlers */ |
---|
487 | #ifdef SIGHOLD |
---|
488 | sighold(SIGINT); |
---|
489 | sighold(SIGQUIT); |
---|
490 | sighold(SIGTSTP); |
---|
491 | #else |
---|
492 | old_sigmask = sigblock(Smask(SIGINT) | Smask(SIGQUIT) | Smask(SIGTSTP)); |
---|
493 | #endif |
---|
494 | init_screen(); |
---|
495 | (void) signal(SIGINT, leave); |
---|
496 | (void) signal(SIGQUIT, leave); |
---|
497 | (void) signal(SIGTSTP, tstop); |
---|
498 | #ifdef SIGWINCH |
---|
499 | (void) signal(SIGWINCH, winch); |
---|
500 | #endif |
---|
501 | #ifdef SIGRELSE |
---|
502 | sigrelse(SIGINT); |
---|
503 | sigrelse(SIGQUIT); |
---|
504 | sigrelse(SIGTSTP); |
---|
505 | #else |
---|
506 | (void) sigsetmask(old_sigmask); |
---|
507 | #endif |
---|
508 | if (warnings) |
---|
509 | { |
---|
510 | fputs("....", stderr); |
---|
511 | fflush(stderr); /* why must I do this? */ |
---|
512 | sleep((unsigned)(3 * warnings)); |
---|
513 | fputc('\n', stderr); |
---|
514 | } |
---|
515 | |
---|
516 | /* setup the jump buffer for stops */ |
---|
517 | if (setjmp(jmp_int) != 0) |
---|
518 | { |
---|
519 | /* control ends up here after an interrupt */ |
---|
520 | reset_display(); |
---|
521 | } |
---|
522 | |
---|
523 | /* |
---|
524 | * main loop -- repeat while display count is positive or while it |
---|
525 | * indicates infinity (by being -1) |
---|
526 | */ |
---|
527 | |
---|
528 | while ((displays == -1) || (displays-- > 0)) |
---|
529 | { |
---|
530 | /* get the current stats */ |
---|
531 | get_system_info(&system_info); |
---|
532 | |
---|
533 | /* get the current set of processes */ |
---|
534 | processes = |
---|
535 | get_process_info(&system_info, |
---|
536 | &ps, |
---|
537 | #ifdef ORDER |
---|
538 | proc_compares[order_index]); |
---|
539 | #else |
---|
540 | proc_compare); |
---|
541 | #endif |
---|
542 | |
---|
543 | /* display the load averages */ |
---|
544 | (*d_loadave)(system_info.last_pid, |
---|
545 | system_info.load_avg); |
---|
546 | |
---|
547 | /* display the current time */ |
---|
548 | /* this method of getting the time SHOULD be fairly portable */ |
---|
549 | time(&curr_time); |
---|
550 | i_timeofday(&curr_time); |
---|
551 | |
---|
552 | /* display process state breakdown */ |
---|
553 | (*d_procstates)(system_info.p_total, |
---|
554 | system_info.procstates); |
---|
555 | |
---|
556 | /* display the cpu state percentage breakdown */ |
---|
557 | if (dostates) /* but not the first time */ |
---|
558 | { |
---|
559 | (*d_cpustates)(system_info.cpustates); |
---|
560 | } |
---|
561 | else |
---|
562 | { |
---|
563 | /* we'll do it next time */ |
---|
564 | if (smart_terminal) |
---|
565 | { |
---|
566 | z_cpustates(); |
---|
567 | } |
---|
568 | else |
---|
569 | { |
---|
570 | putchar('\n'); |
---|
571 | } |
---|
572 | dostates = Yes; |
---|
573 | } |
---|
574 | |
---|
575 | /* display memory stats */ |
---|
576 | (*d_memory)(system_info.memory); |
---|
577 | |
---|
578 | /* handle message area */ |
---|
579 | (*d_message)(); |
---|
580 | |
---|
581 | /* update the header area */ |
---|
582 | (*d_header)(header_text); |
---|
583 | |
---|
584 | if (topn > 0) |
---|
585 | { |
---|
586 | /* determine number of processes to actually display */ |
---|
587 | /* this number will be the smallest of: active processes, |
---|
588 | number user requested, number current screen accomodates */ |
---|
589 | active_procs = system_info.P_ACTIVE; |
---|
590 | if (active_procs > topn) |
---|
591 | { |
---|
592 | active_procs = topn; |
---|
593 | } |
---|
594 | if (active_procs > max_topn) |
---|
595 | { |
---|
596 | active_procs = max_topn; |
---|
597 | } |
---|
598 | |
---|
599 | /* now show the top "n" processes. */ |
---|
600 | for (i = 0; i < active_procs; i++) |
---|
601 | { |
---|
602 | (*d_process)(i, format_next_process(processes, get_userid)); |
---|
603 | } |
---|
604 | } |
---|
605 | else |
---|
606 | { |
---|
607 | i = 0; |
---|
608 | } |
---|
609 | |
---|
610 | /* do end-screen processing */ |
---|
611 | u_endscreen(i); |
---|
612 | |
---|
613 | /* now, flush the output buffer */ |
---|
614 | if (fflush(stdout) != 0) |
---|
615 | { |
---|
616 | new_message(MT_standout, " Write error on stdout"); |
---|
617 | putchar('\r'); |
---|
618 | quit(1); |
---|
619 | /*NOTREACHED*/ |
---|
620 | } |
---|
621 | |
---|
622 | /* only do the rest if we have more displays to show */ |
---|
623 | if (displays) |
---|
624 | { |
---|
625 | /* switch out for new display on smart terminals */ |
---|
626 | if (smart_terminal) |
---|
627 | { |
---|
628 | if (overstrike) |
---|
629 | { |
---|
630 | reset_display(); |
---|
631 | } |
---|
632 | else |
---|
633 | { |
---|
634 | d_loadave = u_loadave; |
---|
635 | d_procstates = u_procstates; |
---|
636 | d_cpustates = u_cpustates; |
---|
637 | d_memory = u_memory; |
---|
638 | d_message = u_message; |
---|
639 | d_header = u_header; |
---|
640 | d_process = u_process; |
---|
641 | } |
---|
642 | } |
---|
643 | |
---|
644 | no_command = Yes; |
---|
645 | if (!interactive) |
---|
646 | { |
---|
647 | /* set up alarm */ |
---|
648 | (void) signal(SIGALRM, onalrm); |
---|
649 | (void) alarm((unsigned)delay); |
---|
650 | |
---|
651 | /* wait for the rest of it .... */ |
---|
652 | pause(); |
---|
653 | } |
---|
654 | else while (no_command) |
---|
655 | { |
---|
656 | /* assume valid command unless told otherwise */ |
---|
657 | no_command = No; |
---|
658 | |
---|
659 | /* set up arguments for select with timeout */ |
---|
660 | FD_ZERO(&readfds); |
---|
661 | FD_SET(0, &readfds); /* for standard input */ |
---|
662 | timeout.tv_sec = delay; |
---|
663 | timeout.tv_usec = 0; |
---|
664 | |
---|
665 | /* wait for either input or the end of the delay period */ |
---|
666 | if (select(32, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timeout) > 0) |
---|
667 | { |
---|
668 | int newval; |
---|
669 | char *errmsg; |
---|
670 | |
---|
671 | /* something to read -- clear the message area first */ |
---|
672 | clear_message(); |
---|
673 | |
---|
674 | /* now read it and convert to command strchr */ |
---|
675 | /* (use "change" as a temporary to hold strchr) */ |
---|
676 | if (read(0, &ch, 1) != 1) |
---|
677 | { |
---|
678 | /* read error: either 0 or -1 */ |
---|
679 | new_message(MT_standout, " Read error on stdin"); |
---|
680 | putchar('\r'); |
---|
681 | quit(1); |
---|
682 | /*NOTREACHED*/ |
---|
683 | } |
---|
684 | if ((iptr = strchr(command_chars, ch)) == NULL) |
---|
685 | { |
---|
686 | /* illegal command */ |
---|
687 | new_message(MT_standout, " Command not understood"); |
---|
688 | putchar('\r'); |
---|
689 | no_command = Yes; |
---|
690 | } |
---|
691 | else |
---|
692 | { |
---|
693 | change = iptr - command_chars; |
---|
694 | if (overstrike && change > CMD_OSLIMIT) |
---|
695 | { |
---|
696 | /* error */ |
---|
697 | new_message(MT_standout, |
---|
698 | " Command cannot be handled by this terminal"); |
---|
699 | putchar('\r'); |
---|
700 | no_command = Yes; |
---|
701 | } |
---|
702 | else switch(change) |
---|
703 | { |
---|
704 | case CMD_redraw: /* redraw screen */ |
---|
705 | reset_display(); |
---|
706 | break; |
---|
707 | |
---|
708 | case CMD_update: /* merely update display */ |
---|
709 | /* is the load average high? */ |
---|
710 | if (system_info.load_avg[0] > LoadMax) |
---|
711 | { |
---|
712 | /* yes, go home for visual feedback */ |
---|
713 | go_home(); |
---|
714 | fflush(stdout); |
---|
715 | } |
---|
716 | break; |
---|
717 | |
---|
718 | case CMD_quit: /* quit */ |
---|
719 | quit(0); |
---|
720 | /*NOTREACHED*/ |
---|
721 | break; |
---|
722 | |
---|
723 | case CMD_help1: /* help */ |
---|
724 | case CMD_help2: |
---|
725 | reset_display(); |
---|
726 | clear(); |
---|
727 | show_help(); |
---|
728 | standout("Hit any key to continue: "); |
---|
729 | fflush(stdout); |
---|
730 | (void) read(0, &ch, 1); |
---|
731 | break; |
---|
732 | |
---|
733 | case CMD_errors: /* show errors */ |
---|
734 | if (error_count() == 0) |
---|
735 | { |
---|
736 | new_message(MT_standout, |
---|
737 | " Currently no errors to report."); |
---|
738 | putchar('\r'); |
---|
739 | no_command = Yes; |
---|
740 | } |
---|
741 | else |
---|
742 | { |
---|
743 | reset_display(); |
---|
744 | clear(); |
---|
745 | show_errors(); |
---|
746 | standout("Hit any key to continue: "); |
---|
747 | fflush(stdout); |
---|
748 | (void) read(0, &ch, 1); |
---|
749 | } |
---|
750 | break; |
---|
751 | |
---|
752 | case CMD_number1: /* new number */ |
---|
753 | case CMD_number2: |
---|
754 | new_message(MT_standout, |
---|
755 | "Number of processes to show: "); |
---|
756 | newval = readline(tempbuf1, 8, Yes); |
---|
757 | if (newval > -1) |
---|
758 | { |
---|
759 | if (newval > max_topn) |
---|
760 | { |
---|
761 | new_message(MT_standout | MT_delayed, |
---|
762 | " This terminal can only display %d processes.", |
---|
763 | max_topn); |
---|
764 | putchar('\r'); |
---|
765 | } |
---|
766 | |
---|
767 | if (newval == 0) |
---|
768 | { |
---|
769 | /* inhibit the header */ |
---|
770 | display_header(No); |
---|
771 | } |
---|
772 | else if (newval > topn && topn == 0) |
---|
773 | { |
---|
774 | /* redraw the header */ |
---|
775 | display_header(Yes); |
---|
776 | d_header = i_header; |
---|
777 | } |
---|
778 | topn = newval; |
---|
779 | } |
---|
780 | break; |
---|
781 | |
---|
782 | case CMD_delay: /* new seconds delay */ |
---|
783 | new_message(MT_standout, "Seconds to delay: "); |
---|
784 | if ((i = readline(tempbuf1, 8, Yes)) > -1) |
---|
785 | { |
---|
786 | if ((delay = i) == 0 && getuid() != 0) |
---|
787 | { |
---|
788 | delay = 1; |
---|
789 | } |
---|
790 | } |
---|
791 | clear_message(); |
---|
792 | break; |
---|
793 | |
---|
794 | case CMD_displays: /* change display count */ |
---|
795 | new_message(MT_standout, |
---|
796 | "Displays to show (currently %s): ", |
---|
797 | displays == -1 ? "infinite" : |
---|
798 | itoa(displays)); |
---|
799 | if ((i = readline(tempbuf1, 10, Yes)) > 0) |
---|
800 | { |
---|
801 | displays = i; |
---|
802 | } |
---|
803 | else if (i == 0) |
---|
804 | { |
---|
805 | quit(0); |
---|
806 | } |
---|
807 | clear_message(); |
---|
808 | break; |
---|
809 | |
---|
810 | case CMD_kill: /* kill program */ |
---|
811 | new_message(0, "kill "); |
---|
812 | if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) |
---|
813 | { |
---|
814 | if ((errmsg = kill_procs(tempbuf2)) != NULL) |
---|
815 | { |
---|
816 | new_message(MT_standout, errmsg); |
---|
817 | putchar('\r'); |
---|
818 | no_command = Yes; |
---|
819 | } |
---|
820 | } |
---|
821 | else |
---|
822 | { |
---|
823 | clear_message(); |
---|
824 | } |
---|
825 | break; |
---|
826 | |
---|
827 | case CMD_renice: /* renice program */ |
---|
828 | new_message(0, "renice "); |
---|
829 | if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) |
---|
830 | { |
---|
831 | if ((errmsg = renice_procs(tempbuf2)) != NULL) |
---|
832 | { |
---|
833 | new_message(MT_standout, errmsg); |
---|
834 | putchar('\r'); |
---|
835 | no_command = Yes; |
---|
836 | } |
---|
837 | } |
---|
838 | else |
---|
839 | { |
---|
840 | clear_message(); |
---|
841 | } |
---|
842 | break; |
---|
843 | |
---|
844 | case CMD_idletog: |
---|
845 | case CMD_idletog2: |
---|
846 | ps.idle = !ps.idle; |
---|
847 | new_message(MT_standout | MT_delayed, |
---|
848 | " %sisplaying idle processes.", |
---|
849 | ps.idle ? "D" : "Not d"); |
---|
850 | putchar('\r'); |
---|
851 | break; |
---|
852 | |
---|
853 | case CMD_user: |
---|
854 | new_message(MT_standout, |
---|
855 | "Username to show: "); |
---|
856 | if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) |
---|
857 | { |
---|
858 | if (tempbuf2[0] == '+' && |
---|
859 | tempbuf2[1] == '\0') |
---|
860 | { |
---|
861 | ps.uid = -1; |
---|
862 | } |
---|
863 | else if ((i = userid(tempbuf2)) == -1) |
---|
864 | { |
---|
865 | new_message(MT_standout, |
---|
866 | " %s: unknown user", tempbuf2); |
---|
867 | no_command = Yes; |
---|
868 | } |
---|
869 | else |
---|
870 | { |
---|
871 | ps.uid = i; |
---|
872 | } |
---|
873 | putchar('\r'); |
---|
874 | } |
---|
875 | else |
---|
876 | { |
---|
877 | clear_message(); |
---|
878 | } |
---|
879 | break; |
---|
880 | |
---|
881 | #ifdef ORDER |
---|
882 | case CMD_order: |
---|
883 | new_message(MT_standout, |
---|
884 | "Order to sort: "); |
---|
885 | if (readline(tempbuf2, sizeof(tempbuf2), No) > 0) |
---|
886 | { |
---|
887 | if ((i = string_index(tempbuf2, statics.order_names)) == -1) |
---|
888 | { |
---|
889 | new_message(MT_standout, |
---|
890 | " %s: unrecognized sorting order", tempbuf2); |
---|
891 | no_command = Yes; |
---|
892 | } |
---|
893 | else |
---|
894 | { |
---|
895 | order_index = i; |
---|
896 | } |
---|
897 | putchar('\r'); |
---|
898 | } |
---|
899 | else |
---|
900 | { |
---|
901 | clear_message(); |
---|
902 | } |
---|
903 | break; |
---|
904 | #endif |
---|
905 | |
---|
906 | default: |
---|
907 | new_message(MT_standout, " BAD CASE IN SWITCH!"); |
---|
908 | putchar('\r'); |
---|
909 | } |
---|
910 | } |
---|
911 | |
---|
912 | /* flush out stuff that may have been written */ |
---|
913 | fflush(stdout); |
---|
914 | } |
---|
915 | } |
---|
916 | } |
---|
917 | } |
---|
918 | |
---|
919 | #ifdef DEBUG |
---|
920 | fclose(debug); |
---|
921 | #endif |
---|
922 | quit(0); |
---|
923 | /*NOTREACHED*/ |
---|
924 | } |
---|
925 | |
---|
926 | /* |
---|
927 | * reset_display() - reset all the display routine pointers so that entire |
---|
928 | * screen will get redrawn. |
---|
929 | */ |
---|
930 | |
---|
931 | reset_display() |
---|
932 | |
---|
933 | { |
---|
934 | d_loadave = i_loadave; |
---|
935 | d_procstates = i_procstates; |
---|
936 | d_cpustates = i_cpustates; |
---|
937 | d_memory = i_memory; |
---|
938 | d_message = i_message; |
---|
939 | d_header = i_header; |
---|
940 | d_process = i_process; |
---|
941 | } |
---|
942 | |
---|
943 | /* |
---|
944 | * signal handlers |
---|
945 | */ |
---|
946 | |
---|
947 | sigret_t leave() /* exit under normal conditions -- INT handler */ |
---|
948 | |
---|
949 | { |
---|
950 | end_screen(); |
---|
951 | exit(0); |
---|
952 | } |
---|
953 | |
---|
954 | sigret_t tstop(i) /* SIGTSTP handler */ |
---|
955 | |
---|
956 | int i; |
---|
957 | |
---|
958 | { |
---|
959 | /* move to the lower left */ |
---|
960 | end_screen(); |
---|
961 | fflush(stdout); |
---|
962 | |
---|
963 | /* default the signal handler action */ |
---|
964 | (void) signal(SIGTSTP, SIG_DFL); |
---|
965 | |
---|
966 | /* unblock the signal and send ourselves one */ |
---|
967 | #ifdef SIGRELSE |
---|
968 | sigrelse(SIGTSTP); |
---|
969 | #else |
---|
970 | (void) sigsetmask(sigblock(0) & ~(1 << (SIGTSTP - 1))); |
---|
971 | #endif |
---|
972 | (void) kill(0, SIGTSTP); |
---|
973 | |
---|
974 | /* reset the signal handler */ |
---|
975 | (void) signal(SIGTSTP, tstop); |
---|
976 | |
---|
977 | /* reinit screen */ |
---|
978 | reinit_screen(); |
---|
979 | |
---|
980 | /* jump to appropriate place */ |
---|
981 | longjmp(jmp_int, 1); |
---|
982 | |
---|
983 | /*NOTREACHED*/ |
---|
984 | } |
---|
985 | |
---|
986 | #ifdef SIGWINCH |
---|
987 | sigret_t winch(i) /* SIGWINCH handler */ |
---|
988 | |
---|
989 | int i; |
---|
990 | |
---|
991 | { |
---|
992 | /* reascertain the screen dimensions */ |
---|
993 | get_screensize(); |
---|
994 | |
---|
995 | /* tell display to resize */ |
---|
996 | max_topn = display_resize(); |
---|
997 | |
---|
998 | /* reset the signal handler */ |
---|
999 | (void) signal(SIGWINCH, winch); |
---|
1000 | |
---|
1001 | /* jump to appropriate place */ |
---|
1002 | longjmp(jmp_int, 1); |
---|
1003 | } |
---|
1004 | #endif |
---|
1005 | |
---|
1006 | void quit(status) /* exit under duress */ |
---|
1007 | |
---|
1008 | int status; |
---|
1009 | |
---|
1010 | { |
---|
1011 | end_screen(); |
---|
1012 | exit(status); |
---|
1013 | /*NOTREACHED*/ |
---|
1014 | } |
---|
1015 | |
---|
1016 | sigret_t onalrm() /* SIGALRM handler */ |
---|
1017 | |
---|
1018 | { |
---|
1019 | /* this is only used in batch mode to break out of the pause() */ |
---|
1020 | /* return; */ |
---|
1021 | } |
---|
1022 | |
---|