[BACK]Return to display.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / top

Annotation of src/usr.bin/top/display.c, Revision 1.64

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