home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Utilities / top-0.5-MI / machine / m_386bsd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-13  |  16.5 KB  |  696 lines

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