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

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