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