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