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

Annotation of src/usr.bin/top/machine.c, Revision 1.19

1.19    ! niklas      1: /*     $OpenBSD: machine.c,v 1.18 1999/11/14 09:03:46 deraadt Exp $    */
1.1       downsj      2:
                      3: /*
                      4:  * top - a top users display for Unix
                      5:  *
                      6:  * SYNOPSIS:  For an OpenBSD system
                      7:  *
                      8:  * DESCRIPTION:
                      9:  * This is the machine-dependent module for OpenBSD
                     10:  * Tested on:
                     11:  *     i386
                     12:  *
                     13:  * LIBS: -lkvm
                     14:  *
                     15:  * TERMCAP: -ltermlib
                     16:  *
1.11      kstailey   17:  * CFLAGS: -DHAVE_GETOPT -DORDER
1.1       downsj     18:  *
                     19:  * AUTHOR:  Thorsten Lockert <tholo@sigmasoft.com>
                     20:  *          Adapted from BSD4.4 by Christos Zoulas <christos@ee.cornell.edu>
                     21:  *          Patch for process wait display by Jarl F. Greipsland <jarle@idt.unit.no>
1.11      kstailey   22:  *         Patch for -DORDER by Kenneth Stailey <kstailey@disclosure.com>
1.15      weingart   23:  *         Patch for new swapctl(2) by Tobias Weingartner <weingart@openbsd.org>
1.1       downsj     24:  */
                     25:
                     26: #include <sys/types.h>
                     27: #include <sys/signal.h>
                     28: #include <sys/param.h>
                     29:
                     30: #define DOSWAP
                     31:
                     32: #include <stdio.h>
                     33: #include <stdlib.h>
1.3       downsj     34: #include <string.h>
1.6       millert    35: #include <limits.h>
                     36: #include <err.h>
1.1       downsj     37: #include <nlist.h>
                     38: #include <math.h>
                     39: #include <kvm.h>
                     40: #include <unistd.h>
                     41: #include <sys/errno.h>
                     42: #include <sys/sysctl.h>
                     43: #include <sys/dir.h>
                     44: #include <sys/dkstat.h>
                     45: #include <sys/file.h>
                     46: #include <sys/time.h>
                     47: #include <sys/resource.h>
                     48:
                     49: #ifdef DOSWAP
1.15      weingart   50: #include <sys/swap.h>
1.1       downsj     51: #include <err.h>
                     52: #endif
                     53:
                     54: static int check_nlist __P((struct nlist *));
                     55: static int getkval __P((unsigned long, int *, int, char *));
                     56: static int swapmode __P((int *, int *));
                     57:
                     58: #include "top.h"
1.3       downsj     59: #include "display.h"
1.1       downsj     60: #include "machine.h"
                     61: #include "utils.h"
                     62:
                     63: /* get_process_info passes back a handle.  This is what it looks like: */
                     64:
                     65: struct handle
                     66: {
                     67:     struct kinfo_proc **next_proc;     /* points to next valid proc pointer */
                     68:     int remaining;             /* number of pointers remaining */
                     69: };
                     70:
                     71: /* declarations for load_avg */
                     72: #include "loadavg.h"
                     73:
                     74: #define PP(pp, field) ((pp)->kp_proc . field)
                     75: #define EP(pp, field) ((pp)->kp_eproc . field)
                     76: #define VP(pp, field) ((pp)->kp_eproc.e_vm . field)
                     77:
                     78: /* what we consider to be process size: */
                     79: #define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp), vm_ssize))
                     80:
                     81: /* definitions for indices in the nlist array */
                     82: #define X_CP_TIME      0
                     83:
                     84: static struct nlist nlst[] = {
                     85:     { "_cp_time" },            /* 0 */
                     86:     { 0 }
                     87: };
                     88:
                     89: /*
                     90:  *  These definitions control the format of the per-process area
                     91:  */
                     92:
                     93: static char header[] =
                     94:   "  PID X        PRI NICE  SIZE   RES STATE WAIT     TIME    CPU COMMAND";
                     95: /* 0123456   -- field to fill in starts at header+6 */
                     96: #define UNAME_START 6
                     97:
                     98: #define Proc_format \
                     99:        "%5d %-8.8s %3d %4d %5s %5s %-5s %-6.6s %6s %5.2f%% %.14s"
                    100:
                    101:
                    102: /* process state names for the "STATE" column of the display */
                    103: /* the extra nulls in the string "run" are for adding a slash and
                    104:    the processor number when needed */
                    105:
                    106: char *state_abbrev[] =
                    107: {
                    108:     "", "start", "run\0\0\0", "sleep", "stop", "zomb",
                    109: };
                    110:
                    111:
                    112: static kvm_t *kd;
                    113:
                    114: /* these are retrieved from the kernel in _init */
                    115:
