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

  1. /*
  2.  * top - a top users display for Unix
  3.  *
  4.  * SYNOPSIS:  any Sequent Running Dynix 3.0.x
  5.  *
  6.  * DESCRIPTION:
  7.  * This is the machine-dependent module for Sequent Dynix 3
  8.  * This makes top work on the following systems:
  9.  *    Sequent Semmetry, Dynix 3.0.12
  10.  *    Sequent Balance,  Dynix 3.0.4
  11.  *
  12.  * AUTHOR:  Daniel Trinkle <trinkle@cs.purdue.edu>
  13.  */
  14.  
  15. #include <sys/types.h>
  16. #include <sys/signal.h>
  17. #include <sys/param.h>
  18.  
  19. #include <stdio.h>
  20. #include <nlist.h>
  21. #include <math.h>
  22. #include <sys/dir.h>
  23. #include <sys/user.h>
  24. #include <sys/proc.h>
  25. #include <sys/dk.h>
  26. #include <sys/vm.h>
  27. #include <machine/pte.h>
  28. #include <machine/plocal.h>
  29. #include <machine/engine.h>
  30. #include <sys/file.h>
  31.  
  32. #include "top.h"
  33. #include "machine.h"
  34. #include "utils.h"
  35.  
  36. #ifndef uid_t
  37. /* some early versions of DYNIX don't have uid_t */
  38. #define uid_t int
  39. #endif
  40.  
  41. struct engine *engine;
  42. struct engine *pengine;
  43. struct plocal **pplocal;
  44. int Nengine;
  45.  
  46. /* get_process_info passes back a handle.  This is what it looks like: */
  47.  
  48. struct handle
  49. {
  50.     struct proc **next_proc;    /* points to next valid proc pointer */
  51.     int remaining;        /* number of pointers remaining */
  52. };
  53.  
  54. /* declarations for load_avg */
  55. typedef long load_avg;
  56. typedef long pctcpu;
  57. #define loaddouble(la) ((double)(la) / FSCALE)
  58. #define intload(i) ((int)((i) * FSCALE))
  59. #define pctdouble(p) ((double)(p) / FSCALE)
  60.  
  61. /* define what weighted cpu is.  */
  62. #define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
  63.              ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
  64.  
  65. /* what we consider to be process size: */
  66. #define PROCSIZE(pp) ((pp)->p_dsize + (pp)->p_ssize)
  67.  
  68. /* definitions for indices in the nlist array */
  69. #define X_AVENRUN    0
  70. #define X_CCPU        1
  71. #define X_MPID        2
  72. #define X_NPROC        3
  73. #define X_PROC        4
  74. #define X_TOTAL        5
  75. #define X_ENGINE    6
  76. #define X_NENGINE    7
  77.  
  78. static struct nlist nlst[] = {
  79.     { "_avenrun" },        /* 0 */
  80.     { "_ccpu" },        /* 1 */
  81.     { "_mpid" },        /* 2 */
  82.     { "_nproc" },        /* 3 */
  83.     { "_proc" },        /* 4 */
  84.     { "_total" },        /* 5 */
  85.     { "_engine" },        /* 6 */
  86.     { "_Nengine" },        /* 7 */
  87.     { 0 }
  88. };
  89.  
  90. /*
  91.  *  These definitions control the format of the per-process area
  92.  */
  93.  
  94. static char header[] =
  95.   "  PID X        PRI NICE  SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
  96. /* 0123456   -- field to fill in starts at header+6 */
  97. #define UNAME_START 6
  98.  
  99. #define Proc_format \
  100.     "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %.16s"
  101.  
  102.  
  103. /* process state names for the "STATE" column of the display */
  104. /* the extra nulls in the string "run" are for adding a slash and
  105.    the processor number when needed */
  106.  
  107. char *state_abbrev[] =
  108. {
  109.     "", "sleep", "WAIT", "run", "start", "zomb", "stop", "RUN"
  110. };
  111.  
  112. /* values that we stash away in _init and use in later routines */
  113.  
  114. static double logcpu;
  115.  
  116. #define VMUNIX "/dynix"
  117. #define KMEM "/dev/kmem"
  118. #define MEM "/dev/mem"
  119.  
  120. static int kmem = -1;
  121. static int mem = -1;
  122.  
  123. struct vmtotal total;
  124.  
  125. /* these are retrieved from the kernel in _init */
  126.  
  127. static unsigned long proc;
  128. static          int  nproc;
  129. static load_avg  ccpu;
  130.  
  131. /* these are offsets obtained via nlist and used in the get_ functions */
  132.  
  133. static unsigned long mpid_offset;
  134. static unsigned long avenrun_offset;
  135. static unsigned long total_offset;
  136.  
  137. /* these are for calculating cpu state percentages */
  138.  
  139. static long cp_time[CPUSTATES];
  140. static long cp_old[CPUSTATES];
  141. static long cp_diff[CPUSTATES];
  142.  
  143. /* these are for detailing the process states */
  144.  
  145. int process_states[8];
  146. char *procstatenames[] = {
  147.     "", " sleeping, ", " ABANDONED, ", " runable, ", " starting, ",
  148.     " zombie, ", " stopped, ", " running, ",
  149.     NULL
  150. };
  151.  
  152. /* these are for detailing the cpu states */
  153.  
  154. int cpu_states[CPUSTATES];
  155. char *cpustatenames[] = {
  156.     "user", "nice", "system", "idle",
  157.     NULL
  158. };
  159.  
  160. /* these are for detailing the memory statistics */
  161.  
  162. int memory_stats[5];
  163. char *memorynames[] = {
  164.     "K (", "K) real, ", "K (", "K) virtual, ", "K free", NULL
  165. };
  166.  
  167. /* these are for keeping track of the proc array */
  168.  
  169. static int bytes;
  170. static int pref_len;
  171. static struct proc *pbase;
  172. static struct proc **pref;
  173.  
  174. #define pagetok(size)    ((size) << (PGSHIFT - LOG1024))
  175.  
  176. /* useful externals */
  177. extern int errno;
  178. extern char *sys_errlist[];
  179.  
  180. long lseek();
  181.  
  182. machine_init(statics)
  183.  
  184. struct statics *statics;
  185.  
  186. {
  187.     register int i;
  188.  
  189.     /* open kernel memory */
  190.     if ((kmem = open(KMEM, 0)) < 0)
  191.     {
  192.     perror(KMEM);
  193.     exit(20);
  194.     }
  195.     if ((mem = open(MEM, 0)) < 0)
  196.     {
  197.     perror(MEM);
  198.     exit(21);
  199.     }
  200.  
  201.     /* get the list of symbols we want to access in the kernel */
  202.     if ((i = nlist(VMUNIX, nlst)) < 0)
  203.     {
  204.     fprintf(stderr, "top: nlist failed\n");
  205.     return(-1);
  206.     }
  207.  
  208.     /* make sure they were all found */
  209.     if (i > 0 && check_nlist(nlst) > 0)
  210.     {
  211.     return(-1);
  212.     }
  213.  
  214.     /* get the symbol values out of kmem */
  215.     (void) getkval(nlst[X_PROC].n_value,   (int *)(&proc),    sizeof(proc),
  216.         nlst[X_PROC].n_name);
  217.     (void) getkval(nlst[X_NPROC].n_value,  &nproc,        sizeof(nproc),
  218.         nlst[X_NPROC].n_name);
  219.     (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),    sizeof(ccpu),
  220.         nlst[X_CCPU].n_name);
  221.     (void) getkval(nlst[X_NENGINE].n_value,  &Nengine,  sizeof(int),
  222.         nlst[X_NENGINE].n_name);
  223.     (void) getkval(nlst[X_ENGINE].n_value,  &pengine,  sizeof(struct engine *),
  224.         nlst[X_ENGINE].n_name);
  225.  
  226.     engine = (struct engine *)calloc(Nengine, sizeof(struct engine));
  227.     if (engine == NULL)
  228.     {
  229.     fprintf(stderr, "Cannot allocate memory for engine structure\n");
  230.     exit(2);
  231.     }
  232.     (void) getkval(pengine,  &engine[0],  Nengine * sizeof(struct engine),
  233.         "engine array");
  234.     pplocal = (struct plocal **)calloc(Nengine, sizeof(struct plocal *));
  235.     if (pplocal == NULL)
  236.     {
  237.     fprintf(stderr, "Cannot allocate memory for plocal structures\n");
  238.     exit(2);
  239.     }
  240.     for (i = 0; i < Nengine; i++) {
  241.     pplocal[i] = (struct plocal *)&engine[i].e_local->pp_local[0][0];
  242.     }
  243.  
  244.     /* stash away certain offsets for later use */
  245.     mpid_offset = nlst[X_MPID].n_value;
  246.     avenrun_offset = nlst[X_AVENRUN].n_value;
  247.     total_offset = nlst[X_TOTAL].n_value;
  248.  
  249.     /* this is used in calculating WCPU -- calculate it ahead of time */
  250.     logcpu = log(loaddouble(ccpu));
  251.  
  252.     /* allocate space for proc structure array and array of pointers */
  253.     bytes = nproc * sizeof(struct proc);
  254.     pbase = (struct proc *)malloc(bytes);
  255.     pref  = (struct proc **)malloc(nproc * sizeof(struct proc *));
  256.  
  257.     /* Just in case ... */
  258.     if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
  259.     {
  260.     fprintf(stderr, "top: can't allocate sufficient memory\n");
  261.     return(-1);
  262.     }
  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.     load_avg avenrun[3];
  295.     struct plocal plocal;
  296.     register int i, j;
  297.  
  298.     /* get the cp_time array */
  299.     for (j = 0; j < CPUSTATES; j++)
  300.     cp_time[j] = 0L;
  301.     for (i = 0; i < Nengine; i++) {
  302.     (void) getkval(pplocal[i], &plocal, sizeof(struct plocal), "plocal array");
  303.     for (j = 0; j < CPUSTATES; j++)
  304.         cp_time[j] += (long)plocal.cnt.v_time[j];
  305.     }
  306.  
  307.     /* get load average array */
  308.     (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
  309.            "_avenrun");
  310.  
  311.     /* get mpid -- process id of last process */
  312.     (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
  313.            "_mpid");
  314.  
  315.     /* convert load averages to doubles */
  316.     {
  317.     register int i;
  318.     register double *infoloadp;
  319.     register load_avg *sysloadp;
  320.  
  321.     infoloadp = si->load_avg;
  322.     sysloadp = avenrun;
  323.     for (i = 0; i < 3; i++)
  324.     {
  325.         *infoloadp++ = loaddouble(*sysloadp++);
  326.     }
  327.     }
  328.  
  329.     /* convert cp_time counts to percentages */
  330.     (void) percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
  331.  
  332.     /* get total -- systemwide main memory usage structure */
  333.     (void) getkval(total_offset, (int *)(&total), sizeof(total),
  334.            "_total");
  335.     /* convert memory stats to Kbytes */
  336.     memory_stats[0] = pagetok(total.t_rm);
  337.     memory_stats[1] = pagetok(total.t_arm);
  338.     memory_stats[2] = pagetok(total.t_vm);
  339.     memory_stats[3] = pagetok(total.t_avm);
  340.     memory_stats[4] = pagetok(total.t_free);
  341.  
  342.     /* set arrays and strings */
  343.     si->cpustates = cpu_states;
  344.     si->memory = memory_stats;
  345. }
  346.  
  347. static struct handle handle;
  348.  
  349. caddr_t get_process_info(si, sel, compare)
  350.  
  351. struct system_info *si;
  352. struct process_select *sel;
  353. int (*compare)();
  354.  
  355. {
  356.     register int i;
  357.     register int total_procs;
  358.     register int active_procs;
  359.     register struct proc **prefp;
  360.     register struct proc *pp;
  361.  
  362.     /* these are copied out of sel for speed */
  363.     int show_idle;
  364.     int show_system;
  365.     int show_uid;
  366.  
  367.     /* read all the proc structures in one fell swoop */
  368.     (void) getkval(proc, (int *)pbase, bytes, "proc array");
  369.  
  370.     /* get a pointer to the states summary array */
  371.     si->procstates = process_states;
  372.  
  373.     /* set up flags which define what we are going to select */
  374.     show_idle = sel->idle;
  375.     show_system = sel->system;
  376.     show_uid = sel->uid != -1;
  377.  
  378.     /* count up process states and get pointers to interesting procs */
  379.     total_procs = 0;
  380.     active_procs = 0;
  381.     bzero((char *)process_states, sizeof(process_states));
  382.     prefp = pref;
  383.     for (pp = pbase, i = 0; i < nproc; pp++, i++)
  384.     {
  385.     /*
  386.      *  Place pointers to each valid proc structure in pref[].
  387.      *  Process slots that are actually in use have a non-zero
  388.      *  status field.  Processes with SSYS set are system
  389.      *  processes---these get ignored unless show_sysprocs is set.
  390.      */
  391.     if (pp->p_stat != 0 &&
  392.         (show_system || ((pp->p_flag & SSYS) == 0)))
  393.     {
  394.         total_procs++;
  395.         process_states[pp->p_stat]++;
  396.         if ((pp->p_stat != SZOMB) &&
  397.         (show_idle || (pp->p_pctcpu != 0) || (pp->p_stat == SRUN)) &&
  398.         (!show_uid || pp->p_uid == (uid_t)sel->uid))
  399.         {
  400.         *prefp++ = pp;
  401.         active_procs++;
  402.         }
  403.     }
  404.     }
  405.  
  406.     /* if requested, sort the "interesting" processes */
  407.     if (compare != NULL)
  408.     {
  409.     qsort((char *)pref, active_procs, sizeof(struct proc *), compare);
  410.     }
  411.  
  412.     /* remember active and total counts */
  413.     si->p_total = total_procs;
  414.     si->p_active = pref_len = active_procs;
  415.  
  416.     /* pass back a handle */
  417.     handle.next_proc = pref;
  418.     handle.remaining = active_procs;
  419.     return((caddr_t)&handle);
  420. }
  421.  
  422. char fmt[MAX_COLS];        /* static area where result is built */
  423.  
  424. char *format_next_process(handle, get_userid)
  425.  
  426. caddr_t handle;
  427. char *(*get_userid)();
  428.  
  429. {
  430.     register struct proc *pp;
  431.     register long cputime;
  432.     register double pct;
  433.     struct user u;
  434.     struct handle *hp;
  435.  
  436.     /* find and remember the next proc structure */
  437.     hp = (struct handle *)handle;
  438.     pp = *(hp->next_proc++);
  439.     hp->remaining--;
  440.     
  441.  
  442.     /* get the process's user struct and set cputime */
  443.     if (getu(pp, &u) == -1)
  444.     {
  445.     (void) strcpy(u.u_comm, "<swapped>");
  446.     cputime = 0;
  447.     }
  448.     else
  449.     {
  450.     /* set u_comm for system processes */
  451.     if (u.u_comm[0] == '\0')
  452.     {
  453.         if (pp->p_pid == 0)
  454.         {
  455.         (void) strcpy(u.u_comm, "Swapper");
  456.         }
  457.         else if (pp->p_pid == 2)
  458.         {
  459.         (void) strcpy(u.u_comm, "Pager");
  460.         }
  461.     }
  462.  
  463.     cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
  464.     }
  465.  
  466.     /* calculate the base for cpu percentages */
  467.     pct = pctdouble(pp->p_pctcpu);
  468.  
  469.     /* format this entry */
  470.     sprintf(fmt,
  471.         Proc_format,
  472.         pp->p_pid,
  473.         (*get_userid)(pp->p_uid),
  474.         pp->p_pri - PZERO,
  475.         pp->p_nice - NZERO,
  476.         format_k(pagetok(PROCSIZE(pp))),
  477.         format_k(pagetok(pp->p_rssize)),
  478.         state_abbrev[pp->p_stat],
  479.         format_time(cputime),
  480.         100.0 * weighted_cpu(pct, pp),
  481.         100.0 * pct,
  482.         printable(u.u_comm));
  483.  
  484.     /* return the result */
  485.     return(fmt);
  486. }
  487.  
  488. /*
  489.  *  getu(p, u) - get the user structure for the process whose proc structure
  490.  *    is pointed to by p.  The user structure is put in the buffer pointed
  491.  *    to by u.  Return 0 if successful, -1 on failure (such as the process
  492.  *    being swapped out).
  493.  */
  494.  
  495. getu(p, u)
  496.  
  497. register struct proc *p;
  498. struct user *u;
  499.  
  500. {
  501.     struct pte uptes[UPAGES];
  502.     register caddr_t upage;
  503.     register struct pte *pte;
  504.     register nbytes, n;
  505.  
  506.     /*
  507.      *  Check if the process is currently loaded or swapped out.  The way we
  508.      *  get the u area is totally different for the two cases.  For this
  509.      *  application, we just don't bother if the process is swapped out.
  510.      */
  511.     if ((p->p_flag & SLOAD) == 0)
  512.     {
  513.     return(-1);
  514.     }
  515.  
  516.     /*
  517.      *  Process is currently in memory, we hope!
  518.      */
  519. #ifdef ns32000
  520.     if (!getkval(p->p_upte, uptes, sizeof(uptes), "!p->p_upte"))
  521. #else
  522.     if (!getkval(p->p_pttop, uptes, sizeof(uptes), "!p->p_upte"))
  523. #endif
  524.     {
  525.     /* we can't seem to get to it, so pretend it's swapped out */
  526.     return(-1);
  527.     } 
  528.     upage = (caddr_t)u;
  529.     pte = uptes;
  530.     for (nbytes = sizeof(struct user); nbytes > 0; nbytes -= NBPG)
  531.     {
  532.         (void) lseek(mem, (long)(pte++->pg_pfnum * NBPG), 0);
  533.     n = MIN(nbytes, NBPG);
  534.     if (read(mem, upage, n) != n)
  535.     {
  536.         /* we can't seem to get to it, so pretend it's swapped out */
  537.         return(-1);
  538.     }
  539.     upage += n;
  540.     }
  541.     return(0);
  542. }
  543.  
  544. /*
  545.  * check_nlist(nlst) - checks the nlist to see if any symbols were not
  546.  *        found.  For every symbol that was not found, a one-line
  547.  *        message is printed to stderr.  The routine returns the
  548.  *        number of symbols NOT found.
  549.  */
  550.  
  551. int check_nlist(nlst)
  552.  
  553. register struct nlist *nlst;
  554.  
  555. {
  556.     register int i;
  557.  
  558.     /* check to see if we got ALL the symbols we requested */
  559.     /* this will write one line to stderr for every symbol not found */
  560.  
  561.     i = 0;
  562.     while (nlst->n_name != NULL)
  563.     {
  564.     if (nlst->n_type == 0)
  565.     {
  566.         /* this one wasn't found */
  567.         fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
  568.         i = 1;
  569.     }
  570.     nlst++;
  571.     }
  572.  
  573.     return(i);
  574. }
  575.  
  576.  
  577. /*
  578.  *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
  579.  *    "offset" is the byte offset into the kernel for the desired value,
  580.  *      "ptr" points to a buffer into which the value is retrieved,
  581.  *      "size" is the size of the buffer (and the object to retrieve),
  582.  *      "refstr" is a reference string used when printing error meessages,
  583.  *        if "refstr" starts with a '!', then a failure on read will not
  584.  *          be fatal (this may seem like a silly way to do things, but I
  585.  *          really didn't want the overhead of another argument).
  586.  *      
  587.  */
  588.  
  589. getkval(offset, ptr, size, refstr)
  590.  
  591. unsigned long offset;
  592. int *ptr;
  593. int size;
  594. char *refstr;
  595.  
  596. {
  597.     if (lseek(kmem, (long)offset, 0) == -1)
  598.     {
  599.     if (*refstr == '!')
  600.     {
  601.         refstr++;
  602.     }
  603.     fprintf(stderr, "%s: lseek to %s: %s\n",
  604.         KMEM, refstr, sys_errlist[errno]);
  605.     quit(22);
  606.     }
  607.     if (read(kmem, (char *)ptr, size) == -1)
  608.     {
  609.     if (*refstr == '!')
  610.     {
  611.         /* we lost the race with the kernel, process isn't in memory */
  612.         return(0);
  613.     } 
  614.     else 
  615.     {
  616.         fprintf(stderr, "%s: reading %s: %s\n",
  617.         KMEM, refstr, sys_errlist[errno]);
  618.         quit(23);
  619.     }
  620.     }
  621.     return(1);
  622. }
  623.     
  624. /* comparison routine for qsort */
  625.  
  626. /*
  627.  *  proc_compare - comparison function for "qsort"
  628.  *    Compares the resource consumption of two processes using five
  629.  *      distinct keys.  The keys (in descending order of importance) are:
  630.  *      percent cpu, cpu ticks, state, resident set size, total virtual
  631.  *      memory usage.  The process states are ordered as follows (from least
  632.  *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
  633.  *      array declaration below maps a process state index into a number
  634.  *      that reflects this ordering.
  635.  */
  636.  
  637. static unsigned char sorted_state[] =
  638. {
  639.     0,    /* not used        */
  640.     3,    /* sleep        */
  641.     1,    /* ABANDONED (WAIT)    */
  642.     6,    /* run            */
  643.     5,    /* start        */
  644.     2,    /* zombie        */
  645.     4,    /* stop            */
  646.     7    /* RUN            */
  647. };
  648.  
  649. proc_compare(pp1, pp2)
  650.  
  651. struct proc **pp1;
  652. struct proc **pp2;
  653.  
  654. {
  655.     register struct proc *p1;
  656.     register struct proc *p2;
  657.     register int result;
  658.     register pctcpu lresult;
  659.  
  660.     /* remove one level of indirection */
  661.     p1 = *pp1;
  662.     p2 = *pp2;
  663.  
  664.     /* compare percent cpu (pctcpu) */
  665.     if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0)
  666.     {
  667.     /* use cpticks to break the tie */
  668.     if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
  669.     {
  670.         /* use process state to break the tie */
  671.         if ((result = sorted_state[p2->p_stat] -
  672.               sorted_state[p1->p_stat])  == 0)
  673.         {
  674.         /* use priority to break the tie */
  675.         if ((result = p2->p_pri - p1->p_pri) == 0)
  676.         {
  677.             /* use resident set size (rssize) to break the tie */
  678.             if ((result = p2->p_rssize - p1->p_rssize) == 0)
  679.             {
  680.             /* use total memory to break the tie */
  681.             result = PROCSIZE(p2) - PROCSIZE(p1);
  682.             }
  683.         }
  684.         }
  685.     }
  686.     }
  687.     else
  688.     {
  689.     result = lresult < 0 ? -1 : 1;
  690.     }
  691.  
  692.     return(result);
  693. }
  694.  
  695.  
  696. /*
  697.  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
  698.  *        the process does not exist.
  699.  *        It is EXTREMLY IMPORTANT that this function work correctly.
  700.  *        If top runs setuid root (as in SVR4), then this function
  701.  *        is the only thing that stands in the way of a serious
  702.  *        security problem.  It validates requests for the "kill"
  703.  *        and "renice" commands.
  704.  */
  705.  
  706. int proc_owner(pid)
  707.  
  708. int pid;
  709.  
  710. {
  711.     register int cnt;
  712.     register struct proc **prefp;
  713.     register struct proc *pp;
  714.  
  715.     prefp = pref;
  716.     cnt = pref_len;
  717.     while (--cnt >= 0)
  718.     {
  719.     if ((pp = *prefp++)->p_pid == (pid_t)pid)
  720.     {
  721.         return((int)pp->p_uid);
  722.     }
  723.     }
  724.     return(-1);
  725. }
  726.