GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: top.c,v 1.88 2015/11/05 17:17:13 espie Exp $ */ |
||
2 |
|||
3 |
/* |
||
4 |
* Top users/processes display for Unix |
||
5 |
* Version 3 |
||
6 |
* |
||
7 |
* Copyright (c) 1984, 1989, William LeFebvre, Rice University |
||
8 |
* Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University |
||
9 |
* |
||
10 |
* Redistribution and use in source and binary forms, with or without |
||
11 |
* modification, are permitted provided that the following conditions |
||
12 |
* are met: |
||
13 |
* 1. Redistributions of source code must retain the above copyright |
||
14 |
* notice, this list of conditions and the following disclaimer. |
||
15 |
* 2. Redistributions in binary form must reproduce the above copyright |
||
16 |
* notice, this list of conditions and the following disclaimer in the |
||
17 |
* documentation and/or other materials provided with the distribution. |
||
18 |
* |
||
19 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
||
20 |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||
21 |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
||
22 |
* IN NO EVENT SHALL THE AUTHOR OR HIS EMPLOYER BE LIABLE FOR ANY DIRECT, INDIRECT, |
||
23 |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||
24 |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||
25 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||
26 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||
27 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
||
28 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||
29 |
*/ |
||
30 |
|||
31 |
#include <sys/types.h> |
||
32 |
#include <curses.h> |
||
33 |
#include <err.h> |
||
34 |
#include <errno.h> |
||
35 |
#include <stdio.h> |
||
36 |
#include <signal.h> |
||
37 |
#include <string.h> |
||
38 |
#include <poll.h> |
||
39 |
#include <stdlib.h> |
||
40 |
#include <limits.h> |
||
41 |
#include <unistd.h> |
||
42 |
|||
43 |
/* includes specific to top */ |
||
44 |
#include "display.h" /* interface to display package */ |
||
45 |
#include "screen.h" /* interface to screen package */ |
||
46 |
#include "top.h" |
||
47 |
#include "top.local.h" |
||
48 |
#include "boolean.h" |
||
49 |
#include "machine.h" |
||
50 |
#include "utils.h" |
||
51 |
|||
52 |
/* Size of the stdio buffer given to stdout */ |
||
53 |
#define BUFFERSIZE 2048 |
||
54 |
|||
55 |
/* The buffer that stdio will use */ |
||
56 |
char stdoutbuf[BUFFERSIZE]; |
||
57 |
|||
58 |
/* signal handling routines */ |
||
59 |
static void leave(int); |
||
60 |
static void onalrm(int); |
||
61 |
static void tstop(int); |
||
62 |
static void sigwinch(int); |
||
63 |
|||
64 |
volatile sig_atomic_t leaveflag, tstopflag, winchflag; |
||
65 |
|||
66 |
static void reset_display(void); |
||
67 |
int rundisplay(void); |
||
68 |
|||
69 |
static int max_topn; /* maximum displayable processes */ |
||
70 |
|||
71 |
extern int (*proc_compares[])(const void *, const void *); |
||
72 |
int order_index; |
||
73 |
|||
74 |
int displays = 0; /* indicates unspecified */ |
||
75 |
char do_unames = Yes; |
||
76 |
struct process_select ps; |
||
77 |
char interactive = Maybe; |
||
78 |
double delay = Default_DELAY; |
||
79 |
char *order_name = NULL; |
||
80 |
int topn = Default_TOPN; |
||
81 |
int no_command = Yes; |
||
82 |
int old_system = No; |
||
83 |
int old_threads = No; |
||
84 |
int show_args = No; |
||
85 |
pid_t hlpid = -1; |
||
86 |
int combine_cpus = 0; |
||
87 |
|||
88 |
#if Default_TOPN == Infinity |
||
89 |
char topn_specified = No; |
||
90 |
#endif |
||
91 |
|||
92 |
/* |
||
93 |
* these defines enumerate the "strchr"s of the commands in |
||
94 |
* command_chars |
||
95 |
*/ |
||
96 |
#define CMD_redraw 0 |
||
97 |
#define CMD_update 1 |
||
98 |
#define CMD_quit 2 |
||
99 |
#define CMD_help1 3 |
||
100 |
#define CMD_help2 4 |
||
101 |
#define CMD_OSLIMIT 4 /* terminals with OS can only handle commands */ |
||
102 |
#define CMD_errors 5 /* less than or equal to CMD_OSLIMIT */ |
||
103 |
#define CMD_number1 6 |
||
104 |
#define CMD_number2 7 |
||
105 |
#define CMD_delay 8 |
||
106 |
#define CMD_displays 9 |
||
107 |
#define CMD_kill 10 |
||
108 |
#define CMD_renice 11 |
||
109 |
#define CMD_idletog 12 |
||
110 |
#define CMD_idletog2 13 |
||
111 |
#define CMD_user 14 |
||
112 |
#define CMD_system 15 |
||
113 |
#define CMD_order 16 |
||
114 |
#define CMD_pid 17 |
||
115 |
#define CMD_command 18 |
||
116 |
#define CMD_threads 19 |
||
117 |
#define CMD_grep 20 |
||
118 |
#define CMD_add 21 |
||
119 |
#define CMD_hl 22 |
||
120 |
#define CMD_cpus 23 |
||
121 |
|||
122 |
static void |
||
123 |
usage(void) |
||
124 |
{ |
||
125 |
extern char *__progname; |
||
126 |
|||
127 |
fprintf(stderr, |
||
128 |
"usage: %s [-1bCHIinqSu] [-d count] [-g string] [-o field] " |
||
129 |
"[-p pid] [-s time]\n\t[-U [-]user] [number]\n", |
||
130 |
__progname); |
||
131 |
} |
||
132 |
|||
133 |
static void |
||
134 |
parseargs(int ac, char **av) |
||
135 |
1 |
{ |
|
136 |
char *endp; |
||
137 |
int i; |
||
138 |
|||
139 |
✗✓ | 2 |
while ((i = getopt(ac, av, "1SHICbinqus:d:p:U:o:g:")) != -1) { |
140 |
switch (i) { |
||
141 |
case '1': |
||
142 |
combine_cpus = 1; |
||
143 |
break; |
||
144 |
case 'C': |
||
145 |
show_args = Yes; |
||
146 |
break; |
||
147 |
case 'u': /* toggle uid/username display */ |
||
148 |
do_unames = !do_unames; |
||
149 |
break; |
||
150 |
|||
151 |
case 'U': /* display only username's processes */ |
||
152 |
if (optarg[0] == '-') { |
||
153 |
if ((ps.huid = userid(optarg+1)) == (uid_t)-1) |
||
154 |
new_message(MT_delayed, "%s: unknown user", |
||
155 |
optarg); |
||
156 |
else |
||
157 |
ps.uid = (uid_t)-1; |
||
158 |
} else if ((ps.uid = userid(optarg)) == (uid_t)-1) |
||
159 |
new_message(MT_delayed, "%s: unknown user", |
||
160 |
optarg); |
||
161 |
else |
||
162 |
ps.huid = (uid_t)-1; |
||
163 |
break; |
||
164 |
|||
165 |
case 'p': { /* display only process id */ |
||
166 |
const char *errstr; |
||
167 |
|||
168 |
i = strtonum(optarg, 0, INT_MAX, &errstr); |
||
169 |
if (errstr != NULL || !find_pid(i)) |
||
170 |
new_message(MT_delayed, "%s: unknown pid", |
||
171 |
optarg); |
||
172 |
else { |
||
173 |
ps.pid = (pid_t)i; |
||
174 |
ps.system = Yes; |
||
175 |
} |
||
176 |
break; |
||
177 |
} |
||
178 |
|||
179 |
case 'S': /* show system processes */ |
||
180 |
ps.system = !ps.system; |
||
181 |
old_system = !old_system; |
||
182 |
break; |
||
183 |
|||
184 |
case 'H': /* show threads */ |
||
185 |
ps.threads = Yes; |
||
186 |
old_threads = Yes; |
||
187 |
break; |
||
188 |
|||
189 |
case 'I': /* show idle processes */ |
||
190 |
ps.idle = !ps.idle; |
||
191 |
break; |
||
192 |
|||
193 |
case 'i': /* go interactive regardless */ |
||
194 |
interactive = Yes; |
||
195 |
break; |
||
196 |
|||
197 |
case 'n': /* batch, or non-interactive */ |
||
198 |
case 'b': |
||
199 |
interactive = No; |
||
200 |
break; |
||
201 |
|||
202 |
case 'd': /* number of displays to show */ |
||
203 |
if ((i = atoiwi(optarg)) != Invalid && i != 0) { |
||
204 |
displays = i; |
||
205 |
if (displays == 1) |
||
206 |
interactive = No; |
||
207 |
break; |
||
208 |
} |
||
209 |
new_message(MT_delayed, |
||
210 |
"warning: display count should be positive " |
||
211 |
"-- option ignored"); |
||
212 |
break; |
||
213 |
|||
214 |
case 's': |
||
215 |
delay = strtod(optarg, &endp); |
||
216 |
|||
217 |
if (delay >= 0 && delay <= 1000000 && *endp == '\0') |
||
218 |
break; |
||
219 |
|||
220 |
new_message(MT_delayed, |
||
221 |
"warning: delay should be a non-negative number" |
||
222 |
" -- using default"); |
||
223 |
delay = Default_DELAY; |
||
224 |
break; |
||
225 |
|||
226 |
case 'q': /* be quick about it */ |
||
227 |
/* only allow this if user is really root */ |
||
228 |
if (getuid() == 0) { |
||
229 |
/* be very un-nice! */ |
||
230 |
(void) nice(-20); |
||
231 |
break; |
||
232 |
} |
||
233 |
new_message(MT_delayed, |
||
234 |
"warning: `-q' option can only be used by root"); |
||
235 |
break; |
||
236 |
|||
237 |
case 'o': /* select sort order */ |
||
238 |
order_name = optarg; |
||
239 |
break; |
||
240 |
|||
241 |
case 'g': /* grep command name */ |
||
242 |
free(ps.command); |
||
243 |
if ((ps.command = strdup(optarg)) == NULL) |
||
244 |
err(1, NULL); |
||
245 |
break; |
||
246 |
|||
247 |
default: |
||
248 |
usage(); |
||
249 |
exit(1); |
||
250 |
} |
||
251 |
} |
||
252 |
|||
253 |
1 |
i = getncpu(); |
|
254 |
✗✓ | 1 |
if (i == -1) |
255 |
err(1, NULL); |
||
256 |
|||
257 |
✗✓ | 1 |
if (i > 8) |
258 |
combine_cpus = 1; |
||
259 |
|||
260 |
/* get count of top processes to display (if any) */ |
||
261 |
✗✓ | 1 |
if (optind < ac) { |
262 |
if ((topn = atoiwi(av[optind])) == Invalid) { |
||
263 |
new_message(MT_delayed, |
||
264 |
"warning: process count should " |
||
265 |
"be a non-negative number -- using default"); |
||
266 |
topn = Infinity; |
||
267 |
} |
||
268 |
#if Default_TOPN == Infinity |
||
269 |
else |
||
270 |
topn_specified = Yes; |
||
271 |
#endif |
||
272 |
} |
||
273 |
1 |
} |
|
274 |
|||
275 |
struct system_info system_info; |
||
276 |
struct statics statics; |
||
277 |
|||
278 |
int |
||
279 |
main(int argc, char *argv[]) |
||
280 |
1 |
{ |
|
281 |
1 |
char *uname_field = "USERNAME", *header_text, *env_top; |
|
282 |
1 |
char *(*get_userid)(uid_t) = username; |
|
283 |
1 |
char **preset_argv = NULL, **av = argv; |
|
284 |
1 |
int preset_argc = 0, ac = argc, active_procs, i; |
|
285 |
sigset_t mask, oldmask; |
||
286 |
time_t curr_time; |
||
287 |
caddr_t processes; |
||
288 |
|||
289 |
/* set the buffer for stdout */ |
||
290 |
#ifdef DEBUG |
||
291 |
setvbuf(stdout, NULL, _IONBUF, 0); |
||
292 |
#else |
||
293 |
1 |
setvbuf(stdout, stdoutbuf, _IOFBF, sizeof stdoutbuf); |
|
294 |
#endif |
||
295 |
|||
296 |
/* initialize some selection options */ |
||
297 |
1 |
ps.idle = Yes; |
|
298 |
1 |
ps.system = No; |
|
299 |
1 |
ps.uid = (uid_t)-1; |
|
300 |
1 |
ps.huid = (uid_t)-1; |
|
301 |
1 |
ps.pid = (pid_t)-1; |
|
302 |
1 |
ps.command = NULL; |
|
303 |
|||
304 |
/* get preset options from the environment */ |
||
305 |
✗✓ | 1 |
if ((env_top = getenv("TOP")) != NULL) { |
306 |
av = preset_argv = argparse(env_top, &preset_argc); |
||
307 |
ac = preset_argc; |
||
308 |
|||
309 |
/* |
||
310 |
* set the dummy argument to an explanatory message, in case |
||
311 |
* getopt encounters a bad argument |
||
312 |
*/ |
||
313 |
preset_argv[0] = "while processing environment"; |
||
314 |
} |
||
315 |
/* process options */ |
||
316 |
do { |
||
317 |
/* |
||
318 |
* if we're done doing the presets, then process the real |
||
319 |
* arguments |
||
320 |
*/ |
||
321 |
✓✗ | 1 |
if (preset_argc == 0) { |
322 |
1 |
ac = argc; |
|
323 |
1 |
av = argv; |
|
324 |
1 |
optind = 1; |
|
325 |
} |
||
326 |
1 |
parseargs(ac, av); |
|
327 |
1 |
i = preset_argc; |
|
328 |
1 |
preset_argc = 0; |
|
329 |
✗✓ | 1 |
} while (i != 0); |
330 |
|||
331 |
✗✓ | 1 |
if (pledge("stdio rpath getpw tty proc ps vminfo wpath cpath", NULL) == -1) |
332 |
err(1, "pledge"); |
||
333 |
|||
334 |
/* set constants for username/uid display correctly */ |
||
335 |
✗✓ | 1 |
if (!do_unames) { |
336 |
uname_field = " UID "; |
||
337 |
get_userid = format_uid; |
||
338 |
} |
||
339 |
/* initialize the kernel memory interface */ |
||
340 |
✗✓ | 1 |
if (machine_init(&statics) == -1) |
341 |
exit(1); |
||
342 |
|||
343 |
/* determine sorting order index, if necessary */ |
||
344 |
✗✓ | 1 |
if (order_name != NULL) { |
345 |
if ((order_index = string_index(order_name, |
||
346 |
statics.order_names)) == -1) { |
||
347 |
char **pp, msg[512]; |
||
348 |
|||
349 |
snprintf(msg, sizeof(msg), |
||
350 |
"'%s' is not a recognized sorting order", |
||
351 |
order_name); |
||
352 |
strlcat(msg, ". Valid are:", sizeof(msg)); |
||
353 |
pp = statics.order_names; |
||
354 |
while (*pp != NULL) { |
||
355 |
strlcat(msg, " ", sizeof(msg)); |
||
356 |
strlcat(msg, *pp++, sizeof(msg)); |
||
357 |
} |
||
358 |
new_message(MT_delayed, msg); |
||
359 |
order_index = 0; |
||
360 |
} |
||
361 |
} |
||
362 |
|||
363 |
/* initialize termcap */ |
||
364 |
1 |
init_termcap(interactive); |
|
365 |
|||
366 |
/* initialize display interface */ |
||
367 |
1 |
max_topn = display_init(&statics); |
|
368 |
|||
369 |
/* print warning if user requested more processes than we can display */ |
||
370 |
✗✓ | 1 |
if (topn > max_topn) |
371 |
new_message(MT_delayed, |
||
372 |
"warning: this terminal can only display %d processes", |
||
373 |
max_topn); |
||
374 |
/* adjust for topn == Infinity */ |
||
375 |
✓✗ | 1 |
if (topn == Infinity) { |
376 |
/* |
||
377 |
* For smart terminals, infinity really means everything that can |
||
378 |
* be displayed, or Largest. |
||
379 |
* On dumb terminals, infinity means every process in the system! |
||
380 |
* We only really want to do that if it was explicitly specified. |
||
381 |
* This is always the case when "Default_TOPN != Infinity". But if |
||
382 |
* topn wasn't explicitly specified and we are on a dumb terminal |
||
383 |
* and the default is Infinity, then (and only then) we use |
||
384 |
* "Nominal_TOPN" instead. |
||
385 |
*/ |
||
386 |
#if Default_TOPN == Infinity |
||
387 |
✗✓✗✗ |
1 |
topn = smart_terminal ? Largest : |
388 |
(topn_specified ? Largest : Nominal_TOPN); |
||
389 |
#else |
||
390 |
topn = Largest; |
||
391 |
#endif |
||
392 |
} |
||
393 |
/* set header display accordingly */ |
||
394 |
1 |
display_header(topn > 0); |
|
395 |
|||
396 |
/* determine interactive state */ |
||
397 |
✓✗ | 1 |
if (interactive == Maybe) |
398 |
1 |
interactive = smart_terminal; |
|
399 |
|||
400 |
/* if # of displays not specified, fill it in */ |
||
401 |
✓✗ | 1 |
if (displays == 0) |
402 |
✓✗ | 1 |
displays = smart_terminal ? Infinity : 1; |
403 |
|||
404 |
/* |
||
405 |
* block interrupt signals while setting up the screen and the |
||
406 |
* handlers |
||
407 |
*/ |
||
408 |
1 |
sigemptyset(&mask); |
|
409 |
1 |
sigaddset(&mask, SIGINT); |
|
410 |
1 |
sigaddset(&mask, SIGQUIT); |
|
411 |
1 |
sigaddset(&mask, SIGTSTP); |
|
412 |
1 |
sigprocmask(SIG_BLOCK, &mask, &oldmask); |
|
413 |
✓✗ | 1 |
if (interactive) |
414 |
1 |
init_screen(); |
|
415 |
1 |
(void) signal(SIGINT, leave); |
|
416 |
1 |
siginterrupt(SIGINT, 1); |
|
417 |
1 |
(void) signal(SIGQUIT, leave); |
|
418 |
1 |
(void) signal(SIGTSTP, tstop); |
|
419 |
✓✗ | 1 |
if (smart_terminal) |
420 |
1 |
(void) signal(SIGWINCH, sigwinch); |
|
421 |
1 |
sigprocmask(SIG_SETMASK, &oldmask, NULL); |
|
422 |
restart: |
||
423 |
|||
424 |
/* |
||
425 |
* main loop -- repeat while display count is positive or while it |
||
426 |
* indicates infinity (by being -1) |
||
427 |
*/ |
||
428 |
✓✗✗✗ |
2 |
while ((displays == -1) || (displays-- > 0)) { |
429 |
✗✓ | 2 |
if (winchflag) { |
430 |
/* |
||
431 |
* reascertain the screen |
||
432 |
* dimensions |
||
433 |
*/ |
||
434 |
get_screensize(); |
||
435 |
resizeterm(screen_length, screen_width + 1); |
||
436 |
|||
437 |
/* tell display to resize */ |
||
438 |
max_topn = display_resize(); |
||
439 |
|||
440 |
/* reset the signal handler */ |
||
441 |
(void) signal(SIGWINCH, sigwinch); |
||
442 |
|||
443 |
reset_display(); |
||
444 |
winchflag = 0; |
||
445 |
} |
||
446 |
|||
447 |
/* get the current stats */ |
||
448 |
2 |
get_system_info(&system_info); |
|
449 |
|||
450 |
/* get the current set of processes */ |
||
451 |
2 |
processes = get_process_info(&system_info, &ps, |
|
452 |
proc_compares[order_index]); |
||
453 |
|||
454 |
/* display the load averages */ |
||
455 |
2 |
i_loadave(system_info.last_pid, system_info.load_avg); |
|
456 |
|||
457 |
/* display the current time */ |
||
458 |
/* this method of getting the time SHOULD be fairly portable */ |
||
459 |
2 |
time(&curr_time); |
|
460 |
2 |
i_timeofday(&curr_time); |
|
461 |
|||
462 |
/* display process/threads state breakdown */ |
||
463 |
2 |
i_procstates(system_info.p_total, system_info.procstates, |
|
464 |
ps.threads); |
||
465 |
|||
466 |
/* display the cpu state percentage breakdown */ |
||
467 |
2 |
i_cpustates(system_info.cpustates); |
|
468 |
|||
469 |
/* display memory stats */ |
||
470 |
2 |
i_memory(system_info.memory); |
|
471 |
|||
472 |
/* handle message area */ |
||
473 |
2 |
i_message(); |
|
474 |
|||
475 |
/* get the string to use for the process area header */ |
||
476 |
2 |
header_text = format_header(uname_field, ps.threads); |
|
477 |
|||
478 |
/* update the header area */ |
||
479 |
2 |
i_header(header_text); |
|
480 |
|||
481 |
✗✓ | 2 |
if (topn == Infinity) { |
482 |
#if Default_TOPN == Infinity |
||
483 |
topn = smart_terminal ? Largest : |
||
484 |
(topn_specified ? Largest : Nominal_TOPN); |
||
485 |
#else |
||
486 |
topn = Largest; |
||
487 |
#endif |
||
488 |
} |
||
489 |
|||
490 |
✓✗ | 2 |
if (topn > 0) { |
491 |
/* determine number of processes to actually display */ |
||
492 |
/* |
||
493 |
* this number will be the smallest of: active |
||
494 |
* processes, number user requested, number current |
||
495 |
* screen accommodates |
||
496 |
*/ |
||
497 |
2 |
active_procs = system_info.p_active; |
|
498 |
✗✓ | 2 |
if (active_procs > topn) |
499 |
active_procs = topn; |
||
500 |
✓✗ | 2 |
if (active_procs > max_topn) |
501 |
2 |
active_procs = max_topn; |
|
502 |
/* now show the top "n" processes. */ |
||
503 |
✓✓ | 50 |
for (i = 0; i < active_procs; i++) { |
504 |
pid_t pid; |
||
505 |
char * s; |
||
506 |
|||
507 |
48 |
s = format_next_process(processes, get_userid, |
|
508 |
&pid, ps.threads); |
||
509 |
48 |
i_process(i, s, pid == hlpid); |
|
510 |
} |
||
511 |
} |
||
512 |
|||
513 |
/* do end-screen processing */ |
||
514 |
2 |
u_endscreen(); |
|
515 |
|||
516 |
/* now, flush the output buffer */ |
||
517 |
2 |
fflush(stdout); |
|
518 |
|||
519 |
✓✗ | 2 |
if (smart_terminal) |
520 |
2 |
refresh(); |
|
521 |
|||
522 |
/* only do the rest if we have more displays to show */ |
||
523 |
✓✗ | 2 |
if (displays) { |
524 |
/* switch out for new display on smart terminals */ |
||
525 |
2 |
no_command = Yes; |
|
526 |
✗✓ | 2 |
if (!interactive) { |
527 |
/* set up alarm */ |
||
528 |
(void) signal(SIGALRM, onalrm); |
||
529 |
(void) alarm((unsigned) delay); |
||
530 |
|||
531 |
/* wait for the rest of it .... */ |
||
532 |
pause(); |
||
533 |
if (leaveflag) |
||
534 |
exit(0); |
||
535 |
if (tstopflag) { |
||
536 |
(void) signal(SIGTSTP, SIG_DFL); |
||
537 |
(void) kill(0, SIGTSTP); |
||
538 |
/* reset the signal handler */ |
||
539 |
(void) signal(SIGTSTP, tstop); |
||
540 |
tstopflag = 0; |
||
541 |
} |
||
542 |
} else { |
||
543 |
✓✓ | 5 |
while (no_command) |
544 |
✗✓ | 4 |
if (rundisplay()) |
545 |
goto restart; |
||
546 |
} |
||
547 |
} |
||
548 |
} |
||
549 |
|||
550 |
quit(0); |
||
551 |
/* NOTREACHED */ |
||
552 |
return (0); |
||
553 |
} |
||
554 |
|||
555 |
int |
||
556 |
rundisplay(void) |
||
557 |
4 |
{ |
|
558 |
static char tempbuf[TEMPBUFSIZE]; |
||
559 |
sigset_t mask; |
||
560 |
char ch, *iptr; |
||
561 |
int change, i; |
||
562 |
struct pollfd pfd[1]; |
||
563 |
uid_t uid, huid; |
||
564 |
static char command_chars[] = "\f qh?en#sdkriIuSopCHg+P1"; |
||
565 |
|||
566 |
/* |
||
567 |
* assume valid command unless told |
||
568 |
* otherwise |
||
569 |
*/ |
||
570 |
4 |
no_command = No; |
|
571 |
|||
572 |
/* |
||
573 |
* set up arguments for select with |
||
574 |
* timeout |
||
575 |
*/ |
||
576 |
4 |
pfd[0].fd = STDIN_FILENO; |
|
577 |
4 |
pfd[0].events = POLLIN; |
|
578 |
|||
579 |
✗✓ | 4 |
if (leaveflag) |
580 |
quit(0); |
||
581 |
✗✓ | 4 |
if (tstopflag) { |
582 |
/* move to the lower left */ |
||
583 |
end_screen(); |
||
584 |
fflush(stdout); |
||
585 |
|||
586 |
/* |
||
587 |
* default the signal handler |
||
588 |
* action |
||
589 |
*/ |
||
590 |
(void) signal(SIGTSTP, SIG_DFL); |
||
591 |
|||
592 |
/* |
||
593 |
* unblock the signal and |
||
594 |
* send ourselves one |
||
595 |
*/ |
||
596 |
sigemptyset(&mask); |
||
597 |
sigaddset(&mask, SIGTSTP); |
||
598 |
sigprocmask(SIG_UNBLOCK, &mask, NULL); |
||
599 |
(void) kill(0, SIGTSTP); |
||
600 |
|||
601 |
/* reset the signal handler */ |
||
602 |
(void) signal(SIGTSTP, tstop); |
||
603 |
|||
604 |
/* reinit screen */ |
||
605 |
reinit_screen(); |
||
606 |
reset_display(); |
||
607 |
tstopflag = 0; |
||
608 |
return 1; |
||
609 |
} |
||
610 |
/* |
||
611 |
* wait for either input or the end |
||
612 |
* of the delay period |
||
613 |
*/ |
||
614 |
✓✗ | 4 |
if (poll(pfd, 1, (int)(delay * 1000)) > 0) { |
615 |
char *errmsg; |
||
616 |
ssize_t len; |
||
617 |
|||
618 |
✗✓ | 4 |
if ((pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL))) |
619 |
exit(1); |
||
620 |
|||
621 |
4 |
clear_message(); |
|
622 |
|||
623 |
/* |
||
624 |
* now read it and convert to |
||
625 |
* command strchr |
||
626 |
*/ |
||
627 |
while (1) { |
||
628 |
4 |
len = read(STDIN_FILENO, &ch, 1); |
|
629 |
✗✓✗✗ |
4 |
if (len == -1 && errno == EINTR) |
630 |
continue; |
||
631 |
✗✓ | 4 |
if (len == 0) |
632 |
exit(1); |
||
633 |
break; |
||
634 |
} |
||
635 |
✓✓ | 4 |
if ((iptr = strchr(command_chars, ch)) == NULL) { |
636 |
/* illegal command */ |
||
637 |
2 |
new_message(MT_standout, " Command not understood"); |
|
638 |
✗✓✗✗ ✗✗ |
2 |
putr(); |
639 |
2 |
no_command = Yes; |
|
640 |
2 |
fflush(stdout); |
|
641 |
2 |
return (0); |
|
642 |
} |
||
643 |
|||
644 |
2 |
change = iptr - command_chars; |
|
645 |
|||
646 |
✗✗✓✗ ✗✗✗✗ ✗✗✗✗ ✗✗✗✓ ✗✗✗✗ ✗✗ |
2 |
switch (change) { |
647 |
case CMD_redraw: /* redraw screen */ |
||
648 |
reset_display(); |
||
649 |
break; |
||
650 |
|||
651 |
case CMD_update: /* merely update display */ |
||
652 |
/* |
||
653 |
* is the load average high? |
||
654 |
*/ |
||
655 |
if (system_info.load_avg[0] > LoadMax) { |
||
656 |
/* yes, go home for visual feedback */ |
||
657 |
go_home(); |
||
658 |
fflush(stdout); |
||
659 |
} |
||
660 |
break; |
||
661 |
|||
662 |
case CMD_quit: /* quit */ |
||
663 |
1 |
quit(0); |
|
664 |
break; |
||
665 |
|||
666 |
case CMD_help1: /* help */ |
||
667 |
case CMD_help2: |
||
668 |
clear(); |
||
669 |
show_help(); |
||
670 |
anykey(); |
||
671 |
clear(); |
||
672 |
break; |
||
673 |
|||
674 |
case CMD_errors: /* show errors */ |
||
675 |
if (error_count() == 0) { |
||
676 |
new_message(MT_standout, |
||
677 |
" Currently no errors to report."); |
||
678 |
putr(); |
||
679 |
no_command = Yes; |
||
680 |
} else { |
||
681 |
clear(); |
||
682 |
show_errors(); |
||
683 |
anykey(); |
||
684 |
clear(); |
||
685 |
} |
||
686 |
break; |
||
687 |
|||
688 |
case CMD_number1: /* new number */ |
||
689 |
case CMD_number2: |
||
690 |
new_message(MT_standout, |
||
691 |
"Number of processes to show: "); |
||
692 |
|||
693 |
if (readline(tempbuf, 8) > 0) { |
||
694 |
if ((i = atoiwi(tempbuf)) != Invalid) { |
||
695 |
if (i > max_topn) { |
||
696 |
new_message(MT_standout | |
||
697 |
MT_delayed, |
||
698 |
" This terminal can only " |
||
699 |
"display %d processes.", |
||
700 |
max_topn); |
||
701 |
putr(); |
||
702 |
} |
||
703 |
if ((i > topn || i == Infinity) |
||
704 |
&& topn == 0) { |
||
705 |
/* redraw the header */ |
||
706 |
display_header(Yes); |
||
707 |
} else if (i == 0) |
||
708 |
display_header(No); |
||
709 |
topn = i; |
||
710 |
} else { |
||
711 |
new_message(MT_standout, |
||
712 |
"Processes should be a " |
||
713 |
"non-negative number"); |
||
714 |
putr(); |
||
715 |
no_command = Yes; |
||
716 |
} |
||
717 |
} else |
||
718 |
clear_message(); |
||
719 |
break; |
||
720 |
|||
721 |
case CMD_delay: /* new seconds delay */ |
||
722 |
new_message(MT_standout, "Seconds to delay: "); |
||
723 |
if (readline(tempbuf, sizeof(tempbuf)) > 0) { |
||
724 |
char *endp; |
||
725 |
double newdelay = strtod(tempbuf, &endp); |
||
726 |
|||
727 |
if (newdelay >= 0 && newdelay <= 1000000 && |
||
728 |
*endp == '\0') { |
||
729 |
delay = newdelay; |
||
730 |
} else { |
||
731 |
new_message(MT_standout, |
||
732 |
"Delay should be a non-negative number"); |
||
733 |
putr(); |
||
734 |
no_command = Yes; |
||
735 |
} |
||
736 |
|||
737 |
} else |
||
738 |
clear_message(); |
||
739 |
break; |
||
740 |
|||
741 |
case CMD_displays: /* change display count */ |
||
742 |
new_message(MT_standout, |
||
743 |
"Displays to show (currently %s): ", |
||
744 |
displays == -1 ? "infinite" : |
||
745 |
itoa(displays)); |
||
746 |
|||
747 |
if (readline(tempbuf, 10) > 0) { |
||
748 |
if ((i = atoiwi(tempbuf)) != Invalid) { |
||
749 |
if (i == 0) |
||
750 |
quit(0); |
||
751 |
displays = i; |
||
752 |
} else { |
||
753 |
new_message(MT_standout, |
||
754 |
"Displays should be a non-negative number"); |
||
755 |
putr(); |
||
756 |
no_command = Yes; |
||
757 |
} |
||
758 |
} else |
||
759 |
clear_message(); |
||
760 |
break; |
||
761 |
|||
762 |
case CMD_kill: /* kill program */ |
||
763 |
new_message(0, "kill "); |
||
764 |
if (readline(tempbuf, sizeof(tempbuf)) > 0) { |
||
765 |
if ((errmsg = kill_procs(tempbuf)) != NULL) { |
||
766 |
new_message(MT_standout, "%s", errmsg); |
||
767 |
putr(); |
||
768 |
no_command = Yes; |
||
769 |
} |
||
770 |
} else |
||
771 |
clear_message(); |
||
772 |
break; |
||
773 |
|||
774 |
case CMD_renice: /* renice program */ |
||
775 |
new_message(0, "renice "); |
||
776 |
if (readline(tempbuf, sizeof(tempbuf)) > 0) { |
||
777 |
if ((errmsg = renice_procs(tempbuf)) != NULL) { |
||
778 |
new_message(MT_standout, "%s", errmsg); |
||
779 |
putr(); |
||
780 |
no_command = Yes; |
||
781 |
} |
||
782 |
} else |
||
783 |
clear_message(); |
||
784 |
break; |
||
785 |
|||
786 |
case CMD_idletog: |
||
787 |
case CMD_idletog2: |
||
788 |
ps.idle = !ps.idle; |
||
789 |
new_message(MT_standout | MT_delayed, |
||
790 |
" %sisplaying idle processes.", |
||
791 |
ps.idle ? "D" : "Not d"); |
||
792 |
putr(); |
||
793 |
break; |
||
794 |
|||
795 |
case CMD_user: |
||
796 |
new_message(MT_standout, |
||
797 |
"Username to show: "); |
||
798 |
if (readline(tempbuf, sizeof(tempbuf)) > 0) { |
||
799 |
if ((tempbuf[0] == '+' || tempbuf[0] == '-') && |
||
800 |
tempbuf[1] == '\0') { |
||
801 |
ps.uid = (uid_t)-1; |
||
802 |
ps.huid = (uid_t)-1; |
||
803 |
} else if (tempbuf[0] == '-') { |
||
804 |
if ((huid = userid(tempbuf+1)) == (uid_t)-1) { |
||
805 |
new_message(MT_standout, |
||
806 |
" %s: unknown user", tempbuf+1); |
||
807 |
no_command = Yes; |
||
808 |
} else { |
||
809 |
ps.huid = huid; |
||
810 |
ps.uid = (uid_t)-1; |
||
811 |
} |
||
812 |
} else if ((uid = userid(tempbuf)) == (uid_t)-1) { |
||
813 |
new_message(MT_standout, |
||
814 |
" %s: unknown user", tempbuf); |
||
815 |
no_command = Yes; |
||
816 |
} else { |
||
817 |
ps.uid = uid; |
||
818 |
ps.huid = (uid_t)-1; |
||
819 |
} |
||
820 |
putr(); |
||
821 |
} else |
||
822 |
clear_message(); |
||
823 |
break; |
||
824 |
|||
825 |
case CMD_system: |
||
826 |
ps.system = !ps.system; |
||
827 |
old_system = ps.system; |
||
828 |
new_message(MT_standout | MT_delayed, |
||
829 |
" %sisplaying system processes.", |
||
830 |
ps.system ? "D" : "Not d"); |
||
831 |
break; |
||
832 |
|||
833 |
case CMD_order: |
||
834 |
new_message(MT_standout, |
||
835 |
"Order to sort: "); |
||
836 |
if (readline(tempbuf, sizeof(tempbuf)) > 0) { |
||
837 |
if ((i = string_index(tempbuf, |
||
838 |
statics.order_names)) == -1) { |
||
839 |
new_message(MT_standout, |
||
840 |
" %s: unrecognized sorting order", |
||
841 |
tempbuf); |
||
842 |
no_command = Yes; |
||
843 |
} else |
||
844 |
order_index = i; |
||
845 |
putr(); |
||
846 |
} else |
||
847 |
clear_message(); |
||
848 |
break; |
||
849 |
|||
850 |
case CMD_pid: |
||
851 |
new_message(MT_standout, "Process ID to show: "); |
||
852 |
if (readline(tempbuf, sizeof(tempbuf)) > 0) { |
||
853 |
if (tempbuf[0] == '+' && |
||
854 |
tempbuf[1] == '\0') { |
||
855 |
ps.pid = (pid_t)-1; |
||
856 |
ps.system = old_system; |
||
857 |
} else { |
||
858 |
unsigned long long num; |
||
859 |
const char *errstr; |
||
860 |
|||
861 |
num = strtonum(tempbuf, 0, INT_MAX, |
||
862 |
&errstr); |
||
863 |
if (errstr != NULL || !find_pid(num)) { |
||
864 |
new_message(MT_standout, |
||
865 |
" %s: unknown pid", |
||
866 |
tempbuf); |
||
867 |
no_command = Yes; |
||
868 |
} else { |
||
869 |
if (ps.system == No) |
||
870 |
old_system = No; |
||
871 |
ps.pid = (pid_t)num; |
||
872 |
ps.system = Yes; |
||
873 |
} |
||
874 |
} |
||
875 |
putr(); |
||
876 |
} else |
||
877 |
clear_message(); |
||
878 |
break; |
||
879 |
|||
880 |
case CMD_command: |
||
881 |
1 |
show_args = (show_args == No) ? Yes : No; |
|
882 |
1 |
break; |
|
883 |
|||
884 |
case CMD_threads: |
||
885 |
ps.threads = !ps.threads; |
||
886 |
old_threads = ps.threads; |
||
887 |
new_message(MT_standout | MT_delayed, |
||
888 |
" %sisplaying threads.", |
||
889 |
ps.threads ? "D" : "Not d"); |
||
890 |
break; |
||
891 |
|||
892 |
case CMD_grep: |
||
893 |
new_message(MT_standout, |
||
894 |
"Grep command name: "); |
||
895 |
if (readline(tempbuf, sizeof(tempbuf)) > 0) { |
||
896 |
free(ps.command); |
||
897 |
if (tempbuf[0] == '+' && |
||
898 |
tempbuf[1] == '\0') |
||
899 |
ps.command = NULL; |
||
900 |
else |
||
901 |
if ((ps.command = strdup(tempbuf)) == |
||
902 |
NULL) |
||
903 |
err(1, NULL); |
||
904 |
putr(); |
||
905 |
} else |
||
906 |
clear_message(); |
||
907 |
break; |
||
908 |
|||
909 |
case CMD_hl: |
||
910 |
new_message(MT_standout, "Process ID to highlight: "); |
||
911 |
if (readline(tempbuf, sizeof(tempbuf)) > 0) { |
||
912 |
if (tempbuf[0] == '+' && |
||
913 |
tempbuf[1] == '\0') { |
||
914 |
hlpid = -1; |
||
915 |
} else { |
||
916 |
unsigned long long num; |
||
917 |
const char *errstr; |
||
918 |
|||
919 |
num = strtonum(tempbuf, 0, INT_MAX, |
||
920 |
&errstr); |
||
921 |
if (errstr != NULL || !find_pid(num)) { |
||
922 |
new_message(MT_standout, |
||
923 |
" %s: unknown pid", |
||
924 |
tempbuf); |
||
925 |
no_command = Yes; |
||
926 |
} else |
||
927 |
hlpid = (pid_t)num; |
||
928 |
} |
||
929 |
putr(); |
||
930 |
} else |
||
931 |
clear_message(); |
||
932 |
break; |
||
933 |
|||
934 |
case CMD_add: |
||
935 |
ps.uid = (uid_t)-1; /* uid */ |
||
936 |
ps.huid = (uid_t)-1; |
||
937 |
ps.pid = (pid_t)-1; /* pid */ |
||
938 |
ps.system = old_system; |
||
939 |
ps.command = NULL; /* grep */ |
||
940 |
hlpid = -1; |
||
941 |
break; |
||
942 |
case CMD_cpus: |
||
943 |
combine_cpus = !combine_cpus; |
||
944 |
max_topn = display_resize(); |
||
945 |
reset_display(); |
||
946 |
break; |
||
947 |
default: |
||
948 |
new_message(MT_standout, " BAD CASE IN SWITCH!"); |
||
949 |
putr(); |
||
950 |
} |
||
951 |
} |
||
952 |
|||
953 |
/* flush out stuff that may have been written */ |
||
954 |
1 |
fflush(stdout); |
|
955 |
1 |
return 0; |
|
956 |
} |
||
957 |
|||
958 |
|||
959 |
/* |
||
960 |
* reset_display() - reset all the display routine pointers so that entire |
||
961 |
* screen will get redrawn. |
||
962 |
*/ |
||
963 |
static void |
||
964 |
reset_display(void) |
||
965 |
{ |
||
966 |
if (smart_terminal) { |
||
967 |
clear(); |
||
968 |
refresh(); |
||
969 |
} |
||
970 |
} |
||
971 |
|||
972 |
/* ARGSUSED */ |
||
973 |
void |
||
974 |
leave(int signo) |
||
975 |
{ |
||
976 |
leaveflag = 1; |
||
977 |
} |
||
978 |
|||
979 |
/* ARGSUSED */ |
||
980 |
void |
||
981 |
tstop(int signo) |
||
982 |
{ |
||
983 |
tstopflag = 1; |
||
984 |
} |
||
985 |
|||
986 |
/* ARGSUSED */ |
||
987 |
void |
||
988 |
sigwinch(int signo) |
||
989 |
{ |
||
990 |
winchflag = 1; |
||
991 |
} |
||
992 |
|||
993 |
/* ARGSUSED */ |
||
994 |
void |
||
995 |
onalrm(int signo) |
||
996 |
{ |
||
997 |
} |
||
998 |
|||
999 |
void |
||
1000 |
quit(int ret) |
||
1001 |
1 |
{ |
|
1002 |
1 |
end_screen(); |
|
1003 |
1 |
exit(ret); |
|
1004 |
} |
Generated by: GCOVR (Version 3.3) |