1.18      deraadt   116: static          int stathz;
1.1       downsj    117:
                    118: /* these are offsets obtained via nlist and used in the get_ functions */
                    119:
                    120: static unsigned long cp_time_offset;
                    121:
                    122: /* these are for calculating cpu state percentages */
1.13      niklas    123: static long cp_time[CPUSTATES];
                    124: static long cp_old[CPUSTATES];
                    125: static long cp_diff[CPUSTATES];
1.1       downsj    126:
                    127: /* these are for detailing the process states */
                    128:
                    129: int process_states[7];
                    130: char *procstatenames[] = {
                    131:     "", " starting, ", " running, ", " idle, ", " stopped, ", " zombie, ",
                    132:     NULL
                    133: };
                    134:
                    135: /* these are for detailing the cpu states */
                    136:
                    137: int cpu_states[CPUSTATES];
                    138: char *cpustatenames[] = {
                    139:     "user", "nice", "system", "interrupt", "idle", NULL
                    140: };
                    141:
                    142: /* these are for detailing the memory statistics */
                    143:
                    144: int memory_stats[8];
                    145: char *memorynames[] = {
                    146:     "Real: ", "K/", "K act/tot  ", "Free: ", "K  ",
                    147: #ifdef DOSWAP
                    148:     "Swap: ", "K/", "K used/tot",
                    149: #endif
                    150:     NULL
                    151: };
                    152:
1.11      kstailey  153: #ifdef ORDER
                    154: /* these are names given to allowed sorting orders -- first is default */
                    155:
                    156: char *ordernames[] = {"cpu", "size", "res", "time", "pri", NULL};
                    157: #endif
                    158:
1.1       downsj    159: /* these are for keeping track of the proc array */
                    160:
                    161: static int nproc;
                    162: static int onproc = -1;
                    163: static int pref_len;
                    164: static struct kinfo_proc *pbase;
                    165: static struct kinfo_proc **pref;
                    166:
                    167: /* these are for getting the memory statistics */
                    168:
                    169: static int pageshift;          /* log base 2 of the pagesize */
                    170:
                    171: /* define pagetok in terms of pageshift */
                    172:
                    173: #define pagetok(size) ((size) << pageshift)
                    174:
                    175: int
1.18      deraadt   176: getstathz()
                    177: {
                    178:        int mib[2];
                    179:        struct clockinfo cinf;
                    180:        size_t size = sizeof(cinf);
                    181:
                    182:        mib[0] = CTL_KERN;
                    183:        mib[1] = KERN_CLOCKRATE;
                    184:        if (sysctl(mib, 2, &cinf, &size, NULL, 0) == -1)
                    185:                return (-1);
                    186:        return (cinf.stathz);
                    187: }
                    188:
                    189: int
1.1       downsj    190: machine_init(statics)
                    191: struct statics *statics;
                    192: {
                    193:     register int i = 0;
                    194:     register int pagesize;
1.6       millert   195:     char errbuf[_POSIX2_LINE_MAX];
1.1       downsj    196:
1.6       millert   197:     if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf)) == NULL) {
                    198:        warnx("%s", errbuf);
                    199:        return(-1);
                    200:     }
1.10      deraadt   201:
                    202:     setegid(getgid());
                    203:     setgid(getgid());
1.1       downsj    204:
                    205:     /* get the list of symbols we want to access in the kernel */
1.15      weingart  206:     if (kvm_nlist(kd, nlst) < 0) {
1.6       millert   207:        warnx("nlist failed");
1.1       downsj    208:        return(-1);
                    209:     }
                    210:
                    211:     /* make sure they were all found */
                    212:     if (i > 0 && check_nlist(nlst) > 0)
                    213:        return(-1);
                    214:
1.18      deraadt   215:     stathz = getstathz();
                    216:     if (stathz == -1)
                    217:        return(-1);
