source: trunk/third/top/machine/m_hpux7.c @ 9084

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