Annotation of src/usr.bin/top/display.c, Revision 1.29
1.29 ! otto 1: /* $OpenBSD: display.c,v 1.28 2007/07/27 14:01:16 deraadt Exp $ */
1.1 downsj 2:
3: /*
4: * Top users/processes display for Unix
5: * Version 3
6: *
1.11 deraadt 7: * Copyright (c) 1984, 1989, William LeFebvre, Rice University
8: * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University
1.1 downsj 9: *
1.11 deraadt 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.
1.1 downsj 29: */
30:
31: /*
32: * This file contains the routines that display information on the screen.
33: * Each section of the screen has two routines: one for initially writing
34: * all constant and dynamic text, and one for only updating the text that
35: * changes. The prefix "i_" is used on all the "initial" routines and the
36: * prefix "u_" is used for all the "updating" routines.
37: *
38: * ASSUMPTIONS:
39: * None of the "i_" routines use any of the termcap capabilities.
40: * In this way, those routines can be safely used on terminals that
1.18 otto 41: * have minimal (or nonexistent) terminal capabilities.
1.1 downsj 42: *
43: * The routines are called in this order: *_loadave, i_timeofday,
44: * *_procstates, *_cpustates, *_memory, *_message, *_header,
45: * *_process, u_endscreen.
46: */
47:
1.2 downsj 48: #include <sys/types.h>
1.20 millert 49: #include <sys/sched.h>
1.25 otto 50: #include <curses.h>
51: #include <errno.h>
1.2 downsj 52: #include <stdio.h>
1.1 downsj 53: #include <ctype.h>
1.20 millert 54: #include <err.h>
1.25 otto 55: #include <signal.h>
1.2 downsj 56: #include <stdlib.h>
57: #include <string.h>
58: #include <unistd.h>
1.1 downsj 59:
60: #include "screen.h" /* interface to screen package */
61: #include "layout.h" /* defines for screen position layout */
62: #include "display.h"
63: #include "top.h"
64: #include "boolean.h"
65: #include "machine.h" /* we should eliminate this!!! */
66: #include "utils.h"
67:
68: #ifdef DEBUG
1.14 deraadt 69: FILE *debug;
1.1 downsj 70: #endif
71:
1.14 deraadt 72: static int display_width = MAX_COLS;
73:
1.20 millert 74: static char *cpustates_tag(int);
1.14 deraadt 75: static int string_count(char **);
1.16 millert 76: static void summary_format(char *, size_t, int *, char **);
1.25 otto 77: static int readlinedumb(char *, int, int);
1.2 downsj 78:
1.1 downsj 79: #define lineindex(l) ((l)*display_width)
80:
1.18 otto 81: /* things initialized by display_init and used throughout */
1.1 downsj 82:
83: /* buffer of proc information lines for display updating */
1.14 deraadt 84: char *screenbuf = NULL;
1.1 downsj 85:
1.14 deraadt 86: static char **procstate_names;
87: static char **cpustate_names;
88: static char **memory_names;
89:
90: static int num_procstates;
91: static int num_cpustates;
92:
93: static int *lprocstates;
1.20 millert 94: static int64_t **lcpustates;
1.14 deraadt 95:
96: static int *cpustate_columns;
97: static int cpustate_total_length;
98:
1.20 millert 99: /* display ips */
100: int y_mem;
101: int y_message;
102: int y_header;
103: int y_idlecursor;
104: int y_procs;
105: extern int ncpu;
106: int Header_lines;
107:
1.14 deraadt 108: static enum {
109: OFF, ON, ERASE
110: } header_status = ON;
1.1 downsj 111:
1.25 otto 112: static int
113: empty(void)
114: {
115: return OK;
116: }
117:
118: static int
119: myfputs(const char *s)
120: {
121: return fputs(s, stdout);
122: }
123:
124: static int (*addstrp)(const char *);
125: static int (*printwp)(const char *, ...);
126: static int (*standoutp)(void);
127: static int (*standendp)(void);
128:
1.12 pvalchev 129: int
130: display_resize(void)
1.1 downsj 131: {
1.14 deraadt 132: int display_lines;
1.1 downsj 133:
1.14 deraadt 134: /* calculate the current dimensions */
135: /* if operating in "dumb" mode, we only need one line */
136: display_lines = smart_terminal ? screen_length - Header_lines : 1;
137:
138: /*
139: * we don't want more than MAX_COLS columns, since the
140: * machine-dependent modules make static allocations based on
141: * MAX_COLS and we don't want to run off the end of their buffers
142: */
143: display_width = screen_width;
144: if (display_width >= MAX_COLS)
145: display_width = MAX_COLS - 1;
146:
147: /* return number of lines available */
148: /* for dumb terminals, pretend like we can show any amount */
149: return (smart_terminal ? display_lines : Largest);
1.1 downsj 150: }
151:
1.12 pvalchev 152: int
1.14 deraadt 153: display_init(struct statics * statics)
1.1 downsj 154: {
1.20 millert 155: int display_lines, *ip, i, cpu;
1.14 deraadt 156: char **pp;
157:
1.25 otto 158: if (smart_terminal) {
159: addstrp = addstr;
160: printwp = (int(*)(const char *, ...))printw;
161: standoutp = standout;
162: standendp = standend;
163: } else {
164: addstrp = myfputs;
165: printwp = printf;
166: standoutp = empty;
167: standendp = empty;
168: }
169:
1.20 millert 170: y_mem = 2 + ncpu;
171: y_message = 3 + ncpu;
172: y_header = 4 + ncpu;
173: y_idlecursor = 3 + ncpu;
174: y_procs = 5 + ncpu;
175: Header_lines = 5 + ncpu;
176:
1.14 deraadt 177: /* call resize to do the dirty work */
178: display_lines = display_resize();
179:
180: /* only do the rest if we need to */
181: if (display_lines > -1) {
182: /* save pointers and allocate space for names */
183: procstate_names = statics->procstate_names;
184: num_procstates = string_count(procstate_names);
1.26 deraadt 185: lprocstates = calloc(num_procstates, sizeof(int));
1.20 millert 186: if (lprocstates == NULL)
187: err(1, NULL);
1.14 deraadt 188:
189: cpustate_names = statics->cpustate_names;
190: num_cpustates = string_count(cpustate_names);
1.26 deraadt 191: lcpustates = calloc(ncpu, sizeof(int64_t *));
1.20 millert 192: if (lcpustates == NULL)
193: err(1, NULL);
194: for (cpu = 0; cpu < ncpu; cpu++) {
1.26 deraadt 195: lcpustates[cpu] = calloc(num_cpustates, sizeof(int64_t));
1.20 millert 196: if (lcpustates[cpu] == NULL)
197: err(1, NULL);
198: }
199:
1.26 deraadt 200: cpustate_columns = calloc(num_cpustates, sizeof(int));
1.20 millert 201: if (cpustate_columns == NULL)
202: err(1, NULL);
1.14 deraadt 203:
204: memory_names = statics->memory_names;
205:
206: /* calculate starting columns where needed */
207: cpustate_total_length = 0;
208: pp = cpustate_names;
209: ip = cpustate_columns;
210: while (*pp != NULL) {
211: if ((i = strlen(*pp++)) > 0) {
212: *ip++ = cpustate_total_length;
213: cpustate_total_length += i + 8;
214: }
215: }
1.1 downsj 216: }
1.14 deraadt 217: /* return number of lines available */
218: return (display_lines);
1.1 downsj 219: }
220:
1.12 pvalchev 221: void
222: i_loadave(pid_t mpid, double *avenrun)
1.1 downsj 223: {
1.14 deraadt 224: int i;
225:
1.25 otto 226: move(0, 0);
227: clrtoeol();
1.1 downsj 228:
1.14 deraadt 229: /* mpid == -1 implies this system doesn't have an _mpid */
230: if (mpid != -1)
1.25 otto 231: printwp("last pid: %5ld; ", (long) mpid);
1.1 downsj 232:
1.25 otto 233: addstrp("load averages");
1.14 deraadt 234:
235: for (i = 0; i < 3; i++)
1.25 otto 236: printwp("%c %5.2f", i == 0 ? ':' : ',', avenrun[i]);
1.1 downsj 237: }
238:
1.14 deraadt 239: /*
240: * Display the current time.
241: * "ctime" always returns a string that looks like this:
242: *
243: * Sun Sep 16 01:03:52 1973
244: * 012345678901234567890123
245: * 1 2
246: *
247: * We want indices 11 thru 18 (length 8).
248: */
249:
1.12 pvalchev 250: void
1.14 deraadt 251: i_timeofday(time_t * tod)
1.1 downsj 252: {
1.14 deraadt 253:
254: if (smart_terminal) {
1.25 otto 255: move(0, screen_width - 8);
1.14 deraadt 256: } else {
257: if (fputs(" ", stdout) == EOF)
258: exit(1);
259: }
1.1 downsj 260: #ifdef DEBUG
1.14 deraadt 261: {
262: char *foo;
263: foo = ctime(tod);
1.25 otto 264: addstrp(foo);
1.14 deraadt 265: }
1.1 downsj 266: #endif
1.25 otto 267: printwp("%-8.8s", &(ctime(tod)[11]));
268: putn();
1.1 downsj 269: }
270:
271: /*
272: * *_procstates(total, brkdn, names) - print the process summary line
273: *
274: * Assumptions: cursor is at the beginning of the line on entry
275: * lastline is valid
276: */
1.12 pvalchev 277: void
278: i_procstates(int total, int *brkdn)
1.1 downsj 279: {
1.14 deraadt 280: int i;
1.25 otto 281: char procstates_buffer[MAX_COLS];
1.1 downsj 282:
1.25 otto 283: move(1, 0);
284: clrtoeol();
1.14 deraadt 285: /* write current number of processes and remember the value */
1.25 otto 286: printwp("%d processes:", total);
1.14 deraadt 287:
1.25 otto 288: if (smart_terminal)
289: move(1, 15);
290: else {
291: /* put out enough spaces to get to column 15 */
292: i = digits(total);
293: while (i++ < 4) {
294: if (putchar(' ') == EOF)
295: exit(1);
296: }
1.14 deraadt 297: }
298:
299: /* format and print the process state summary */
1.16 millert 300: summary_format(procstates_buffer, sizeof(procstates_buffer), brkdn,
301: procstate_names);
1.1 downsj 302:
1.25 otto 303: addstrp(procstates_buffer);
304: putn();
1.1 downsj 305: }
306:
307: /*
308: * *_cpustates(states, names) - print the cpu state percentages
309: *
310: * Assumptions: cursor is on the PREVIOUS line
311: */
312:
313: /* cpustates_tag() calculates the correct tag to use to label the line */
314:
1.12 pvalchev 315: static char *
1.20 millert 316: cpustates_tag(int cpu)
1.1 downsj 317: {
1.20 millert 318: static char *tag;
319: static int cpulen, old_width;
320: int i;
1.14 deraadt 321:
1.20 millert 322: if (cpulen == 0 && ncpu > 1) {
323: /* compute length of the cpu string */
324: for (i = ncpu; i > 0; cpulen++, i /= 10)
325: continue;
326: }
327:
328: if (old_width == screen_width) {
329: if (ncpu > 1) {
330: /* just store the cpu number in the tag */
331: i = tag[3 + cpulen];
332: snprintf(tag + 3, cpulen + 1, "%.*d", cpulen, cpu);
333: tag[3 + cpulen] = i;
334: }
335: } else {
336: /*
337: * use a long tag if it will fit, otherwise use short one.
338: */
339: free(tag);
340: if (cpustate_total_length + 10 + cpulen >= screen_width)
341: i = asprintf(&tag, "CPU%.*d: ", cpulen, cpu);
342: else
343: i = asprintf(&tag, "CPU%.*d states: ", cpulen, cpu);
344: if (i == -1)
345: tag = NULL;
1.25 otto 346: else
1.20 millert 347: old_width = screen_width;
348: }
349: return (tag);
1.1 downsj 350: }
351:
1.12 pvalchev 352: void
1.20 millert 353: i_cpustates(int64_t *ostates)
1.1 downsj 354: {
1.20 millert 355: int i, cpu, value;
356: int64_t *states;
1.14 deraadt 357: char **names = cpustate_names, *thisname;
358:
1.20 millert 359: for (cpu = 0; cpu < ncpu; cpu++) {
1.25 otto 360: move(2 + cpu, 0);
361: clrtoeol();
1.20 millert 362: /* print tag and bump lastline */
1.25 otto 363: addstrp(cpustates_tag(cpu));
1.20 millert 364:
365: /* now walk thru the names and print the line */
366: names = cpustate_names;
367: i = 0;
368: states = ostates + (CPUSTATES * cpu);
369: while ((thisname = *names++) != NULL) {
370: if (*thisname != '\0') {
371: /* retrieve the value and remember it */
372: value = *states++;
373:
374: /* if percentage is >= 1000, print it as 100% */
1.25 otto 375: printwp((value >= 1000 ? "%s%4.0f%% %s" :
1.20 millert 376: "%s%4.1f%% %s"), i++ == 0 ? "" : ", ",
377: ((float) value) / 10., thisname);
378: }
1.14 deraadt 379: }
1.25 otto 380: putn();
1.1 downsj 381: }
382: }
383:
384: /*
385: * *_memory(stats) - print "Memory: " followed by the memory summary string
386: *
387: * Assumptions: cursor is on "lastline"
388: * for i_memory ONLY: cursor is on the previous line
389: */
1.12 pvalchev 390: void
391: i_memory(int *stats)
1.1 downsj 392: {
1.25 otto 393: char memory_buffer[MAX_COLS];
394:
395: move(y_mem, 0);
396: clrtoeol();
397: addstrp("Memory: ");
1.14 deraadt 398:
399: /* format and print the memory summary */
1.16 millert 400: summary_format(memory_buffer, sizeof(memory_buffer), stats,
401: memory_names);
1.25 otto 402: addstrp(memory_buffer);
403: putn();
1.1 downsj 404: }
405:
406: /*
407: * *_message() - print the next pending message line, or erase the one
408: * that is there.
409: *
410: * Note that u_message is (currently) the same as i_message.
411: *
412: * Assumptions: lastline is consistent
413: */
414:
415: /*
416: * i_message is funny because it gets its message asynchronously (with
417: * respect to screen updates).
418: */
419:
1.14 deraadt 420: static char next_msg[MAX_COLS + 5];
421: static int msglen = 0;
422: /*
423: * Invariant: msglen is always the length of the message currently displayed
424: * on the screen (even when next_msg doesn't contain that message).
425: */
1.1 downsj 426:
1.12 pvalchev 427: void
428: i_message(void)
1.1 downsj 429: {
1.25 otto 430: /*
1.14 deraadt 431: while (lastline < y_message) {
432: if (fputc('\n', stdout) == EOF)
433: exit(1);
434: lastline++;
435: }
1.25 otto 436: */
437: move(y_message, 0);
1.14 deraadt 438: if (next_msg[0] != '\0') {
1.25 otto 439: standoutp();
440: addstrp(next_msg);
441: standendp();
442: clrtoeol();
1.14 deraadt 443: msglen = strlen(next_msg);
444: next_msg[0] = '\0';
445: } else if (msglen > 0) {
1.25 otto 446: clrtoeol();
1.14 deraadt 447: msglen = 0;
448: }
1.1 downsj 449: }
450:
1.14 deraadt 451: static int header_length;
1.1 downsj 452:
453: /*
454: * *_header(text) - print the header for the process area
455: *
456: * Assumptions: cursor is on the previous line and lastline is consistent
457: */
458:
1.12 pvalchev 459: void
460: i_header(char *text)
1.1 downsj 461: {
1.14 deraadt 462: header_length = strlen(text);
463: if (header_status == ON) {
1.25 otto 464: if (!smart_terminal) {
465: putn();
466: if (fputs(text, stdout) == EOF)
467: exit(1);
468: putn();
469: } else {
470: move(y_header, 0);
471: clrtoeol();
472: addstrp(text);
473: }
1.14 deraadt 474: } else if (header_status == ERASE) {
475: header_status = OFF;
476: }
1.1 downsj 477: }
478:
479: /*
480: * *_process(line, thisline) - print one process line
481: *
482: * Assumptions: lastline is consistent
483: */
484:
1.12 pvalchev 485: void
1.25 otto 486: i_process(int line, char *thisline, int hl)
1.1 downsj 487: {
1.14 deraadt 488: /* make sure we are on the correct line */
1.25 otto 489: move(y_procs + line, 0);
1.1 downsj 490:
1.14 deraadt 491: /* truncate the line to conform to our current screen width */
492: thisline[display_width] = '\0';
1.1 downsj 493:
1.14 deraadt 494: /* write the line out */
1.25 otto 495: if (hl && smart_terminal)
496: standoutp();
497: addstrp(thisline);
498: if (hl && smart_terminal)
499: standendp();
500: putn();
501: clrtoeol();
1.1 downsj 502: }
503:
1.12 pvalchev 504: void
1.27 deraadt 505: u_endscreen(void)
1.1 downsj 506: {
1.14 deraadt 507: if (smart_terminal) {
1.25 otto 508: clrtobot();
1.14 deraadt 509: /* move the cursor to a pleasant place */
1.25 otto 510: move(y_idlecursor, x_idlecursor);
1.14 deraadt 511: } else {
512: /*
513: * separate this display from the next with some vertical
514: * room
515: */
516: if (fputs("\n\n", stdout) == EOF)
517: exit(1);
1.1 downsj 518: }
519: }
520:
1.12 pvalchev 521: void
522: display_header(int t)
1.1 downsj 523: {
1.14 deraadt 524: if (t) {
525: header_status = ON;
526: } else if (header_status == ON) {
527: header_status = ERASE;
528: }
1.1 downsj 529: }
530:
1.12 pvalchev 531: void
1.14 deraadt 532: new_message(int type, const char *msgfmt,...)
533: {
534: va_list ap;
535: int i;
536:
537: va_start(ap, msgfmt);
538: /* first, format the message */
539: vsnprintf(next_msg, sizeof(next_msg), msgfmt, ap);
540: va_end(ap);
541:
542: if (msglen > 0) {
543: /* message there already -- can we clear it? */
1.25 otto 544: /* yes -- write it and clear to end */
545: i = strlen(next_msg);
546: if ((type & MT_delayed) == 0) {
547: move(y_message, 0);
548: if (type & MT_standout)
549: standoutp();
550: addstrp(next_msg);
551: if (type & MT_standout)
552: standendp();
553: clrtoeol();
554: msglen = i;
555: next_msg[0] = '\0';
1.14 deraadt 556: }
557: } else {
558: if ((type & MT_delayed) == 0) {
1.25 otto 559: move(y_message, 0);
560: if (type & MT_standout)
561: standoutp();
562: addstrp(next_msg);
1.14 deraadt 563: if (type & MT_standout)
1.25 otto 564: standendp();
565: clrtoeol();
1.14 deraadt 566: msglen = strlen(next_msg);
567: next_msg[0] = '\0';
1.5 deraadt 568: }
1.1 downsj 569: }
1.25 otto 570: if (smart_terminal)
571: refresh();
1.1 downsj 572: }
573:
1.12 pvalchev 574: void
575: clear_message(void)
1.1 downsj 576: {
1.25 otto 577: move(y_message, 0);
578: clrtoeol();
1.1 downsj 579: }
580:
1.25 otto 581:
582: static int
583: readlinedumb(char *buffer, int size, int numeric)
1.1 downsj 584: {
1.14 deraadt 585: char *ptr = buffer, ch, cnt = 0, maxcnt = 0;
1.17 deraadt 586: extern volatile sig_atomic_t leaveflag;
587: ssize_t len;
1.14 deraadt 588:
589: /* allow room for null terminator */
590: size -= 1;
591:
592: /* read loop */
1.19 deraadt 593: while ((fflush(stdout), (len = read(STDIN_FILENO, ptr, 1)) > 0)) {
1.17 deraadt 594:
595: if (len == 0 || leaveflag) {
596: end_screen();
597: exit(0);
598: }
599:
1.14 deraadt 600: /* newline means we are done */
601: if ((ch = *ptr) == '\n')
602: break;
603:
604: /* handle special editing characters */
605: if (ch == ch_kill) {
606: /* return null string */
607: *buffer = '\0';
1.25 otto 608: putr();
1.14 deraadt 609: return (-1);
610: } else if (ch == ch_erase) {
611: /* erase previous character */
612: if (cnt <= 0) {
613: /* none to erase! */
614: if (putchar('\7') == EOF)
615: exit(1);
616: } else {
617: if (fputs("\b \b", stdout) == EOF)
618: exit(1);
619: ptr--;
620: cnt--;
621: }
622: }
623: /* check for character validity and buffer overflow */
624: else if (cnt == size || (numeric && !isdigit(ch)) ||
625: !isprint(ch)) {
626: /* not legal */
627: if (putchar('\7') == EOF)
628: exit(1);
629: } else {
630: /* echo it and store it in the buffer */
631: if (putchar(ch) == EOF)
632: exit(1);
633: ptr++;
634: cnt++;
635: if (cnt > maxcnt)
636: maxcnt = cnt;
637: }
1.1 downsj 638: }
639:
1.14 deraadt 640: /* all done -- null terminate the string */
641: *ptr = '\0';
642:
643: /* account for the extra characters in the message area */
1.25 otto 644: msglen += cnt;
1.14 deraadt 645:
646: /* return either inputted number or string length */
1.25 otto 647: putr();
648: return (cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
649: }
650:
651: int
652: readline(char *buffer, int size, int numeric)
653: {
654: size_t cnt;
655:
656: /* allow room for null terminator */
657: size -= 1;
658:
659: if (smart_terminal)
660: getnstr(buffer, size);
661: else
662: return readlinedumb(buffer, size, numeric);
663:
664: cnt = strlen(buffer);
665: if (cnt > 0 && buffer[cnt - 1] == '\n')
666: buffer[cnt - 1] = '\0';
1.14 deraadt 667: return (cnt == 0 ? -1 : numeric ? atoi(buffer) : cnt);
1.1 downsj 668: }
669:
670: /* internal support routines */
1.12 pvalchev 671: static int
672: string_count(char **pp)
1.1 downsj 673: {
1.14 deraadt 674: int cnt;
1.1 downsj 675:
1.14 deraadt 676: cnt = 0;
677: while (*pp++ != NULL)
678: cnt++;
679: return (cnt);
1.1 downsj 680: }
681:
1.16 millert 682: #define COPYLEFT(to, from) \
683: do { \
684: len = strlcpy((to), (from), left); \
685: if (len >= left) \
686: return; \
687: p += len; \
688: left -= len; \
689: } while (0)
690:
1.12 pvalchev 691: static void
1.16 millert 692: summary_format(char *buf, size_t left, int *numbers, char **names)
1.1 downsj 693: {
1.14 deraadt 694: char *p, *thisname;
1.16 millert 695: size_t len;
1.14 deraadt 696: int num;
1.1 downsj 697:
1.14 deraadt 698: /* format each number followed by its string */
1.16 millert 699: p = buf;
1.14 deraadt 700: while ((thisname = *names++) != NULL) {
701: /* get the number to format */
702: num = *numbers++;
703:
704: if (num >= 0) {
705: /* is this number in kilobytes? */
706: if (thisname[0] == 'K') {
707: /* yes: format it as a memory value */
1.16 millert 708: COPYLEFT(p, format_k(num));
1.14 deraadt 709:
710: /*
711: * skip over the K, since it was included by
712: * format_k
713: */
1.16 millert 714: COPYLEFT(p, thisname + 1);
1.14 deraadt 715: } else if (num > 0) {
1.16 millert 716: len = snprintf(p, left, "%d%s", num, thisname);
717: if (len == (size_t)-1 || len >= left)
718: return;
719: p += len;
720: left -= len;
1.14 deraadt 721: }
1.16 millert 722: } else {
723: /*
724: * Ignore negative numbers, but display corresponding
725: * string.
726: */
727: COPYLEFT(p, thisname);
1.14 deraadt 728: }
1.1 downsj 729: }
730:
1.14 deraadt 731: /* if the last two characters in the string are ", ", delete them */
732: p -= 2;
1.16 millert 733: if (p >= buf && p[0] == ',' && p[1] == ' ')
1.14 deraadt 734: *p = '\0';
1.1 downsj 735: }
736:
737: /*
738: * printable(str) - make the string pointed to by "str" into one that is
739: * printable (i.e.: all ascii), by converting all non-printable
740: * characters into '?'. Replacements are done in place and a pointer
741: * to the original buffer is returned.
742: */
1.12 pvalchev 743: char *
744: printable(char *str)
1.1 downsj 745: {
1.14 deraadt 746: char *ptr, ch;
1.1 downsj 747:
1.14 deraadt 748: ptr = str;
749: while ((ch = *ptr) != '\0') {
750: if (!isprint(ch))
751: *ptr = '?';
752: ptr++;
1.1 downsj 753: }
1.14 deraadt 754: return (str);
1.25 otto 755: }
756:
757:
758: /*
759: * show_help() - display the help screen; invoked in response to
760: * either 'h' or '?'.
761: */
762: void
763: show_help(void)
764: {
765: if (smart_terminal) {
766: clear();
767: nl();
768: }
769: printwp("These single-character commands are available:\n"
770: "\n"
771: "^L - redraw screen\n"
772: "+ - reset any g, p, or u filters\n"
773: "C - toggle the display of command line arguments\n"
774: "d count - show `count' displays, then exit\n"
775: "e - list errors generated by last \"kill\" or \"renice\" command\n"
776: "h | ? - help; show this text\n"
777: "g string - filter on command name (g+ selects all commands)\n"
778: "I | i - toggle the display of idle processes\n"
779: "k [-sig] pid - send signal `-sig' to process `pid'\n"
780: "n|# count - show `count' processes\n"
781: "o field - specify sort order (size, res, cpu, time, pri)\n"
782: "P pid - highlight process `pid' (P+ switches highlighting off)\n"
783: "p pid - display process by `pid' (p+ selects all processes)\n"
784: "q - quit\n"
785: "r count pid - renice process `pid' to nice value `count'\n"
786: "S - toggle the display of system processes\n"
787: "s time - change delay between displays to `time' seconds\n"
788: "T - toggle the display of threads\n"
789: "u user - display processes for `user' (u+ selects all users)\n"
790: "\n");
791:
792: if (smart_terminal) {
793: nonl();
794: refresh();
795: }
796: }
797:
798: /*
799: * show_errors() - display on stdout the current log of errors.
800: */
801: void
802: show_errors(void)
803: {
804: struct errs *errp = errs;
805: int cnt = 0;
806:
807: if (smart_terminal) {
808: clear();
809: nl();
810: }
811: printwp("%d error%s:\n\n", errcnt, errcnt == 1 ? "" : "s");
812: while (cnt++ < errcnt) {
813: printf("%5s: %s\n", errp->arg,
814: errp->err == 0 ? "Not a number" : strerror(errp->err));
815: errp++;
816: }
817: if (smart_terminal) {
818: nonl();
819: refresh();
820: }
821: }
822:
823: void
824: anykey(void)
825: {
826: int ch;
1.28 deraadt 827: ssize_t len;
1.25 otto 828:
829: standoutp();
830: addstrp("Hit any key to continue: ");
831: standendp();
832: if (smart_terminal)
833: refresh();
834: else
835: fflush(stdout);
836: while (1) {
837: len = read(STDIN_FILENO, &ch, 1);
838: if (len == -1 && errno == EINTR)
839: continue;
840: if (len == 0)
841: exit(1);
842: break;
843: }
1.1 downsj 844: }