1.1       downsj    218:
                    219:     /* stash away certain offsets for later use */
                    220:     cp_time_offset = nlst[X_CP_TIME].n_value;
                    221:
                    222:     pbase = NULL;
                    223:     pref = NULL;
                    224:     onproc = -1;
                    225:     nproc = 0;
                    226:
                    227:     /* get the page size with "getpagesize" and calculate pageshift from it */
                    228:     pagesize = getpagesize();
                    229:     pageshift = 0;
                    230:     while (pagesize > 1)
                    231:     {
                    232:        pageshift++;
                    233:        pagesize >>= 1;
                    234:     }
                    235:
                    236:     /* we only need the amount of log(2)1024 for our conversion */
                    237:     pageshift -= LOG1024;
                    238:
                    239:     /* fill in the statics information */
                    240:     statics->procstate_names = procstatenames;
                    241:     statics->cpustate_names = cpustatenames;
                    242:     statics->memory_names = memorynames;
1.11      kstailey  243: #ifdef ORDER
                    244:     statics->order_names = ordernames;
                    245: #endif
1.1       downsj    246:
                    247:     /* all done! */
                    248:     return(0);
                    249: }
                    250:
                    251: char *format_header(uname_field)
                    252:
                    253: register char *uname_field;
                    254:
                    255: {
                    256:     register char *ptr;
                    257:
                    258:     ptr = header + UNAME_START;
                    259:     while (*uname_field != '\0')
                    260:     {
                    261:        *ptr++ = *uname_field++;
                    262:     }
                    263:
                    264:     return(header);
                    265: }
                    266:
                    267: void
                    268: get_system_info(si)
                    269:
                    270: struct system_info *si;
                    271:
                    272: {
1.3       downsj    273:     int total;
1.1       downsj    274:
                    275:     /* get the cp_time array */
                    276:     (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
                    277:                   "_cp_time");
                    278:
                    279:     /* convert load averages to doubles */
                    280:     {
                    281:        register int i;
                    282:        register double *infoloadp;
                    283:        struct loadavg sysload;
1.4       downsj    284:        size_t size = sizeof(sysload);
1.1       downsj    285:        static int mib[] = { CTL_VM, VM_LOADAVG };
                    286:
                    287:        if (sysctl(mib, 2, &sysload, &size, NULL, 0) < 0) {
1.6       millert   288:            warn("sysctl failed");
1.1       downsj    289:            bzero(&total, sizeof(total));
                    290:        }
                    291:
                    292:        infoloadp = si->load_avg;
                    293:        for (i = 0; i < 3; i++)
                    294:            *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
                    295:     }
                    296:
                    297:     /* convert cp_time counts to percentages */
                    298:     total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
                    299:
                    300:     /* sum memory statistics */
                    301:     {
                    302:        struct vmtotal total;
1.4       downsj    303:        size_t size = sizeof(total);
1.1       downsj    304:        static int mib[] = { CTL_VM, VM_METER };
                    305:
                    306:        /* get total -- systemwide main memory usage structure */
                    307:        if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
1.6       millert   308:            warn("sysctl failed");
1.1       downsj    309:            bzero(&total, sizeof(total));
                    310:        }
                    311:        /* convert memory stats to Kbytes */
                    312:        memory_stats[0] = -1;
                    313:        memory_stats[1] = pagetok(total.t_arm);
                    314:        memory_stats[2] = pagetok(total.t_rm);
                    315:        memory_stats[3] = -1;
                    316:        memory_stats[4] = pagetok(total.t_free);
                    317:        memory_stats[5] = -1;
                    318: #ifdef DOSWAP
                    319:        if (!swapmode(&memory_stats[6], &memory_stats[7])) {
                    320:            memory_stats[6] = 0;
                    321:            memory_stats[7] = 0;
                    322:        }
                    323: #endif
                    324:     }
                    325:
                    326:     /* set arrays and strings */
                    327:     si->cpustates = cpu_states;
                    328:     si->memory = memory_stats;
1.7       millert   329:     si->last_pid = -1;
1.1       downsj    330: }
                    331:
                    332: static struct handle handle;
                    333:
                    334: caddr_t get_process_info(si, sel, compare)
                    335:
                    336: struct system_info *si;
                    337: struct process_select *sel;
