home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Utilities / top-0.5-MI / machine / m_netbsd08.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-18  |  16.9 KB  |  723 lines

  1. /*
  2.  * top - a top users display for Unix
  3.  *
  4.  * SYNOPSIS:  For a NetBSD system
  5.  *
  6.  * DESCRIPTION:
  7.  * This is the machine-dependent module for NetBSD
  8.  * READ THE NOTE AT THE END OF "INSTALL" BEFORE COMPILING.
  9.  * Tested only with a:
  10.  *    i386
  11.  *
  12.  * LIBS: -lkvm
  13.  *
  14.  * AUTHOR:  Christos Zoulas <christos@ee.cornell.edu>
  15.  *        [originally from m_386bsd.c]
  16.  */
  17.  
  18. #include <sys/types.h>
  19. #include <sys/signal.h>
  20. #include <sys/param.h>
  21.  
  22. #include <stdio.h>
  23. #include <nlist.h>
  24. #include <math.h>
  25. #include <kvm.h>
  26. #include <sys/errno.h>
  27. #include <sys/kinfo.h>
  28. #include <sys/kinfo_proc.h>
  29. #ifdef notyet
  30. #define time __time
  31. #define hz __hz
  32. #include <sys/kernel.h>
  33. #undef time
  34. #undef hz
  35. #endif
  36. #include <sys/dir.h>
  37. #include <sys/dkstat.h>
  38. #include <sys/file.h>
  39. #include <sys/time.h>
  40. #include <sys/vmmeter.h>
  41. #include <sys/resource.h>
  42.  
  43.  
  44. /* #define PATCHED_KVM        /* READ THE FOLLOWING NOTE: */
  45.                 /* define this ONLY if your version of 386bsd
  46.                    has patchkit 2.4 installed. */
  47.  
  48. /* #define TOTAL_WORKING */    /* Uncomment when the total structure in */
  49.                 /* the kernel actually works */
  50. #define DOSWAP
  51. #define GETLOADAVG
  52.  
  53. #include "top.h"
  54. #include "machine.h"
  55. #include "utils.h"
  56.  
  57. #define VMUNIX    "/netbsd"
  58. #define KMEM    "/dev/kmem"
  59. #define MEM    "/dev/mem"
  60. #ifdef DOSWAP
  61. #define SWAP    "/dev/drum"
  62. #endif
  63.  
  64. typedef struct _kinfo {
  65.         struct proc ki_p;      /* proc structure */
  66.         struct eproc ki_e;     /* extra stuff */
  67. } KINFO;
  68.  
  69. /* get_process_info passes back a handle.  This is what it looks like: */
  70.  
  71. struct handle
  72. {
  73.     KINFO **next_proc;    /* points to next valid proc pointer */
  74.     int remaining;        /* number of pointers remaining */
  75. };
  76.  
  77. /* declarations for load_avg */
  78. #include "loadavg.h"
  79.  
  80. #define PP(pp, field) ((pp)->ki_p . field)
  81. #define EP(pp, field) ((pp)->ki_e . field)
  82. #define VP(pp, field) ((pp)->ki_e.e_vm . field)
  83.  
  84. /* define what weighted cpu is.  */
  85. #define weighted_cpu(pct, pp) (PP((pp), p_time) == 0 ? 0.0 : \
  86.              ((pct) / (1.0 - exp(PP((pp), p_time) * logcpu))))
  87.  
  88. /* what we consider to be process size: */
  89. #define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp), vm_ssize))
  90.  
  91. /* definitions for indices in the nlist array */
  92. #define X_CCPU        0
  93. #define X_CP_TIME    1
  94. #define X_HZ        2
  95. #define X_TOTAL        3
  96. #if !defined(KINFO_LOADAVG) && !defined(GETLOADAVG)
  97. # define X_AVENRUN    4
  98. # define XX_LAST    4
  99. #else
  100. # define XX_LAST    3
  101. #endif
  102. #ifndef TOTAL_WORKING
  103. # define X_PG_FREE    (XX_LAST + 1)
  104. # define X_PG_ACTIVE    (XX_LAST + 2)
  105. # define X_PG_INACTIVE    (XX_LAST + 3)
  106. # define X_PG_WIRED    (XX_LAST + 4)
  107. #endif
  108.  
  109. static struct nlist nlst[] = {
  110.     { "_ccpu" },        /* 0 */
  111.     { "_cp_time" },        /* 1 */
  112.     { "_hz" },            /* 2 */
  113.     { "_total"},        /* 3 */
  114. #if !defined(KINFO_LOADAVG) && !defined(GETLOADAVG)
  115.     { "_averunnable" },        
  116. #endif
  117. #ifndef TOTAL_WORKING
  118.     { "_vm_page_free_count" },
  119.     { "_vm_page_active_count" },
  120.     { "_vm_page_inactive_count" },
  121.     { "_vm_page_wire_count" },    
  122. #endif
  123.     { 0 }
  124. };
  125.  
  126. /*
  127.  *  These definitions control the format of the per-process area
  128.  */
  129.  
  130. static char header[] =
  131.   "  PID X        PRI NICE  SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
  132. /* 0123456   -- field to fill in starts at header+6 */
  133. #define UNAME_START 6
  134.  
  135. #define Proc_format \
  136.     "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %.14s"
  137.  
  138.  
  139. /* process state names for the "STATE" column of the display */
  140. /* the extra nulls in the string "run" are for adding a slash and
  141.    the processor number when needed */
  142.  
  143. char *state_abbrev[] =
  144. {
  145.     "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
  146. };
  147.  
  148.  
  149. /* values that we stash away in _init and use in later routines */
  150.  
  151. static double logcpu;
  152.  
  153. /* these are retrieved from the kernel in _init */
  154.  
  155. static          long hz;
  156. static load_avg  ccpu;
  157. static          int  ncpu = 0;
  158.  
  159. /* these are offsets obtained via nlist and used in the get_ functions */
  160.  
  161. static unsigned long cp_time_offset;
  162. #if !defined(KINFO_LOADAVG) && !defined(GETLOADAVG)
  163. static unsigned long avenrun_offset;
  164. #endif
  165.  
  166. /* these are for calculating cpu state percentages */
  167.  
  168. static long cp_time[CPUSTATES];
  169. static long cp_old[CPUSTATES];
  170. static long cp_diff[CPUSTATES];
  171.  
  172. /* these are for detailing the process states */
  173.  
  174. int process_states[7];
  175. char *procstatenames[] = {
  176.     "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
  177.     " zombie, ", " stopped, ",
  178.     NULL
  179. };
  180.  
  181. /* these are for detailing the cpu states */
  182.  
  183. int cpu_states[4];
  184. char *cpustatenames[] = {
  185.     "user", "nice", "system", "idle", NULL
  186. };
  187.  
  188. /* these are for detailing the memory statistics */
  189.  
  190. int memory_stats[8];
  191. char *memorynames[] = {
  192. #ifdef    TOTAL_WORKING
  193.     "Real: ", "K/", "K ", "Virt: ", "K/",
  194.     "K ", "Free: ", "K", NULL
  195. #else
  196.     " Free: ", "K ", " Active: ", "K ", " Inactive: ",
  197.     "K ", " Wired: ", "K ", NULL
  198. #endif
  199. };
  200.  
  201. /* these are for keeping track of the proc array */
  202.  
  203. static int bytes;
  204. static int nproc;
  205. static int onproc = -1;
  206. static int pref_len;
  207. static KINFO *pbase;
  208. static KINFO **pref;
  209.  
  210. /* these are for getting the memory statistics */
  211.  
  212. static int pageshift;        /* log base 2 of the pagesize */
  213.  
  214. /* define pagetok in terms of pageshift */
  215.  
  216. #define pagetok(size) ((size) << pageshift)
  217.  
  218. machine_init(statics)
  219.  
  220. struct statics *statics;
  221.  
  222. {
  223.     register int i = 0;
  224.     register int pagesize;
  225.     char buf[1024];
  226.  
  227. #if 0        /* some funny stuff going on here */
  228.     if (kvm_openfiles(NULL, NULL, NULL) == -1);
  229.     return -1;
  230. #else
  231.     kvm_openfiles(VMUNIX, NULL, NULL);
  232. #endif
  233.  
  234.     /* get the list of symbols we want to access in the kernel */
  235.     (void) kvm_nlist(nlst);
  236.     if (nlst[0].n_type == 0)
  237.     {
  238.     fprintf(stderr, "top: nlist failed\n");
  239.     return(-1);
  240.     }
  241.  
  242.     /* make sure they were all found */
  243.     if (i > 0 && check_nlist(nlst) > 0)
  244.     {
  245.     return(-1);
  246.     }
  247.  
  248.     /* get the symbol values out of kmem */
  249.     (void) getkval(nlst[X_HZ].n_value,     (int *)(&hz),    sizeof(hz),
  250.         nlst[X_HZ].n_name);
  251.     (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),    sizeof(ccpu),
  252.         nlst[X_CCPU].n_name);
  253.  
  254.     /* stash away certain offsets for later use */
  255.     cp_time_offset = nlst[X_CP_TIME].n_value;
  256. #ifndef KINFO_LOADAVG
  257.     avenrun_offset = nlst[X_AVENRUN].n_value;
  258. #endif
  259.  
  260.     /* this is used in calculating WCPU -- calculate it ahead of time */
  261.     logcpu = log(loaddouble(ccpu));
  262.  
  263.     pbase = NULL;
  264.     pref = NULL;
  265.     nproc = 0;
  266.     onproc = -1;
  267.     /* get the page size with "getpagesize" and calculate pageshift from it */
  268.     pagesize = getpagesize();
  269.     pageshift = 0;
  270.     while (pagesize > 1)
  271.     {
  272.     pageshift++;
  273.     pagesize >>= 1;
  274.     }
  275.  
  276.     /* we only need the amount of log(2)1024 for our conversion */
  277.     pageshift -= LOG1024;
  278.  
  279.     /* fill in the statics information */
  280.     statics->procstate_names = procstatenames;
  281.     statics->cpustate_names = cpustatenames;
  282.     statics->memory_names = memorynames;
  283.  
  284.     /* all done! */
  285.     return(0);
  286. }
  287.  
  288. char *format_header(uname_field)
  289.  
  290. register char *uname_field;
  291.  
  292. {
  293.     register char *ptr;
  294.  
  295.     ptr = header + UNAME_START;
  296.     while (*uname_field != '\0')
  297.     {
  298.     *ptr++ = *uname_field++;
  299.     }
  300.  
  301.     return(header);
  302. }
  303.  
  304. get_system_info(si)
  305.  
  306. struct system_info *si;
  307.  
  308. {
  309.     long total;
  310. #if !defined(KINFO_LOADAVG) && !defined(GETLOADAVG)
  311.     load_avg avenrun[3];
  312. #endif
  313.  
  314.     /* get the cp_time array */
  315.     (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
  316.            "_cp_time");
  317.  
  318. #ifndef GETLOADAVG
  319.  
  320. # ifndef KINFO_LOADAVG
  321.     (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
  322.            "_avenrun");
  323. # endif
  324.  
  325.     /* convert load averages to doubles */
  326.     {
  327.     register int i;
  328.     register double *infoloadp;
  329.  
  330. # ifdef KINFO_LOADAVG
  331.     struct loadavg sysload;
  332.     int size;
  333.     getkerninfo(KINFO_LOADAVG, &sysload, &size, 0);
  334. # else
  335.     load_avg *avenrunp;
  336.     avenrunp = avenrun;
  337. # endif
  338.  
  339.     infoloadp = si->load_avg;
  340.     for (i = 0; i < 3; i++)
  341.     {
  342. # ifdef KINFO_LOADAVG
  343.         *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
  344. # else
  345.         *infoloadp++ = loaddouble(*avenrunp++);
  346. # endif
  347.     }
  348.     }
  349. #else
  350.     getloadavg(si->load_avg, 3);
  351. #endif
  352.  
  353.     /* convert cp_time counts to percentages */
  354.     total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
  355.  
  356.     /* sum memory statistics */
  357.     {
  358. #ifdef TOTAL_WORKING
  359.     static struct vmtotal total;
  360.     int size;
  361.  
  362.     /* get total -- systemwide main memory usage structure */
  363. #ifdef KINFO_METER
  364.     getkerninfo(KINFO_METER, &total, &size, 0);
  365. #else
  366.     (void) getkval(nlst[X_TOTAL].n_value, (int *)(&total), sizeof(total),
  367.         nlst[X_TOTAL].n_name);
  368. #endif
  369.     /* convert memory stats to Kbytes */
  370.     memory_stats[0] = -1;
  371.     memory_stats[1] = pagetok(total.t_arm);
  372.     memory_stats[2] = pagetok(total.t_rm);
  373.     memory_stats[3] = -1;
  374.     memory_stats[4] = pagetok(total.t_avm);
  375.     memory_stats[5] = pagetok(total.t_vm);
  376.     memory_stats[6] = -1;
  377.     memory_stats[7] = pagetok(total.t_free);
  378. #else
  379.         static int free, active, inactive, wired;
  380.  
  381.     (void) getkval(nlst[X_PG_FREE].n_value, (int *)(&free), sizeof(free),
  382.                 nlst[X_PG_FREE].n_name);
  383.     (void) getkval(nlst[X_PG_ACTIVE].n_value, (int *)(&active), sizeof(active),
  384.                 nlst[X_PG_ACTIVE].n_name);
  385.     (void) getkval(nlst[X_PG_INACTIVE].n_value, (int *)(&inactive), sizeof(inactive),
  386.                 nlst[X_PG_INACTIVE].n_name);
  387.     (void) getkval(nlst[X_PG_WIRED].n_value, (int *)(&wired), sizeof(wired),
  388.                 nlst[X_PG_WIRED].n_name);
  389.     memory_stats[0] = -1;
  390.     memory_stats[1] = pagetok(free);
  391.     memory_stats[2] = -1;
  392.     memory_stats[3] = pagetok(active);
  393.     memory_stats[4] = -1;
  394.     memory_stats[5] = pagetok(inactive);
  395.     memory_stats[6] = -1;
  396.     memory_stats[7] = pagetok(wired);
  397. #endif
  398.     }
  399.  
  400.     /* set arrays and strings */
  401.     si->cpustates = cpu_states;
  402.     si->memory = memory_stats;
  403.     si->last_pid = -1;
  404. }
  405.  
  406. static struct handle handle;
  407.  
  408. caddr_t get_process_info(si, sel, compare)
  409.  
  410. struct system_info *si;
  411. struct process_select *sel;
  412. int (*compare)();
  413.  
  414. {
  415.     register int i;
  416.     register int total_procs;
  417.     register int active_procs;
  418.     register KINFO **prefp;
  419.     KINFO *pp;
  420.     struct proc *pr;
  421.     struct eproc *epr;
  422.  
  423.     /* these are copied out of sel for speed */
  424.     int show_idle;
  425.     int show_system;
  426.     int show_uid;
  427.     int show_command;
  428.  
  429.     
  430.     nproc = kvm_getprocs(KINFO_PROC_ALL, 0);
  431.     if (nproc > onproc)
  432.     {
  433.     pref = (KINFO **) realloc(pref, sizeof(KINFO *)
  434.         * nproc);
  435.         pbase = (KINFO *) realloc(pbase, sizeof(KINFO)
  436.                 * (nproc + 2));
  437.         onproc = nproc;
  438.     }
  439.     if (pref == NULL || pbase == NULL) {
  440.     (void) fprintf(stderr, "top: Out of memory.\n");
  441.     quit(23);
  442.     }
  443.     /* get a pointer to the states summary array */
  444.     si->procstates = process_states;
  445.  
  446.     /* set up flags which define what we are going to select */
  447.     show_idle = sel->idle;
  448.     show_system = sel->system;
  449.     show_uid = sel->uid != -1;
  450.     show_command = sel->command != NULL;
  451.  
  452.     /* count up process states and get pointers to interesting procs */
  453.     total_procs = 0;
  454.     active_procs = 0;
  455.     memset((char *)process_states, 0, sizeof(process_states));
  456.     prefp = pref;
  457.     for (pp = pbase, i = 0; pr = kvm_nextproc(); pp++, i++)
  458.     {
  459.     /*
  460.      *  Place pointers to each valid proc structure in pref[].
  461.      *  Process slots that are actually in use have a non-zero
  462.      *  status field.  Processes with SSYS set are system
  463.      *  processes---these get ignored unless show_sysprocs is set.
  464.      */
  465.         epr = kvm_geteproc(pr);
  466.         pp->ki_p = *pr;
  467.         pp->ki_e = *epr;
  468.     if (PP(pp, p_stat) != 0 &&
  469.         (show_system || ((PP(pp, p_flag) & SSYS) == 0)))
  470.     {
  471.         total_procs++;
  472.         process_states[PP(pp, p_stat)]++;
  473.         if ((PP(pp, p_stat) != SZOMB) &&
  474.         (show_idle || (PP(pp, p_pctcpu) != 0) || 
  475.          (PP(pp, p_stat) == SRUN)) &&
  476.         (!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t)sel->uid))
  477.         {
  478.         *prefp++ = pp;
  479.         active_procs++;
  480.         }
  481.     }
  482.     }
  483.  
  484.     /* if requested, sort the "interesting" processes */
  485.     if (compare != NULL)
  486.     {
  487.     qsort((char *)pref, active_procs, sizeof(KINFO *), compare);
  488.     }
  489.  
  490.     /* remember active and total counts */
  491.     si->p_total = total_procs;
  492.     si->p_active = pref_len = active_procs;
  493.  
  494.     /* pass back a handle */
  495.     handle.next_proc = pref;
  496.     handle.remaining = active_procs;
  497. #ifndef PATCHED_KVM
  498.     kvm_freeprocs();
  499. #endif
  500.     return((caddr_t)&handle);
  501. }
  502.  
  503. char fmt[MAX_COLS];        /* static area where result is built */
  504.  
  505. char *format_next_process(handle, get_userid)
  506.  
  507. caddr_t handle;
  508. char *(*get_userid)();
  509.  
  510. {
  511.     register KINFO *pp;
  512.     register long cputime;
  513.     register double pct;
  514.     int where;
  515.     struct handle *hp;
  516.  
  517.     /* find and remember the next proc structure */
  518.     hp = (struct handle *)handle;
  519.     pp = *(hp->next_proc++);
  520.     hp->remaining--;
  521.     
  522.  
  523.     /* get the process's user struct and set cputime */
  524.     cputime = PP(pp, p_utime.tv_sec) + PP(pp, p_stime.tv_sec);
  525.  
  526.     /* calculate the base for cpu percentages */
  527.     pct = pctdouble(PP(pp, p_pctcpu));
  528.  
  529.     /* format this entry */
  530.     sprintf(fmt,
  531.         Proc_format,
  532.         PP(pp, p_pid),
  533.         (*get_userid)(EP(pp, e_pcred.p_ruid)),
  534.         PP(pp, p_pri) - PZERO,
  535.         PP(pp, p_nice) - NZERO,
  536.         format_k(pagetok(PROCSIZE(pp))),
  537. #ifdef notyet
  538.         format_k(pagetok(VP(pp, vm_rssize))),
  539. #else
  540.             format_k(pagetok(pp->ki_e.e_vm.vm_pmap.pm_stats.resident_count)),
  541. #endif
  542.         state_abbrev[PP(pp, p_stat)],
  543.         format_time(cputime),
  544.         100.0 * weighted_cpu(pct, pp),
  545.         100.0 * pct,
  546.         printable(PP(pp, p_comm)));
  547.  
  548.     /* return the result */
  549.     return(fmt);
  550. }
  551.  
  552.  
  553. /*
  554.  * check_nlist(nlst) - checks the nlist to see if any symbols were not
  555.  *        found.  For every symbol that was not found, a one-line
  556.  *        message is printed to stderr.  The routine returns the
  557.  *        number of symbols NOT found.
  558.  */
  559.  
  560. int check_nlist(nlst)
  561.  
  562. register struct nlist *nlst;
  563.  
  564. {
  565.     register int i;
  566.  
  567.     /* check to see if we got ALL the symbols we requested */
  568.     /* this will write one line to stderr for every symbol not found */
  569.  
  570.     i = 0;
  571.     while (nlst->n_name != NULL)
  572.     {
  573.     if (nlst->n_type == 0)
  574.     {
  575.         /* this one wasn't found */
  576.         fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
  577.         i = 1;
  578.     }
  579.     nlst++;
  580.     }
  581.  
  582.     return(i);
  583. }
  584.  
  585.  
  586. /*
  587.  *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
  588.  *    "offset" is the byte offset into the kernel for the desired value,
  589.  *      "ptr" points to a buffer into which the value is retrieved,
  590.  *      "size" is the size of the buffer (and the object to retrieve),
  591.  *      "refstr" is a reference string used when printing error meessages,
  592.  *        if "refstr" starts with a '!', then a failure on read will not
  593.  *          be fatal (this may seem like a silly way to do things, but I
  594.  *          really didn't want the overhead of another argument).
  595.  *      
  596.  */
  597.  
  598. getkval(offset, ptr, size, refstr)
  599.  
  600. unsigned long offset;
  601. int *ptr;
  602. int size;
  603. char *refstr;
  604.  
  605. {
  606.     if (kvm_read((void *) offset, (void *) ptr, size) != size)
  607.     {
  608.     if (*refstr == '!')
  609.     {
  610.         return(0);
  611.     }
  612.     else
  613.     {
  614.         fprintf(stderr, "top: kvm_read for %s: %s\n",
  615.         refstr, strerror(errno));
  616.         quit(23);
  617.     }
  618.     }
  619.     return(1);
  620. }
  621.     
  622. /* comparison routine for qsort */
  623.  
  624. /*
  625.  *  proc_compare - comparison function for "qsort"
  626.  *    Compares the resource consumption of two processes using five
  627.  *      distinct keys.  The keys (in descending order of importance) are:
  628.  *      percent cpu, cpu ticks, state, resident set size, total virtual
  629.  *      memory usage.  The process states are ordered as follows (from least
  630.  *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
  631.  *      array declaration below maps a process state index into a number
  632.  *      that reflects this ordering.
  633.  */
  634.  
  635. static unsigned char sorted_state[] =
  636. {
  637.     0,    /* not used        */
  638.     3,    /* sleep        */
  639.     1,    /* ABANDONED (WAIT)    */
  640.     6,    /* run            */
  641.     5,    /* start        */
  642.     2,    /* zombie        */
  643.     4    /* stop            */
  644. };
  645.  
  646. proc_compare(pp1, pp2)
  647.  
  648. KINFO **pp1;
  649. KINFO **pp2;
  650.  
  651. {
  652.     register KINFO *p1;
  653.     register KINFO *p2;
  654.     register int result;
  655.     register pctcpu lresult;
  656.  
  657.     /* remove one level of indirection */
  658.     p1 = *pp1;
  659.     p2 = *pp2;
  660.  
  661.     /* compare percent cpu (pctcpu) */
  662.     if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0)
  663.     {
  664.     /* use cpticks to break the tie */
  665.     if ((result = PP(p2, p_cpticks) - PP(p1, p_cpticks)) == 0)
  666.     {
  667.         /* use process state to break the tie */
  668.         if ((result = sorted_state[PP(p2, p_stat)] -
  669.               sorted_state[PP(p1, p_stat)])  == 0)
  670.         {
  671.         /* use priority to break the tie */
  672.         if ((result = PP(p2, p_pri) - PP(p1, p_pri)) == 0)
  673.         {
  674.             /* use resident set size (rssize) to break the tie */
  675.             if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
  676.             {
  677.             /* use total memory to break the tie */
  678.             result = PROCSIZE(p2) - PROCSIZE(p1);
  679.             }
  680.         }
  681.         }
  682.     }
  683.     }
  684.     else
  685.     {
  686.     result = lresult < 0 ? -1 : 1;
  687.     }
  688.  
  689.     return(result);
  690. }
  691.  
  692. /*
  693.  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
  694.  *        the process does not exist.
  695.  *        It is EXTREMLY IMPORTANT that this function work correctly.
  696.  *        If top runs setuid root (as in SVR4), then this function
  697.  *        is the only thing that stands in the way of a serious
  698.  *        security problem.  It validates requests for the "kill"
  699.  *        and "renice" commands.
  700.  */
  701.  
  702. int proc_owner(pid)
  703.  
  704. int pid;
  705.  
  706. {
  707.     register int cnt;
  708.     register KINFO **prefp;
  709.     register KINFO *pp;
  710.  
  711.     prefp = pref;
  712.     cnt = pref_len;
  713.     while (--cnt >= 0)
  714.     {
  715.     pp = *prefp++;
  716.     if (PP(pp, p_pid) == (pid_t)pid)
  717.     {
  718.         return((int)EP(pp, e_pcred.p_ruid));
  719.     }
  720.     }
  721.     return(-1);
  722. }
  723.