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