1.3       downsj    338: int (*compare) __P((const void *, const void *));
1.1       downsj    339:
                    340: {
                    341:     register int i;
                    342:     register int total_procs;
                    343:     register int active_procs;
                    344:     register struct kinfo_proc **prefp;
                    345:     register struct kinfo_proc *pp;
                    346:
                    347:     /* these are copied out of sel for speed */
                    348:     int show_idle;
                    349:     int show_system;
                    350:     int show_uid;
                    351:     int show_command;
                    352:
                    353:
1.19    ! niklas    354:     if ((pbase = kvm_getprocs(kd, KERN_PROC_KTHREAD, 0, &nproc)) == NULL) {
1.6       millert   355:        warnx("%s", kvm_geterr(kd));
                    356:        quit(23);
                    357:     }
1.1       downsj    358:     if (nproc > onproc)
                    359:        pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *)
                    360:                * (onproc = nproc));
1.6       millert   361:     if (pref == NULL) {
                    362:        warnx("Out of memory.");
1.1       downsj    363:        quit(23);
                    364:     }
                    365:     /* get a pointer to the states summary array */
                    366:     si->procstates = process_states;
                    367:
                    368:     /* set up flags which define what we are going to select */
                    369:     show_idle = sel->idle;
                    370:     show_system = sel->system;
                    371:     show_uid = sel->uid != -1;
                    372:     show_command = sel->command != NULL;
                    373:
                    374:     /* count up process states and get pointers to interesting procs */
                    375:     total_procs = 0;
                    376:     active_procs = 0;
                    377:     memset((char *)process_states, 0, sizeof(process_states));
                    378:     prefp = pref;
                    379:     for (pp = pbase, i = 0; i < nproc; pp++, i++)
                    380:     {
                    381:        /*
                    382:         *  Place pointers to each valid proc structure in pref[].
                    383:         *  Process slots that are actually in use have a non-zero
                    384:         *  status field.  Processes with SSYS set are system
                    385:         *  processes---these get ignored unless show_sysprocs is set.
                    386:         */
                    387:        if (PP(pp, p_stat) != 0 &&
                    388:            (show_system || ((PP(pp, p_flag) & P_SYSTEM) == 0)))
                    389:        {
                    390:            total_procs++;
                    391:            process_states[(unsigned char) PP(pp, p_stat)]++;
                    392:            if ((PP(pp, p_stat) != SZOMB) &&
                    393:                (show_idle || (PP(pp, p_pctcpu) != 0) ||
                    394:                 (PP(pp, p_stat) == SRUN)) &&
                    395:                (!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t)sel->uid))
                    396:            {
                    397:                *prefp++ = pp;
                    398:                active_procs++;
                    399:            }
                    400:        }
                    401:     }
                    402:
                    403:     /* if requested, sort the "interesting" processes */
                    404:     if (compare != NULL)
                    405:     {
                    406:        qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare);
                    407:     }
                    408:
                    409:     /* remember active and total counts */
                    410:     si->p_total = total_procs;
                    411:     si->p_active = pref_len = active_procs;
                    412:
                    413:     /* pass back a handle */
                    414:     handle.next_proc = pref;
                    415:     handle.remaining = active_procs;
                    416:     return((caddr_t)&handle);
                    417: }
                    418:
                    419: char fmt[MAX_COLS];            /* static area where result is built */
                    420:
                    421: char *format_next_process(handle, get_userid)
                    422:
                    423: caddr_t handle;
                    424: char *(*get_userid)();
                    425:
                    426: {
                    427:     register struct kinfo_proc *pp;
1.3       downsj    428:     register int cputime;
1.1       downsj    429:     register double pct;
                    430:     struct handle *hp;
                    431:     char waddr[sizeof(void *) * 2 + 3];        /* Hexify void pointer */
                    432:     char *p_wait;
                    433:
                    434:     /* find and remember the next proc structure */
                    435:     hp = (struct handle *)handle;
                    436:     pp = *(hp->next_proc++);
                    437:     hp->remaining--;
                    438:
                    439:
                    440:     /* get the process's user struct and set cputime */
                    441:     if ((PP(pp, p_flag) & P_INMEM) == 0) {
                    442:        /*
                    443:         * Print swapped processes as <pname>
                    444:         */
                    445:        char *comm = PP(pp, p_comm);
                    446: #define COMSIZ sizeof(PP(pp, p_comm))
                    447:        char buf[COMSIZ];
                    448:        (void) strncpy(buf, comm, COMSIZ);
                    449:        comm[0] = '<';
                    450:        (void) strncpy(&comm[1], buf, COMSIZ - 2);
                    451:        comm[COMSIZ - 2] = '\0';
                    452:        (void) strncat(comm, ">", COMSIZ - 1);
                    453:        comm[COMSIZ - 1] = '\0';
                    454:     }
                    455:
1.18      deraadt   456:     cputime = (PP(pp, p_uticks) + PP(pp, p_sticks) + PP(pp, p_iticks)) / stathz;
1.1       downsj    457:
                    458:     /* calculate the base for cpu percentages */
                    459:     pct = pctdouble(PP(pp, p_pctcpu));
                    460:
                    461:     if (PP(pp, p_wchan))
                    462:         if (PP(pp, p_wmesg))
                    463:            p_wait = EP(pp, e_wmesg);
                    464:        else {
1.4       downsj    465:            snprintf(waddr, sizeof(waddr), "%lx",
1.5       millert   466:                (unsigned long)(PP(pp, p_wchan)) & ~KERNBASE);
1.1       downsj    467:            p_wait = waddr;
                    468:         }
                    469:     else
                    470:        p_wait = "-";
                    471:
                    472:     /* format this entry */
                    473:     snprintf(fmt, MAX_COLS,
                    474:            Proc_format,
                    475:            PP(pp, p_pid),
                    476:            (*get_userid)(EP(pp, e_pcred.p_ruid)),
                    477:            PP(pp, p_priority) - PZERO,
                    478:            PP(pp, p_nice) - NZERO,
                    479:            format_k(pagetok(PROCSIZE(pp))),
                    480:            format_k(pagetok(VP(pp, vm_rssize))),
1.2       kstailey  481:            (PP(pp, p_stat) == SSLEEP && PP(pp, p_slptime) > MAXSLP)
                    482:             ? "idle" : state_abbrev[(unsigned char) PP(pp, p_stat)],
1.1       downsj    483:            p_wait,
                    484:            format_time(cputime),
                    485:            100.0 * pct,
                    486:            printable(PP(pp, p_comm)));
                    487:
                    488:     /* return the result */
                    489:     return(fmt);
                    490: }
                    491:
                    492:
                    493: /*
                    494:  * check_nlist(nlst) - checks the nlist to see if any symbols were not
                    495:  *             found.  For every symbol that was not found, a one-line
                    496:  *             message is printed to stderr.  The routine returns the
                    497:  *             number of symbols NOT found.
                    498:  */
                    499:
                    500: static int check_nlist(nlst)
                    501:
                    502: register struct nlist *nlst;
                    503:
                    504: {
                    505:     register int i;
                    506:
                    507:     /* check to see if we got ALL the symbols we requested */
                    508:     /* this will write one line to stderr for every symbol not found */
                    509:
                    510:     i = 0;
                    511:     while (nlst->n_name != NULL)
                    512:     {
                    513:        if (nlst->n_type == 0)
                    514:        {
                    515:            /* this one wasn't found */
                    516:            (void) fprintf(stderr, "kernel: no symbol named `%s'\n",
                    517:                           nlst->n_name);
                    518:            i = 1;
                    519:        }
                    520:        nlst++;
                    521:     }
                    522:
                    523:     return(i);
                    524: }
                    525:
                    526:
                    527: /*
                    528:  *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
                    529:  *     "offset" is the byte offset into the kernel for the desired value,
                    530:  *     "ptr" points to a buffer into which the value is retrieved,
                    531:  *     "size" is the size of the buffer (and the object to retrieve),
                    532:  *     "refstr" is a reference string used when printing error meessages,
                    533:  *         if "refstr" starts with a '!', then a failure on read will not
                    534:  *         be fatal (this may seem like a silly way to do things, but I
                    535:  *         really didn't want the overhead of another argument).
                    536:  *
                    537:  */
                    538:
                    539: static int getkval(offset, ptr, size, refstr)
                    540:
                    541: unsigned long offset;
                    542: int *ptr;
                    543: int size;
                    544: char *refstr;
                    545:
                    546: {
1.16      art       547:     if (kvm_read(kd, offset, ptr, size) != size)
1.1       downsj    548:     {
                    549:        if (*refstr == '!')
                    550:        {
                    551:            return(0);
                    552:        }
                    553:        else
                    554:        {
1.6       millert   555:            warn("kvm_read for %s", refstr);
1.1       downsj    556:            quit(23);
                    557:        }
                    558:     }
                    559:     return(1);
                    560: }
                    561:
                    562: /* comparison routine for qsort */
                    563:
