1/*
2 * Copyright (c) 1984 through 2008, William LeFebvre
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 *     * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 *
16 *     * Neither the name of William LeFebvre nor the names of other
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * top - a top users display for Unix
35 *
36 * SYNOPSIS:  any hp9000 running hpux version 8 (may work with 9)
37 *
38 * DESCRIPTION:
39 * This is the machine-dependent module for HPUX 8 and is rumored to work
40 * for version 9 as well.  This makes top work on (at least) the
41 * following systems:
42 *	hp9000s300
43 *	hp9000s700
44 *	hp9000s800
45 *
46 * LIBS:
47 *
48 * AUTHOR:  Christos Zoulas <christos@ee.cornell.edu>
49 */
50
51#include "config.h"
52#include <sys/types.h>
53#include <sys/signal.h>
54#include <sys/param.h>
55
56#include <stdio.h>
57#include <nlist.h>
58#include <math.h>
59#include <sys/dir.h>
60#include <sys/user.h>
61#include <sys/proc.h>
62#include <sys/dk.h>
63#include <sys/vm.h>
64#include <sys/file.h>
65#include <sys/time.h>
66#ifndef hpux
67# define P_RSSIZE(p) (p)->p_rssize
68# define P_TSIZE(p) (p)->p_tsize
69# define P_DSIZE(p) (p)->p_dsize
70# define P_SSIZE(p) (p)->p_ssize
71#else
72# include <sys/pstat.h>
73# define __PST2P(p, field) \
74    ((p)->p_upreg ? ((struct pst_status *) (p)->p_upreg)->field : 0)
75# define P_RSSIZE(p) __PST2P(p, pst_rssize)
76# define P_TSIZE(p) __PST2P(p, pst_tsize)
77# define P_DSIZE(p) __PST2P(p, pst_dsize)
78# define P_SSIZE(p) __PST2P(p, pst_ssize)
79#endif
80
81#include "top.h"
82#include "machine.h"
83#include "utils.h"
84
85#define VMUNIX	"/hp-ux"
86#define KMEM	"/dev/kmem"
87#define MEM	"/dev/mem"
88#ifdef DOSWAP
89#define SWAP	"/dev/dmem"
90#endif
91
92/* get_process_info passes back a handle.  This is what it looks like: */
93
94struct handle
95{
96    struct proc **next_proc;	/* points to next valid proc pointer */
97    int remaining;		/* number of pointers remaining */
98};
99
100/* declarations for load_avg */
101#include "loadavg.h"
102
103/* define what weighted cpu is.  */
104#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
105			 ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
106
107/* what we consider to be process size: */
108#define PROCSIZE(pp) (P_TSIZE(pp) + P_DSIZE(pp) + P_SSIZE(pp))
109
110/* definitions for indices in the nlist array */
111#define X_AVENRUN	0
112#define X_CCPU		1
113#define X_NPROC		2
114#define X_PROC		3
115#define X_TOTAL		4
116#define X_CP_TIME	5
117#define X_MPID		6
118
119/*
120 * Steinar Haug from University of Trondheim, NORWAY pointed out that
121 * the HP 9000 system 800 doesn't have _hz defined in the kernel.  He
122 * provided a patch to work around this.  We've improved on this patch
123 * here and set the constant X_HZ only when _hz is available in the
124 * kernel.  Code in this module that uses X_HZ is surrounded with
125 * appropriate ifdefs.
126 */
127
128#ifndef hp9000s300
129#define X_HZ		7
130#endif
131
132
133static struct nlist nlst[] = {
134    { "_avenrun" },		/* 0 */
135    { "_ccpu" },		/* 1 */
136    { "_nproc" },		/* 2 */
137    { "_proc" },		/* 3 */
138    { "_total" },		/* 4 */
139    { "_cp_time" },		/* 5 */
140    { "_mpid" },		/* 6 */
141#ifdef X_HZ
142    { "_hz" },			/* 7 */
143#endif
144    { 0 }
145};
146
147/*
148 *  These definitions control the format of the per-process area
149 */
150
151static char header[] =
152  "  PID X        PRI NICE  SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
153/* 0123456   -- field to fill in starts at header+6 */
154#define UNAME_START 6
155
156#define Proc_format \
157	"%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %s"
158
159
160/* process state names for the "STATE" column of the display */
161/* the extra nulls in the string "run" are for adding a slash and
162   the processor number when needed */
163
164char *state_abbrev[] =
165{
166    "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
167};
168
169
170static int kmem;
171
172/* values that we stash away in _init and use in later routines */
173
174static double logcpu;
175
176/* these are retrieved from the kernel in _init */
177
178static unsigned long proc;
179static          int  nproc;
180static          long hz;
181static load_avg  ccpu;
182static          int  ncpu = 0;
183
184/* these are offsets obtained via nlist and used in the get_ functions */
185static unsigned long mpid_offset;
186static unsigned long avenrun_offset;
187static unsigned long total_offset;
188static unsigned long cp_time_offset;
189
190/* these are for calculating cpu state percentages */
191
192static long cp_time[CPUSTATES];
193static long cp_old[CPUSTATES];
194static long cp_diff[CPUSTATES];
195
196/* these are for detailing the process states */
197
198int process_states[7];
199char *procstatenames[] = {
200    "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
201    " zombie, ", " stopped, ",
202    NULL
203};
204
205/* these are for detailing the cpu states */
206
207int cpu_states[9];
208char *cpustatenames[] = {
209    "usr", "nice", "sys", "idle", "", "", "", "intr", "ker",
210    NULL
211};
212
213/* these are for detailing the memory statistics */
214
215long memory_stats[8];
216char *memorynames[] = {
217    "Real: ", "K act, ", "K tot  ", "Virtual: ", "K act, ",
218    "K tot, ", "K free", NULL
219};
220
221/* these are for keeping track of the proc array */
222
223static int bytes;
224static int pref_len;
225static struct proc *pbase;
226static struct proc **pref;
227static struct pst_status *pst;
228
229/* these are for getting the memory statistics */
230
231static int pageshift;		/* log base 2 of the pagesize */
232
233/* define pagetok in terms of pageshift */
234
235#define pagetok(size) ((size) << pageshift)
236
237/* useful externals */
238extern int errno;
239extern char *sys_errlist[];
240
241long lseek();
242long time();
243
244machine_init(statics)
245
246struct statics *statics;
247
248{
249    register int i = 0;
250    register int pagesize;
251
252    if ((kmem = open(KMEM, O_RDONLY)) == -1) {
253	perror(KMEM);
254	return(-1);
255    }
256#ifdef hp9000s800
257    /* 800 names don't have leading underscores */
258    for (i = 0; nlst[i].n_name; nlst[i++].n_name++)
259	continue;
260#endif
261
262    /* get the list of symbols we want to access in the kernel */
263    (void) nlist(VMUNIX, nlst);
264    if (nlst[0].n_type == 0)
265    {
266	fprintf(stderr, "top: nlist failed\n");
267	return(-1);
268    }
269
270    /* make sure they were all found */
271    if (check_nlist(nlst) > 0)
272    {
273	return(-1);
274    }
275
276    /* get the symbol values out of kmem */
277    (void) getkval(nlst[X_PROC].n_value,   (int *)(&proc),	sizeof(proc),
278	    nlst[X_PROC].n_name);
279    (void) getkval(nlst[X_NPROC].n_value,  &nproc,		sizeof(nproc),
280	    nlst[X_NPROC].n_name);
281    (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),	sizeof(ccpu),
282	    nlst[X_CCPU].n_name);
283#ifdef X_HZ
284    (void) getkval(nlst[X_HZ].n_value,     (int *)(&hz),	sizeof(hz),
285	    nlst[X_HZ].n_name);
286#else
287    hz = HZ;
288#endif
289
290    /* stash away certain offsets for later use */
291    mpid_offset = nlst[X_MPID].n_value;
292    avenrun_offset = nlst[X_AVENRUN].n_value;
293    total_offset = nlst[X_TOTAL].n_value;
294    cp_time_offset = nlst[X_CP_TIME].n_value;
295
296    /* this is used in calculating WCPU -- calculate it ahead of time */
297    logcpu = log(loaddouble(ccpu));
298
299    /* allocate space for proc structure array and array of pointers */
300    bytes = nproc * sizeof(struct proc);
301    pbase = (struct proc *)malloc(bytes);
302    pref  = (struct proc **)malloc(nproc * sizeof(struct proc *));
303    pst   = (struct pst_status *)malloc(nproc * sizeof(struct pst_status));
304
305    /* Just in case ... */
306    if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
307    {
308	fprintf(stderr, "top: can't allocate sufficient memory\n");
309	return(-1);
310    }
311
312    /* get the page size with "getpagesize" and calculate pageshift from it */
313    pagesize = getpagesize();
314    pageshift = 0;
315    while (pagesize > 1)
316    {
317	pageshift++;
318	pagesize >>= 1;
319    }
320
321    /* we only need the amount of log(2)1024 for our conversion */
322    pageshift -= LOG1024;
323
324    /* fill in the statics information */
325    statics->procstate_names = procstatenames;
326    statics->cpustate_names = cpustatenames;
327    statics->memory_names = memorynames;
328
329    /* all done! */
330    return(0);
331}
332
333char *format_header(uname_field)
334
335register char *uname_field;
336
337{
338    register char *ptr;
339
340    ptr = header + UNAME_START;
341    while (*uname_field != '\0')
342    {
343	*ptr++ = *uname_field++;
344    }
345
346    return(header);
347}
348
349void
350get_system_info(si)
351
352struct system_info *si;
353
354{
355    load_avg avenrun[3];
356    long total;
357
358    /* get the cp_time array */
359    (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
360		   "_cp_time");
361
362    /* get load average array */
363    (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
364		   "_avenrun");
365
366    /* get mpid -- process id of last process */
367    (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
368		   "_mpid");
369
370    /* convert load averages to doubles */
371    {
372	register int i;
373	register double *infoloadp;
374	register load_avg *sysloadp;
375
376	infoloadp = si->load_avg;
377	sysloadp = avenrun;
378	for (i = 0; i < 3; i++)
379	{
380	    *infoloadp++ = loaddouble(*sysloadp++);
381	}
382    }
383
384    /* convert cp_time counts to percentages */
385    total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
386
387    /* sum memory statistics */
388    {
389	struct vmtotal total;
390
391	/* get total -- systemwide main memory usage structure */
392	(void) getkval(total_offset, (int *)(&total), sizeof(total),
393		       "_total");
394	/* convert memory stats to Kbytes */
395	memory_stats[0] = -1;
396	memory_stats[1] = pagetok(total.t_arm);
397	memory_stats[2] = pagetok(total.t_rm);
398	memory_stats[3] = -1;
399	memory_stats[4] = pagetok(total.t_avm);
400	memory_stats[5] = pagetok(total.t_vm);
401	memory_stats[6] = pagetok(total.t_free);
402    }
403
404    /* set arrays and strings */
405    si->cpustates = cpu_states;
406    si->memory = memory_stats;
407}
408
409static struct handle handle;
410
411caddr_t get_process_info(si, sel, i)
412
413struct system_info *si;
414struct process_select *sel;
415int i;
416
417{
418    register int i;
419    register int total_procs;
420    register int active_procs;
421    register struct proc **prefp;
422    register struct proc *pp;
423
424    /* these are copied out of sel for speed */
425    int show_idle;
426    int show_system;
427    int show_uid;
428    int show_command;
429
430    /* read all the proc structures in one fell swoop */
431    (void) getkval(proc, (int *)pbase, bytes, "proc array");
432    for (i = 0; i < nproc; ++i) {
433	if (pstat(PSTAT_PROC, &pst[i], sizeof(pst[i]), 0, pbase[i].p_pid) != 1)
434	    pbase[i].p_upreg = (preg_t *) 0;
435	else
436	    pbase[i].p_upreg = (preg_t *) &pst[i];
437	pbase[i].p_nice = pst[i].pst_nice;
438	pbase[i].p_cpticks = pst[i].pst_cpticks;
439    }
440
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 *), 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 = __PST2P(pp, pst_cptickstotal) / hz;
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(P_RSSIZE(pp))),
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
585getu(p, u)
586
587register struct proc *p;
588struct user *u;
589
590{
591    struct pst_status *ps;
592    char *s, *c;
593    int i;
594
595    if ((ps = (struct pst_status *) p->p_upreg) == NULL)
596	return -1;
597
598    memset(u, 0, sizeof(struct user));
599    c = ps->pst_cmd;
600    ps->pst_cmd[PST_CLEN - 1] = '\0';        /* paranoia */
601    s = strtok(ps->pst_cmd, "\t \n");
602
603    if (c = strrchr(s, '/'))
604	c++;
605    else
606	c = s;
607    if (*c == '-')
608	c++;
609    i = 0;
610    for (; i < MAXCOMLEN; i++) {
611	if (*c == '\0' || *c == ' ' || *c == '/')
612	    break;
613	u->u_comm[i] = *c++;
614    }
615#ifndef DOSWAP
616    return ((p->p_flag & SLOAD) == 0 ? 1 : 0);
617#endif
618    return(0);
619}
620
621/*
622 * check_nlist(nlst) - checks the nlist to see if any symbols were not
623 *		found.  For every symbol that was not found, a one-line
624 *		message is printed to stderr.  The routine returns the
625 *		number of symbols NOT found.
626 */
627
628int check_nlist(nlst)
629
630register struct nlist *nlst;
631
632{
633    register int i;
634
635    /* check to see if we got ALL the symbols we requested */
636    /* this will write one line to stderr for every symbol not found */
637
638    i = 0;
639    while (nlst->n_name != NULL)
640    {
641	if (nlst->n_type == 0)
642	{
643	    /* this one wasn't found */
644	    fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
645	    i = 1;
646	}
647	nlst++;
648    }
649
650    return(i);
651}
652
653
654/*
655 *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
656 *	"offset" is the byte offset into the kernel for the desired value,
657 *  	"ptr" points to a buffer into which the value is retrieved,
658 *  	"size" is the size of the buffer (and the object to retrieve),
659 *  	"refstr" is a reference string used when printing error meessages,
660 *	    if "refstr" starts with a '!', then a failure on read will not
661 *  	    be fatal (this may seem like a silly way to do things, but I
662 *  	    really didn't want the overhead of another argument).
663 *
664 */
665
666getkval(offset, ptr, size, refstr)
667
668unsigned long offset;
669int *ptr;
670int size;
671char *refstr;
672
673{
674    if (lseek(kmem, (long)offset, L_SET) == -1) {
675        if (*refstr == '!')
676            refstr++;
677        (void) fprintf(stderr, "%s: lseek to %s: %s\n", KMEM,
678		       refstr, strerror(errno));
679        quit(23);
680    }
681    if (read(kmem, (char *) ptr, size) == -1) {
682        if (*refstr == '!')
683            return(0);
684        else {
685            (void) fprintf(stderr, "%s: reading %s: %s\n", KMEM,
686			   refstr, strerror(errno));
687            quit(23);
688        }
689    }
690    return(1);
691}
692
693/* comparison routine for qsort */
694
695/*
696 *  proc_compare - comparison function for "qsort"
697 *	Compares the resource consumption of two processes using five
698 *  	distinct keys.  The keys (in descending order of importance) are:
699 *  	percent cpu, cpu ticks, state, resident set size, total virtual
700 *  	memory usage.  The process states are ordered as follows (from least
701 *  	to most important):  WAIT, zombie, sleep, stop, start, run.  The
702 *  	array declaration below maps a process state index into a number
703 *  	that reflects this ordering.
704 */
705
706static unsigned char sorted_state[] =
707{
708    0,	/* not used		*/
709    3,	/* sleep		*/
710    1,	/* ABANDONED (WAIT)	*/
711    6,	/* run			*/
712    5,	/* start		*/
713    2,	/* zombie		*/
714    4	/* stop			*/
715};
716
717proc_compare(pp1, pp2)
718
719struct proc **pp1;
720struct proc **pp2;
721
722{
723    register struct proc *p1;
724    register struct proc *p2;
725    register int result;
726    register pctcpu lresult;
727
728    /* remove one level of indirection */
729    p1 = *pp1;
730    p2 = *pp2;
731
732    /* compare percent cpu (pctcpu) */
733    if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0)
734    {
735	/* use cpticks to break the tie */
736	if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
737	{
738	    /* use process state to break the tie */
739	    if ((result = sorted_state[p2->p_stat] -
740			  sorted_state[p1->p_stat])  == 0)
741	    {
742		/* use priority to break the tie */
743		if ((result = p2->p_pri - p1->p_pri) == 0)
744		{
745		    /* use resident set size (rssize) to break the tie */
746		    if ((result = P_RSSIZE(p2) - P_RSSIZE(p1)) == 0)
747		    {
748			/* use total memory to break the tie */
749			result = PROCSIZE(p2) - PROCSIZE(p1);
750		    }
751		}
752	    }
753	}
754    }
755    else
756    {
757	result = lresult < 0 ? -1 : 1;
758    }
759
760    return(result);
761}
762
763
764void (*signal(sig, func))()
765    int sig;
766    void (*func)();
767{
768    struct sigvec osv, sv;
769
770    /*
771     * XXX: we should block the signal we are playing with,
772     *	    in case we get interrupted in here.
773     */
774    if (sigvector(sig, NULL, &osv) == -1)
775	return BADSIG;
776    sv = osv;
777    sv.sv_handler = func;
778#ifdef SV_BSDSIG
779    sv.sv_flags |= SV_BSDSIG;
780#endif
781    if (sigvector(sig, &sv, NULL) == -1)
782	return BADSIG;
783    return osv.sv_handler;
784}
785
786int getpagesize() { return 1 << PGSHIFT; }
787
788int setpriority(a, b, c) { errno = ENOSYS; return -1; }
789
790/*
791 * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
792 *		the process does not exist.
793 *		It is EXTREMLY IMPORTANT that this function work correctly.
794 *		If top runs setuid root (as in SVR4), then this function
795 *		is the only thing that stands in the way of a serious
796 *		security problem.  It validates requests for the "kill"
797 *		and "renice" commands.
798 */
799
800int proc_owner(pid)
801
802int pid;
803
804{
805    register int cnt;
806    register struct proc **prefp;
807    register struct proc *pp;
808
809    prefp = pref;
810    cnt = pref_len;
811    while (--cnt >= 0)
812    {
813	if ((pp = *prefp++)->p_pid == (pid_t)pid)
814	{
815	    return((int)pp->p_uid);
816	}
817    }
818    return(-1);
819}
820