source: trunk/third/top/machine/m_hpux9.c @ 16185

Revision 16185, 19.4 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16184, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * top - a top users display for Unix
3 *
4 * SYNOPSIS:  any hp9000 running hpux version 9
5 *
6 * DESCRIPTION:
7 * This is the machine-dependent module for HPUX 9.
8 * This makes top work on (at least) the following systems:
9 *      hp9000s800
10 *      hp9000s700
11 * This may make top work on the following, but we aren't sure:
12 *      hp9000s300
13 *
14 * LIBS:
15 *
16 * CFLAGS: -DHAVE_GETOPT
17 *
18 * AUTHOR: Kevin Schmidt <kevin@mcl.ucsb.edu>
19 *         adapted from Christos Zoulas <christos@ee.cornell.edu>
20 */
21
22#include <sys/types.h>
23#include <sys/signal.h>
24#include <sys/param.h>
25
26#include <stdio.h>
27#include <nlist.h>
28#include <math.h>
29#include <sys/dir.h>
30#include <sys/user.h>
31#include <sys/proc.h>
32#include <sys/dk.h>
33#include <sys/vm.h>
34#include <sys/file.h>
35#include <sys/time.h>
36#ifndef hpux
37# define P_RSSIZE(p) (p)->p_rssize
38# define P_TSIZE(p) (p)->p_tsize
39# define P_DSIZE(p) (p)->p_dsize
40# define P_SSIZE(p) (p)->p_ssize
41#else
42# include <sys/pstat.h>
43# define __PST2P(p, field) \
44    ((p)->p_upreg ? ((struct pst_status *) (p)->p_upreg)->field : 0)
45# define P_RSSIZE(p) __PST2P(p, pst_rssize)
46# define P_TSIZE(p) __PST2P(p, pst_tsize)
47# define P_DSIZE(p) __PST2P(p, pst_dsize)
48# define P_SSIZE(p) __PST2P(p, pst_ssize)
49# ifdef __hp9000s700
50#  define p_percentcpu(p) ((p)->p_pctcpu)
51#  define p_time_exact(p) ((p)->p_time)
52# else
53/* The following 4 #defines are per HPUX-9.0's <sys/proc.h> */
54#  define PCT_NORM 9       /* log2(PCT_BASE) */
55#  define PCT_BASE (1<<PCT_NORM)
56#  define p_percentcpu(p) ((p)->p_fractioncpu/(float)(PCT_BASE*HZ))
57#  define p_time_exact(p) (time.tv_sec-((p)->p_swaptime))
58# endif /* __hp9000s700 */
59#endif /* hpux */
60
61#include "top.h"
62#include "machine.h"
63#include "utils.h"
64
65#define VMUNIX  "/hp-ux"
66#define KMEM    "/dev/kmem"
67#define MEM     "/dev/mem"
68#ifdef DOSWAP
69#define SWAP    "/dev/dmem"
70#endif
71
72/* get_process_info passes back a handle.  This is what it looks like: */
73
74struct handle
75{
76    struct proc **next_proc;    /* points to next valid proc pointer */
77    int remaining;              /* number of pointers remaining */
78};
79
80/* declarations for load_avg */
81#include "loadavg.h"
82
83/* define what weighted cpu is.  */
84#define weighted_cpu(pct, pp) ((p_time_exact(pp)) == 0 ? 0.0 : \
85                         ((pct) / (1.0 - exp((p_time_exact(pp)) * logcpu))))
86
87/* what we consider to be process size: */
88#define PROCSIZE(pp) (P_TSIZE(pp) + P_DSIZE(pp) + P_SSIZE(pp))
89
90/* definitions for indices in the nlist array */
91#define X_AVENRUN       0
92#define X_CCPU          1
93#define X_NPROC         2
94#define X_PROC          3
95#define X_TOTAL         4
96#define X_CP_TIME       5
97#define X_MPID          6
98
99/*
100 * Steinar Haug from University of Trondheim, NORWAY pointed out that
101 * the HP 9000 system 800 doesn't have _hz defined in the kernel.  He
102 * provided a patch to work around this.  We've improved on this patch
103 * here and set the constant X_HZ only when _hz is available in the
104 * kernel.  Code in this module that uses X_HZ is surrounded with
105 * appropriate ifdefs.
106 */
107
108#ifndef hp9000s300
109#define X_HZ            7
110#endif
111
112
113static struct nlist nlst[] = {
114    { "_avenrun" },             /* 0 */
115    { "_cexp" },                /* 1 */
116    { "_nproc" },               /* 2 */
117    { "_proc" },                /* 3 */
118    { "_total" },               /* 4 */
119    { "_cp_time" },             /* 5 */
120    { "_mpid" },                /* 6 */
121#ifdef X_HZ
122    { "_hz" },                  /* 7 */
123#endif
124    { 0 }
125};
126
127/*
128 *  These definitions control the format of the per-process area
129 */
130
131static char header[] =
132  "  PID X        PRI NICE  SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
133/* 0123456   -- field to fill in starts at header+6 */
134#define UNAME_START 6
135
136#define Proc_format \
137        "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %s"
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
143char *state_abbrev[] =
144{
145    "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
146};
147
148
149static int kmem;
150
151/* values that we stash away in _init and use in later routines */
152
153static double logcpu;
154
155/* these are retrieved from the kernel in _init */
156
157static unsigned long proc;
158static          int  nproc;
159static          long hz;
160static load_avg  ccpu;
161static          int  ncpu = 0;
162
163/* these are offsets obtained via nlist and used in the get_ functions */
164static unsigned long mpid_offset;
165static unsigned long avenrun_offset;
166static unsigned long total_offset;
167static unsigned long cp_time_offset;
168
169/* these are for calculating cpu state percentages */
170
171static long cp_time[CPUSTATES];
172static long cp_old[CPUSTATES];
173static long cp_diff[CPUSTATES];
174
175/* these are for detailing the process states */
176
177int process_states[7];
178char *procstatenames[] = {
179    "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
180    " zombie, ", " stopped, ",
181    NULL
182};
183
184/* these are for detailing the cpu states */
185
186int cpu_states[9];
187char *cpustatenames[] = {
188    "usr", "nice", "sys", "idle", "", "", "", "intr", "ker",
189    NULL
190};
191
192/* these are for detailing the memory statistics */
193
194int memory_stats[8];
195char *memorynames[] = {
196    "Real: ", "K/", "K act/tot  ", "Virtual: ", "K/",
197    "K act/tot  ", "Free: ", "K", NULL
198};
199
200/* these are for keeping track of the proc array */
201
202static int bytes;
203static int pref_len;
204static struct proc *pbase;
205static struct proc **pref;
206static struct pst_status *pst;
207
208/* these are for getting the memory statistics */
209
210static int pageshift;           /* log base 2 of the pagesize */
211
212/* define pagetok in terms of pageshift */
213
214#define pagetok(size) ((size) << pageshift)
215
216/* useful externals */
217extern int errno;
218extern char *sys_errlist[];
219
220long lseek();
221long time();
222
223machine_init(statics)
224
225struct statics *statics;
226
227{
228    register int i = 0;
229    register int pagesize;
230
231    if ((kmem = open(KMEM, O_RDONLY)) == -1) {
232        perror(KMEM);
233        return(-1);
234    }
235#ifdef hp9000s800
236    /* 800 names don't have leading underscores */
237    for (i = 0; nlst[i].n_name; nlst[i++].n_name++)
238        continue;
239#endif
240
241    /* get the list of symbols we want to access in the kernel */
242    (void) nlist(VMUNIX, nlst);
243    if (nlst[0].n_type == 0)
244    {
245        fprintf(stderr, "top: nlist failed\n");
246        return(-1);
247    }
248
249    /* make sure they were all found */
250    if (check_nlist(nlst) > 0)
251    {
252        return(-1);
253    }
254
255    /* get the symbol values out of kmem */
256    (void) getkval(nlst[X_PROC].n_value,   (int *)(&proc),      sizeof(proc),
257            nlst[X_PROC].n_name);
258    (void) getkval(nlst[X_NPROC].n_value,  &nproc,              sizeof(nproc),
259            nlst[X_NPROC].n_name);
260    (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),      sizeof(ccpu),
261            nlst[X_CCPU].n_name);
262#ifdef X_HZ
263    (void) getkval(nlst[X_HZ].n_value,     (int *)(&hz),        sizeof(hz),
264            nlst[X_HZ].n_name);
265#else
266    hz = HZ;
267#endif
268
269    /* stash away certain offsets for later use */
270    mpid_offset = nlst[X_MPID].n_value;
271    avenrun_offset = nlst[X_AVENRUN].n_value;
272    total_offset = nlst[X_TOTAL].n_value;
273    cp_time_offset = nlst[X_CP_TIME].n_value;
274
275    /* this is used in calculating WCPU -- calculate it ahead of time */
276    logcpu = log(loaddouble(ccpu));
277
278    /* allocate space for proc structure array and array of pointers */
279    bytes = nproc * sizeof(struct proc);
280    pbase = (struct proc *)malloc(bytes);
281    pref  = (struct proc **)malloc(nproc * sizeof(struct proc *));
282    pst   = (struct pst_status *)malloc(nproc * sizeof(struct pst_status));
283
284    /* Just in case ... */
285    if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
286    {
287        fprintf(stderr, "top: can't allocate sufficient memory\n");
288        return(-1);
289    }
290
291    /* get the page size with "getpagesize" and calculate pageshift from it */
292    pagesize = getpagesize();
293    pageshift = 0;
294    while (pagesize > 1)
295    {
296        pageshift++;
297        pagesize >>= 1;
298    }
299
300    /* we only need the amount of log(2)1024 for our conversion */
301    pageshift -= LOG1024;
302
303    /* fill in the statics information */
304    statics->procstate_names = procstatenames;
305    statics->cpustate_names = cpustatenames;
306    statics->memory_names = memorynames;
307
308    /* all done! */
309    return(0);
310}
311
312char *format_header(uname_field)
313
314register char *uname_field;
315
316{
317    register char *ptr;
318
319    ptr = header + UNAME_START;
320    while (*uname_field != '\0')
321    {
322        *ptr++ = *uname_field++;
323    }
324
325    return(header);
326}
327
328get_system_info(si)
329
330struct system_info *si;
331
332{
333    load_avg avenrun[3];
334    long total;
335
336    /* get the cp_time array */
337    (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
338                   "_cp_time");
339
340    /* get load average array */
341    (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
342                   "_avenrun");
343
344    /* get mpid -- process id of last process */
345    (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
346                   "_mpid");
347
348    /* convert load averages to doubles */
349    {
350        register int i;
351        register double *infoloadp;
352        register load_avg *sysloadp;
353
354        infoloadp = si->load_avg;
355        sysloadp = avenrun;
356        for (i = 0; i < 3; i++)
357        {
358            *infoloadp++ = loaddouble(*sysloadp++);
359        }
360    }
361
362    /* convert cp_time counts to percentages */
363    total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
364
365    /* sum memory statistics */
366    {
367        struct vmtotal total;
368
369        /* get total -- systemwide main memory usage structure */
370        (void) getkval(total_offset, (int *)(&total), sizeof(total),
371                       "_total");
372        /* convert memory stats to Kbytes */
373        memory_stats[0] = -1;
374        memory_stats[1] = pagetok(total.t_arm);
375        memory_stats[2] = pagetok(total.t_rm);
376        memory_stats[3] = -1;
377        memory_stats[4] = pagetok(total.t_avm);
378        memory_stats[5] = pagetok(total.t_vm);
379        memory_stats[6] = -1;
380        memory_stats[7] = pagetok(total.t_free);
381    }
382
383    /* set arrays and strings */
384    si->cpustates = cpu_states;
385    si->memory = memory_stats;
386}
387
388static struct handle handle;
389
390caddr_t get_process_info(si, sel, compare)
391
392struct system_info *si;
393struct process_select *sel;
394int (*compare)();
395
396{
397    register int i;
398    register int total_procs;
399    register int active_procs;
400    register struct proc **prefp;
401    register struct proc *pp;
402
403    /* these are copied out of sel for speed */
404    int show_idle;
405    int show_system;
406    int show_uid;
407    int show_command;
408
409    /* read all the proc structures in one fell swoop */
410    (void) getkval(proc, (int *)pbase, bytes, "proc array");
411    for (i = 0; i < nproc; ++i) {
412        if (pstat(PSTAT_PROC, &pst[i], sizeof(pst[i]), 0, pbase[i].p_pid) != 1)
413            pbase[i].p_upreg = (preg_t *) 0;
414        else
415            pbase[i].p_upreg = (preg_t *) &pst[i];
416        pbase[i].p_nice = pst[i].pst_nice;
417        pbase[i].p_cpticks = pst[i].pst_cpticks;
418    }
419
420
421    /* get a pointer to the states summary array */
422    si->procstates = process_states;
423
424    /* set up flags which define what we are going to select */
425    show_idle = sel->idle;
426    show_system = sel->system;
427    show_uid = sel->uid != -1;
428    show_command = sel->command != NULL;
429
430    /* count up process states and get pointers to interesting procs */
431    total_procs = 0;
432    active_procs = 0;
433    memset((char *)process_states, 0, sizeof(process_states));
434    prefp = pref;
435    for (pp = pbase, i = 0; i < nproc; pp++, i++)
436    {
437        /*
438         *  Place pointers to each valid proc structure in pref[].
439         *  Process slots that are actually in use have a non-zero
440         *  status field.  Processes with SSYS set are system
441         *  processes---these get ignored unless show_sysprocs is set.
442         */
443        if (pp->p_stat != 0 &&
444            (show_system || ((pp->p_flag & SSYS) == 0)))
445        {
446            total_procs++;
447            process_states[pp->p_stat]++;
448            /*
449             * idle processes can be selectively ignored:  a process is
450             * considered idle when cpticks is zero AND it is not in the run
451             * state.  Zombies are always ignored.  We also skip over
452             * processes that have been excluded via a uid selection
453             */
454            if ((pp->p_stat != SZOMB) &&
455                (show_idle || (pp->p_cpticks != 0) || (pp->p_stat == SRUN)) &&
456                (!show_uid || pp->p_uid == (uid_t)sel->uid))
457            {
458                *prefp++ = pp;
459                active_procs++;
460            }
461        }
462    }
463
464    /* if requested, sort the "interesting" processes */
465    if (compare != NULL)
466    {
467        qsort((char *)pref, active_procs, sizeof(struct proc *), compare);
468    }
469
470    /* remember active and total counts */
471    si->p_total = total_procs;
472    si->p_active = pref_len = active_procs;
473
474    /* pass back a handle */
475    handle.next_proc = pref;
476    handle.remaining = active_procs;
477    return((caddr_t)&handle);
478}
479
480char fmt[MAX_COLS];             /* static area where result is built */
481
482char *format_next_process(handle, get_userid)
483
484caddr_t handle;
485char *(*get_userid)();
486
487{
488    register struct proc *pp;
489    register long cputime;
490    register double pct;
491    int where;
492    struct user u;
493    struct handle *hp;
494    struct timeval time;
495    struct timezone timezone;
496
497    /* find and remember the next proc structure */
498    hp = (struct handle *)handle;
499    pp = *(hp->next_proc++);
500    hp->remaining--;
501   
502
503    /* get the process's user struct and set cputime */
504    where = getu(pp, &u);
505    if (where == -1)
506    {
507        (void) strcpy(u.u_comm, "<swapped>");
508        cputime = 0;
509    }
510    else
511    {
512
513         
514        /* set u_comm for system processes */
515        if (u.u_comm[0] == '\0')
516        {
517            if (pp->p_pid == 0)
518            {
519                (void) strcpy(u.u_comm, "Swapper");
520            }
521            else if (pp->p_pid == 2)
522            {
523                (void) strcpy(u.u_comm, "Pager");
524            }
525        }
526        if (where == 1) {
527            /*
528             * Print swapped processes as <pname>
529             */
530            char buf[sizeof(u.u_comm)];
531            (void) strncpy(buf, u.u_comm, sizeof(u.u_comm));
532            u.u_comm[0] = '<';
533            (void) strncpy(&u.u_comm[1], buf, sizeof(u.u_comm) - 2);
534            u.u_comm[sizeof(u.u_comm) - 2] = '\0';
535            (void) strncat(u.u_comm, ">", sizeof(u.u_comm) - 1);
536            u.u_comm[sizeof(u.u_comm) - 1] = '\0';
537        }
538
539        cputime = __PST2P(pp, pst_cptickstotal) / hz;
540    }
541
542    /* calculate the base for cpu percentages */
543    pct = pctdouble(p_percentcpu(pp));
544
545    /* get time used for calculation in weighted_cpu */
546    gettimeofday(&time, &timezone);
547
548    /* format this entry */
549    sprintf(fmt,
550            Proc_format,
551            pp->p_pid,
552            (*get_userid)(pp->p_uid),
553            pp->p_pri - PZERO,
554            pp->p_nice - NZERO,
555            format_k(pagetok(PROCSIZE(pp))),
556            format_k(pagetok(P_RSSIZE(pp))),
557            state_abbrev[pp->p_stat],
558            format_time(cputime),
559            100.0 * weighted_cpu(pct, pp),
560            100.0 * pct,
561            printable(u.u_comm));
562
563    /* return the result */
564    return(fmt);
565}
566
567/*
568 *  getu(p, u) - get the user structure for the process whose proc structure
569 *      is pointed to by p.  The user structure is put in the buffer pointed
570 *      to by u.  Return 0 if successful, -1 on failure (such as the process
571 *      being swapped out).
572 */
573
574
575getu(p, u)
576
577register struct proc *p;
578struct user *u;
579
580{
581    struct pst_status *ps;
582    char *s, *c;
583    int i;
584
585    if ((ps = (struct pst_status *) p->p_upreg) == NULL)
586        return -1;
587
588    memset(u, 0, sizeof(struct user));
589    c = ps->pst_cmd;
590    ps->pst_cmd[PST_CLEN - 1] = '\0';        /* paranoia */
591    s = strtok(ps->pst_cmd, "\t \n");
592
593    if (c = strrchr(s, '/'))
594        c++;
595    else
596        c = s;
597    if (*c == '-')
598        c++;
599    i = 0;
600    for (; i < MAXCOMLEN; i++) {
601        if (*c == '\0' || *c == ' ' || *c == '/')
602            break;
603        u->u_comm[i] = *c++;
604    }
605#ifndef DOSWAP
606    return ((p->p_flag & SLOAD) == 0 ? 1 : 0);
607#endif
608    return(0);
609}
610
611/*
612 * check_nlist(nlst) - checks the nlist to see if any symbols were not
613 *              found.  For every symbol that was not found, a one-line
614 *              message is printed to stderr.  The routine returns the
615 *              number of symbols NOT found.
616 */
617
618int check_nlist(nlst)
619
620register struct nlist *nlst;
621
622{
623    register int i;
624
625    /* check to see if we got ALL the symbols we requested */
626    /* this will write one line to stderr for every symbol not found */
627
628    i = 0;
629    while (nlst->n_name != NULL)
630    {
631        if (nlst->n_type == 0)
632        {
633            /* this one wasn't found */
634            fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
635            i = 1;
636        }
637        nlst++;
638    }
639
640    return(i);
641}
642
643
644/*
645 *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
646 *      "offset" is the byte offset into the kernel for the desired value,
647 *      "ptr" points to a buffer into which the value is retrieved,
648 *      "size" is the size of the buffer (and the object to retrieve),
649 *      "refstr" is a reference string used when printing error meessages,
650 *          if "refstr" starts with a '!', then a failure on read will not
651 *          be fatal (this may seem like a silly way to do things, but I
652 *          really didn't want the overhead of another argument).
653 *     
654 */
655
656getkval(offset, ptr, size, refstr)
657
658unsigned long offset;
659int *ptr;
660int size;
661char *refstr;
662
663{
664    if (lseek(kmem, (long)offset, L_SET) == -1) {
665        if (*refstr == '!')
666            refstr++;
667        (void) fprintf(stderr, "%s: lseek to %s: %s\n", KMEM,
668                       refstr, strerror(errno));
669        quit(23);
670    }
671    if (read(kmem, (char *) ptr, size) == -1) {
672        if (*refstr == '!')
673            return(0);
674        else {
675            (void) fprintf(stderr, "%s: reading %s: %s\n", KMEM,
676                           refstr, strerror(errno));
677            quit(23);
678        }
679    }
680    return(1);
681}
682   
683/* comparison routine for qsort */
684
685/*
686 *  proc_compare - comparison function for "qsort"
687 *      Compares the resource consumption of two processes using five
688 *      distinct keys.  The keys (in descending order of importance) are:
689 *      percent cpu, cpu ticks, state, resident set size, total virtual
690 *      memory usage.  The process states are ordered as follows (from least
691 *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
692 *      array declaration below maps a process state index into a number
693 *      that reflects this ordering.
694 */
695
696static unsigned char sorted_state[] =
697{
698    0,  /* not used             */
699    3,  /* sleep                */
700    1,  /* ABANDONED (WAIT)     */
701    6,  /* run                  */
702    5,  /* start                */
703    2,  /* zombie               */
704    4   /* stop                 */
705};
706 
707proc_compare(pp1, pp2)
708
709struct proc **pp1;
710struct proc **pp2;
711
712{
713    register struct proc *p1;
714    register struct proc *p2;
715    register int result;
716    register pctcpu lresult;
717
718    /* remove one level of indirection */
719    p1 = *pp1;
720    p2 = *pp2;
721
722    /* compare percent cpu (pctcpu) */
723    if ((lresult = p_percentcpu(p2) - p_percentcpu(p1)) == 0)
724    {
725        /* use cpticks to break the tie */
726        if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
727        {
728            /* use process state to break the tie */
729            if ((result = sorted_state[p2->p_stat] -
730                          sorted_state[p1->p_stat])  == 0)
731            {
732                /* use priority to break the tie */
733                if ((result = p2->p_pri - p1->p_pri) == 0)
734                {
735                    /* use resident set size (rssize) to break the tie */
736                    if ((result = P_RSSIZE(p2) - P_RSSIZE(p1)) == 0)
737                    {
738                        /* use total memory to break the tie */
739                        result = PROCSIZE(p2) - PROCSIZE(p1);
740                    }
741                }
742            }
743        }
744    }
745    else
746    {
747        result = lresult < 0 ? -1 : 1;
748    }
749
750    return(result);
751}
752
753
754void (*signal(sig, func))()
755    int sig;
756    void (*func)();
757{
758    struct sigvec osv, sv;
759
760    /*
761     * XXX: we should block the signal we are playing with,
762     *      in case we get interrupted in here.
763     */
764    if (sigvector(sig, NULL, &osv) == -1)
765        return BADSIG;
766    sv = osv;
767    sv.sv_handler = func;
768#ifdef SV_BSDSIG
769    sv.sv_flags |= SV_BSDSIG;
770#endif
771    if (sigvector(sig, &sv, NULL) == -1)
772        return BADSIG;
773    return osv.sv_handler;
774}
775
776int getpagesize() { return 1 << PGSHIFT; }
777
778int setpriority(a, b, c) { errno = ENOSYS; return -1; }
779
780/*
781 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
782 *              the process does not exist.
783 *              It is EXTREMLY IMPORTANT that this function work correctly.
784 *              If top runs setuid root (as in SVR4), then this function
785 *              is the only thing that stands in the way of a serious
786 *              security problem.  It validates requests for the "kill"
787 *              and "renice" commands.
788 */
789
790int proc_owner(pid)
791
792int pid;
793
794{
795    register int cnt;
796    register struct proc **prefp;
797    register struct proc *pp;
798
799    prefp = pref;
800    cnt = pref_len;
801    while (--cnt >= 0)
802    {
803        if ((pp = *prefp++)->p_pid == (pid_t)pid)
804        {
805            return((int)pp->p_uid);
806        }
807    }
808    return(-1);
809}
Note: See TracBrowser for help on using the repository browser.