1.11      kstailey  564: static unsigned char sorted_state[] =
                    565: {
                    566:     0, /* not used             */
                    567:     4, /* start                */
                    568:     5, /* run                  */
                    569:     2, /* sleep                */
                    570:     3, /* stop                 */
                    571:     1  /* zombie               */
                    572: };
                    573:
                    574: #ifdef ORDER
                    575:
                    576: /*
                    577:  *  proc_compares - comparison functions for "qsort"
                    578:  */
                    579:
                    580: /*
                    581:  * First, the possible comparison keys.  These are defined in such a way
                    582:  * that they can be merely listed in the source code to define the actual
                    583:  * desired ordering.
                    584:  */
                    585:
                    586:
                    587: #define ORDERKEY_PCTCPU \
1.12      niklas    588:        if (lresult = (pctcpu)PP(p2, p_pctcpu) - (pctcpu)PP(p1, p_pctcpu), \
1.11      kstailey  589:            (result = lresult > 0 ? 1 : lresult < 0 ? -1 : 0) == 0)
                    590: #define ORDERKEY_CPUTIME \
                    591:        if ((result = PP(p2, p_rtime.tv_sec) - PP(p1, p_rtime.tv_sec)) == 0) \
                    592:                if ((result = PP(p2, p_rtime.tv_usec) - \
                    593:                     PP(p1, p_rtime.tv_usec)) == 0)
                    594: #define ORDERKEY_STATE \
                    595:        if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] - \
                    596:                       sorted_state[(unsigned char) PP(p1, p_stat)])  == 0)
                    597: #define ORDERKEY_PRIO \
                    598:        if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0)
                    599: #define ORDERKEY_RSSIZE \
                    600:        if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
                    601: #define ORDERKEY_MEM \
                    602:        if ((result = PROCSIZE(p2) - PROCSIZE(p1)) == 0)
                    603:
                    604:
                    605: /* compare_cpu - the comparison function for sorting by cpu percentage */
                    606:
                    607: int
                    608: compare_cpu(v1, v2)
                    609:
                    610: const void *v1, *v2;
                    611:
                    612: {
                    613:     register struct proc **pp1 = (struct proc **)v1;
                    614:     register struct proc **pp2 = (struct proc **)v2;
                    615:     register struct kinfo_proc *p1;
                    616:     register struct kinfo_proc *p2;
                    617:     register int result;
                    618:     register pctcpu lresult;
                    619:
                    620:     /* remove one level of indirection */
                    621:     p1 = *(struct kinfo_proc **) pp1;
                    622:     p2 = *(struct kinfo_proc **) pp2;
                    623:
                    624:     ORDERKEY_PCTCPU
                    625:     ORDERKEY_CPUTIME
                    626:     ORDERKEY_STATE
                    627:     ORDERKEY_PRIO
                    628:     ORDERKEY_RSSIZE
                    629:     ORDERKEY_MEM
                    630:     ;
                    631:     return(result);
                    632: }
                    633:
                    634: /* compare_size - the comparison function for sorting by total memory usage */
                    635:
                    636: int
                    637: compare_size(v1, v2)
                    638:
                    639: const void *v1, *v2;
                    640:
                    641: {
                    642:     register struct proc **pp1 = (struct proc **)v1;
                    643:     register struct proc **pp2 = (struct proc **)v2;
                    644:     register struct kinfo_proc *p1;
                    645:     register struct kinfo_proc *p2;
                    646:     register int result;
                    647:     register pctcpu lresult;
                    648:
                    649:     /* remove one level of indirection */
                    650:     p1 = *(struct kinfo_proc **) pp1;
                    651:     p2 = *(struct kinfo_proc **) pp2;
                    652:
                    653:     ORDERKEY_MEM
                    654:     ORDERKEY_RSSIZE
                    655:     ORDERKEY_PCTCPU
                    656:     ORDERKEY_CPUTIME
                    657:     ORDERKEY_STATE
                    658:     ORDERKEY_PRIO
                    659:     ;
                    660:
                    661:     return(result);
                    662: }
                    663:
                    664: /* compare_res - the comparison function for sorting by resident set size */
                    665:
                    666: int
                    667: compare_res(v1, v2)
                    668:
                    669: const void *v1, *v2;
                    670:
                    671: {
                    672:     register struct proc **pp1 = (struct proc **)v1;
                    673:     register struct proc **pp2 = (struct proc **)v2;
                    674:     register struct kinfo_proc *p1;
                    675:     register struct kinfo_proc *p2;
                    676:     register int result;
                    677:     register pctcpu lresult;
                    678:
                    679:     /* remove one level of indirection */
                    680:     p1 = *(struct kinfo_proc **) pp1;
                    681:     p2 = *(struct kinfo_proc **) pp2;
                    682:
                    683:     ORDERKEY_RSSIZE
                    684:     ORDERKEY_MEM
                    685:     ORDERKEY_PCTCPU
                    686:     ORDERKEY_CPUTIME
                    687:     ORDERKEY_STATE
                    688:     ORDERKEY_PRIO
                    689:     ;
                    690:
                    691:     return(result);
                    692: }
                    693:
                    694: /* compare_time - the comparison function for sorting by CPU time */
                    695:
                    696: int
                    697: compare_time(v1, v2)
                    698:
                    699: const void *v1, *v2;
                    700:
                    701: {
                    702:     register struct proc **pp1 = (struct proc **)v1;
                    703:     register struct proc **pp2 = (struct proc **)v2;
                    704:     register struct kinfo_proc *p1;
                    705:     register struct kinfo_proc *p2;
                    706:     register int result;
                    707:     register pctcpu lresult;
                    708:
                    709:     /* remove one level of indirection */
                    710:     p1 = *(struct kinfo_proc **) pp1;
                    711:     p2 = *(struct kinfo_proc **) pp2;
                    712:
                    713:     ORDERKEY_CPUTIME
                    714:     ORDERKEY_PCTCPU
                    715:     ORDERKEY_STATE
                    716:     ORDERKEY_PRIO
                    717:     ORDERKEY_MEM
                    718:     ORDERKEY_RSSIZE
                    719:     ;
                    720:
                    721:     return(result);
                    722: }
                    723:
                    724: /* compare_prio - the comparison function for sorting by CPU time */
                    725:
                    726: int
                    727: compare_prio(v1, v2)
                    728:
                    729: const void *v1, *v2;
                    730:
                    731: {
                    732:     register struct proc **pp1 = (struct proc **)v1;
                    733:     register struct proc **pp2 = (struct proc **)v2;
                    734:     register struct kinfo_proc *p1;
                    735:     register struct kinfo_proc *p2;
                    736:     register int result;
                    737:     register pctcpu lresult;
                    738:
                    739:     /* remove one level of indirection */
                    740:     p1 = *(struct kinfo_proc **) pp1;
                    741:     p2 = *(struct kinfo_proc **) pp2;
                    742:
                    743:     ORDERKEY_PRIO
                    744:     ORDERKEY_PCTCPU
                    745:     ORDERKEY_CPUTIME
                    746:     ORDERKEY_STATE
                    747:     ORDERKEY_RSSIZE
                    748:     ORDERKEY_MEM
                    749:     ;
                    750:
                    751:     return(result);
                    752: }
                    753:
                    754: int (*proc_compares[])() = {
                    755:     compare_cpu,
                    756:     compare_size,
                    757:     compare_res,
                    758:     compare_time,
                    759:     compare_prio,
                    760:     NULL
                    761: };
                    762: #else
1.1       downsj    763: /*
                    764:  *  proc_compare - comparison function for "qsort"
                    765:  *     Compares the resource consumption of two processes using five
                    766:  *     distinct keys.  The keys (in descending order of importance) are:
                    767:  *     percent cpu, cpu ticks, state, resident set size, total virtual
                    768:  *     memory usage.  The process states are ordered as follows (from least
                    769:  *     to most important):  zombie, sleep, stop, start, run.  The array
                    770:  *     declaration below maps a process state index into a number that
                    771:  *     reflects this ordering.
                    772:  */
                    773:
                    774: int
1.3       downsj    775: proc_compare(v1, v2)
1.1       downsj    776:
1.3       downsj    777: const void *v1, *v2;
1.1       downsj    778:
                    779: {
1.3       downsj    780:     register struct proc **pp1 = (struct proc **)v1;
                    781:     register struct proc **pp2 = (struct proc **)v2;
1.1       downsj    782:     register struct kinfo_proc *p1;
                    783:     register struct kinfo_proc *p2;
                    784:     register int result;
                    785:     register pctcpu lresult;
                    786:
                    787:     /* remove one level of indirection */
                    788:     p1 = *(struct kinfo_proc **) pp1;
                    789:     p2 = *(struct kinfo_proc **) pp2;
                    790:
                    791:     /* compare percent cpu (pctcpu) */
                    792:     if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0)
                    793:     {
1.8       millert   794:        /* use CPU usage to break the tie */
                    795:        if ((result = PP(p2, p_rtime).tv_sec - PP(p1, p_rtime).tv_sec) == 0)
1.1       downsj    796:        {
                    797:            /* use process state to break the tie */
                    798:            if ((result = sorted_state[(unsigned char) PP(p2, p_stat)] -
                    799:                          sorted_state[(unsigned char) PP(p1, p_stat)])  == 0)
                    800:            {
                    801:                /* use priority to break the tie */
                    802:                if ((result = PP(p2, p_priority) - PP(p1, p_priority)) == 0)
                    803:                {
                    804:                    /* use resident set size (rssize) to break the tie */
                    805:                    if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
                    806:                    {
                    807:                        /* use total memory to break the tie */
                    808:                        result = PROCSIZE(p2) - PROCSIZE(p1);
                    809:                    }
                    810:                }
                    811:            }
                    812:        }
                    813:     }
                    814:     else
                    815:     {
                    816:        result = lresult < 0 ? -1 : 1;
                    817:     }
                    818:
                    819:     return(result);
                    820: }
1.11      kstailey  821: #endif
1.1       downsj    822:
                    823: /*
                    824:  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
                    825:  *             the process does not exist.
                    826:  *             It is EXTREMLY IMPORTANT that this function work correctly.
                    827:  *             If top runs setuid root (as in SVR4), then this function
                    828:  *             is the only thing that stands in the way of a serious
                    829:  *             security problem.  It validates requests for the "kill"
                    830:  *             and "renice" commands.
                    831:  */
                    832:
                    833: int proc_owner(pid)
                    834:
1.3       downsj    835: pid_t pid;
1.1       downsj    836:
                    837: {
                    838:     register int cnt;
                    839:     register struct kinfo_proc **prefp;
                    840:     register struct kinfo_proc *pp;
                    841:
                    842:     prefp = pref;
                    843:     cnt = pref_len;
                    844:     while (--cnt >= 0)
                    845:     {
                    846:        pp = *prefp++;
1.3       downsj    847:        if (PP(pp, p_pid) == pid)
1.1       downsj    848:        {
                    849:            return((int)EP(pp, e_pcred.p_ruid));
                    850:        }
                    851:     }
                    852:     return(-1);
                    853: }
                    854:
                    855: #ifdef DOSWAP
                    856: /*
1.17      todd      857:  * swapmode is rewritten by Tobias Weingartner <weingart@openbsd.org>
1.15      weingart  858:  * to be based on the new swapctl(2) system call.
1.1       downsj    859:  */
                    860: static int
                    861: swapmode(used, total)
                    862: int *used;
                    863: int *total;
                    864: {
1.15      weingart  865:        int nswap, rnswap, i;
                    866:        struct swapent *swdev;
1.1       downsj    867:
1.15      weingart  868:        nswap = swapctl(SWAP_NSWAP, 0, 0);
                    869:        if (nswap == 0)
                    870:                return 0;
                    871:
                    872:        swdev = malloc(nswap * sizeof(*swdev));
                    873:        if(swdev == NULL)
                    874:                return 0;
                    875:
                    876:        rnswap = swapctl(SWAP_STATS, swdev, nswap);
                    877:        if(rnswap == -1)
                    878:                return 0;
                    879:
                    880:        /* if rnswap != nswap, then what? */
                    881:
                    882:        /* Total things up */
                    883:        *total = *used = 0;
                    884:        for (i = 0; i < nswap; i++) {
                    885:                if (swdev[i].se_flags & SWF_ENABLE) {
                    886:                        *used += (swdev[i].se_inuse / (1024/DEV_BSIZE));
                    887:                        *total += (swdev[i].se_nblks / (1024/DEV_BSIZE));
1.1       downsj    888:                }
                    889:        }
                    890:
1.15      weingart  891:        free (swdev);
1.1       downsj    892:        return 1;
                    893: }
                    894: #endif