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:  Intel based System V Release 4
     37  1.1  christos  *
     38  1.1  christos  * DESCRIPTION:
     39  1.1  christos  *	System V release 4.0.x for i486
     40  1.1  christos  *	System V release 4     for Okidata M88100
     41  1.1  christos  *	System V release 4     for NCR 3000 series OS Rel 1.00 to 2.02
     42  1.1  christos  *	System V release 4     for NCR 3000 series OS Rel 02.03.00 and above
     43  1.1  christos  *	and probably other svr4 ports
     44  1.1  christos  *
     45  1.1  christos  * LIBS:  -lelf
     46  1.1  christos  *
     47  1.1  christos  * AUTHORS:  Andrew Herbert     <andrew (at) werple.apana.org.au>
     48  1.1  christos  *           Robert Boucher     <boucher (at) sofkin.ca>
     49  1.1  christos  * Ported to System 3000 Release 2.03 by:
     50  1.1  christos  * 	     Jeff Janvrin       <jeff.janvrinColumbiaSC.NCR.COM>
     51  1.1  christos  */
     52  1.1  christos 
     53  1.1  christos #include "top.h"
     54  1.1  christos #include "machine.h"
     55  1.1  christos #include "utils.h"
     56  1.1  christos #include <stdio.h>
     57  1.1  christos #include <fcntl.h>
     58  1.1  christos #include <unistd.h>
     59  1.1  christos #include <stdlib.h>
     60  1.1  christos #include <errno.h>
     61  1.1  christos #include <dirent.h>
     62  1.1  christos #include <nlist.h>
     63  1.1  christos #include <string.h>
     64  1.1  christos #if TIME_WITH_SYS_TIME
     65  1.1  christos # include <sys/time.h>
     66  1.1  christos # include <time.h>
     67  1.1  christos #else
     68  1.1  christos # if HAVE_SYS_TIME_H
     69  1.1  christos #  include <sys/time.h>
     70  1.1  christos # else
     71  1.1  christos #  include <time.h>
     72  1.1  christos # endif
     73  1.1  christos #endif
     74  1.1  christos #include <sys/types.h>
     75  1.1  christos #include <sys/stat.h>
     76  1.1  christos #include <sys/param.h>
     77  1.1  christos #include <sys/procfs.h>
     78  1.1  christos #include <sys/sysinfo.h>
     79  1.1  christos #include <sys/sysmacros.h>
     80  1.1  christos #include <sys/vmmeter.h>
     81  1.1  christos #include <vm/anon.h>
     82  1.1  christos #include <sys/priocntl.h>
     83  1.1  christos #include <sys/rtpriocntl.h>
     84  1.1  christos #include <sys/tspriocntl.h>
     85  1.1  christos #include <sys/procset.h>
     86  1.1  christos #include <sys/var.h>
     87  1.1  christos 
     88  1.1  christos #define UNIX "/stand/unix"
     89  1.1  christos #define KMEM "/dev/kmem"
     90  1.1  christos #define PROCFS "/proc"
     91  1.1  christos #define CPUSTATES	5
     92  1.1  christos 
     93  1.1  christos #ifndef PRIO_MAX
     94  1.1  christos #define PRIO_MAX	20
     95  1.1  christos #endif
     96  1.1  christos #ifndef PRIO_MIN
     97  1.1  christos #define PRIO_MIN	-20
     98  1.1  christos #endif
     99  1.1  christos 
    100  1.1  christos #ifndef FSCALE
    101  1.1  christos #define FSHIFT  8		/* bits to right of fixed binary point */
    102  1.1  christos #define FSCALE  (1<<FSHIFT)
    103  1.1  christos #endif
    104  1.1  christos 
    105  1.1  christos #define loaddouble(x) ((double)(x) / FSCALE)
    106  1.1  christos #define percent_cpu(x) ((double)(x)->pr_cpu / FSCALE)
    107  1.1  christos #define weighted_cpu(pct, pp) ( ((pp)->pr_time.tv_sec) == 0 ? 0.0 : \
    108  1.1  christos         ((pp)->pr_cpu) / ((pp)->pr_time.tv_sec) )
    109  1.1  christos #define pagetok(size) ctob(size) >> LOG1024
    110  1.1  christos 
    111  1.1  christos /* definitions for the index in the nlist array */
    112  1.1  christos #define X_AVENRUN	0
    113  1.1  christos #define X_MPID		1
    114  1.1  christos #define X_V		2
    115  1.1  christos #define X_NPROC		3
    116  1.1  christos #define X_ANONINFO	4
    117  1.1  christos #define X_TOTAL		5
    118  1.1  christos #define X_SYSINFO	6
    119  1.1  christos 
    120  1.1  christos static struct nlist nlst[] =
    121  1.1  christos {
    122  1.1  christos {"avenrun"},			/* 0 */
    123  1.1  christos {"mpid"},			/* 1 */
    124  1.1  christos {"v"},			/* 2 */
    125  1.1  christos {"nproc"},			/* 3 */
    126  1.1  christos {"anoninfo"},			/* 4 */
    127  1.1  christos {"total"},			/* 5 */
    128  1.1  christos {"sysinfo"},			/* 6 */
    129  1.1  christos {NULL}
    130  1.1  christos };
    131  1.1  christos 
    132  1.1  christos static unsigned long avenrun_offset;
    133  1.1  christos static unsigned long mpid_offset;
    134  1.1  christos static unsigned long nproc_offset;
    135  1.1  christos static unsigned long anoninfo_offset;
    136  1.1  christos static unsigned long total_offset;
    137  1.1  christos static unsigned long sysinfo_offset;
    138  1.1  christos 
    139  1.1  christos /* get_process_info passes back a handle.  This is what it looks like: */
    140  1.1  christos 
    141  1.1  christos struct handle
    142  1.1  christos   {
    143  1.1  christos     struct prpsinfo **next_proc;/* points to next valid proc pointer */
    144  1.1  christos     int remaining;		/* number of pointers remaining */
    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 #define Proc_format \
    156  1.1  christos 	"%5d %-8.8s %3d %4d %5s %5s %-5s %6s %3d.0%% %5.2f%% %.16s"
    157  1.1  christos 
    158  1.1  christos char *state_abbrev[] =
    159  1.1  christos {"", "sleep", "run", "zombie", "stop", "start", "cpu", "swap"};
    160  1.1  christos 
    161  1.1  christos int process_states[8];
    162  1.1  christos char *procstatenames[] =
    163  1.1  christos {
    164  1.1  christos   "", " sleeping, ", " running, ", " zombie, ", " stopped, ",
    165  1.1  christos   " starting, ", " on cpu, ", " swapped, ",
    166  1.1  christos   NULL
    167  1.1  christos };
    168  1.1  christos 
    169  1.1  christos int cpu_states[CPUSTATES];
    170  1.1  christos char *cpustatenames[] =
    171  1.1  christos {"idle", "user", "kernel", "wait", "swap", NULL};
    172  1.1  christos 
    173  1.1  christos /* these are for detailing the memory statistics */
    174  1.1  christos 
    175  1.1  christos long memory_stats[5];
    176  1.1  christos char *memorynames[] =
    177  1.1  christos {"K real, ", "K active, ", "K free, ", "K swap, ", "K free swap", NULL};
    178  1.1  christos 
    179  1.1  christos /* forward reference for qsort comparison function */
    180  1.1  christos int proc_compare();
    181  1.1  christos 
    182  1.1  christos static int kmem = -1;
    183  1.1  christos static int nproc;
    184  1.1  christos static int bytes;
    185  1.1  christos static int use_stats = 0;
    186  1.1  christos static struct prpsinfo *pbase;
    187  1.1  christos static struct prpsinfo **pref;
    188  1.1  christos static DIR *proc_dir;
    189  1.1  christos 
    190  1.1  christos /* useful externals */
    191  1.1  christos extern int errno;
    192  1.1  christos extern char *sys_errlist[];
    193  1.1  christos extern char *myname;
    194  1.1  christos extern int check_nlist ();
    195  1.1  christos extern int getkval ();
    196  1.1  christos extern void perror ();
    197  1.1  christos extern void getptable ();
    198  1.1  christos extern void quit ();
    199  1.1  christos extern int nlist ();
    200  1.1  christos 
    201  1.1  christos int
    202  1.1  christos machine_init (struct statics *statics)
    203  1.1  christos   {
    204  1.1  christos     static struct var v;
    205  1.1  christos 
    206  1.1  christos     /* fill in the statics information */
    207  1.1  christos     statics->procstate_names = procstatenames;
    208  1.1  christos     statics->cpustate_names = cpustatenames;
    209  1.1  christos     statics->memory_names = memorynames;
    210  1.1  christos 
    211  1.1  christos     /* get the list of symbols we want to access in the kernel */
    212  1.1  christos     if (nlist (UNIX, nlst))
    213  1.1  christos       {
    214  1.1  christos 	(void) fprintf (stderr, "Unable to nlist %s\n", UNIX);
    215  1.1  christos 	return (-1);
    216  1.1  christos       }
    217  1.1  christos 
    218  1.1  christos     /* make sure they were all found */
    219  1.1  christos     if (check_nlist (nlst) > 0)
    220  1.1  christos       return (-1);
    221  1.1  christos 
    222  1.1  christos     /* open kernel memory */
    223  1.1  christos     if ((kmem = open (KMEM, O_RDONLY)) == -1)
    224  1.1  christos       {
    225  1.1  christos 	perror (KMEM);
    226  1.1  christos 	return (-1);
    227  1.1  christos       }
    228  1.1  christos 
    229  1.1  christos     /* get the symbol values out of kmem */
    230  1.1  christos     /* NPROC Tuning parameter for max number of processes */
    231  1.1  christos     (void) getkval (nlst[X_V].n_value, &v, sizeof (struct var), nlst[X_V].n_name);
    232  1.1  christos     nproc = v.v_proc;
    233  1.1  christos 
    234  1.1  christos     /* stash away certain offsets for later use */
    235  1.1  christos     mpid_offset = nlst[X_MPID].n_value;
    236  1.1  christos     nproc_offset = nlst[X_NPROC].n_value;
    237  1.1  christos     avenrun_offset = nlst[X_AVENRUN].n_value;
    238  1.1  christos     anoninfo_offset = nlst[X_ANONINFO].n_value;
    239  1.1  christos     total_offset = nlst[X_TOTAL].n_value;
    240  1.1  christos /* JJ this may need to be changed */
    241  1.1  christos     sysinfo_offset = nlst[X_SYSINFO].n_value;
    242  1.1  christos 
    243  1.1  christos     /* allocate space for proc structure array and array of pointers */
    244  1.1  christos     bytes = nproc * sizeof (struct prpsinfo);
    245  1.1  christos     pbase = (struct prpsinfo *) malloc (bytes);
    246  1.1  christos     pref = (struct prpsinfo **) malloc (nproc * sizeof (struct prpsinfo *));
    247  1.1  christos 
    248  1.1  christos     /* Just in case ... */
    249  1.1  christos     if (pbase == (struct prpsinfo *) NULL || pref == (struct prpsinfo **) NULL)
    250  1.1  christos       {
    251  1.1  christos 	(void) fprintf (stderr, "%s: can't allocate sufficient memory\n", myname);
    252  1.1  christos 	return (-1);
    253  1.1  christos       }
    254  1.1  christos 
    255  1.1  christos     if (!(proc_dir = opendir (PROCFS)))
    256  1.1  christos       {
    257  1.1  christos 	(void) fprintf (stderr, "Unable to open %s\n", PROCFS);
    258  1.1  christos 	return (-1);
    259  1.1  christos       }
    260  1.1  christos 
    261  1.1  christos     if (chdir (PROCFS))
    262  1.1  christos       {				/* handy for later on when we're reading it */
    263  1.1  christos 	(void) fprintf (stderr, "Unable to chdir to %s\n", PROCFS);
    264  1.1  christos 	return (-1);
    265  1.1  christos       }
    266  1.1  christos 
    267  1.1  christos     /* all done! */
    268  1.1  christos     return (0);
    269  1.1  christos   }
    270  1.1  christos 
    271  1.1  christos char *
    272  1.1  christos format_header (char *uname_field)
    273  1.1  christos {
    274  1.1  christos   register char *ptr;
    275  1.1  christos 
    276  1.1  christos   ptr = header + UNAME_START;
    277  1.1  christos   while (*uname_field != '\0')
    278  1.1  christos     *ptr++ = *uname_field++;
    279  1.1  christos 
    280  1.1  christos   return (header);
    281  1.1  christos }
    282  1.1  christos 
    283  1.1  christos void
    284  1.1  christos get_system_info (struct system_info *si)
    285  1.1  christos {
    286  1.1  christos   long avenrun[3];
    287  1.1  christos   struct sysinfo sysinfo;
    288  1.1  christos   static struct sysinfo *mpinfo = NULL;	/* array, per-processor sysinfo structures. */
    289  1.1  christos   struct vmtotal total;
    290  1.1  christos   struct anoninfo anoninfo;
    291  1.1  christos   static long cp_old[CPUSTATES];
    292  1.1  christos   static long cp_diff[CPUSTATES];	/* for cpu state percentages */
    293  1.1  christos   static int num_cpus;
    294  1.1  christos   static int fd_cpu = 0;
    295  1.1  christos   register int i;
    296  1.1  christos 
    297  1.1  christos   if ( use_stats == 1) {
    298  1.1  christos     if ( fd_cpu == 0 ) {
    299  1.1  christos       if ((fd_cpu = open("/stats/cpuinfo", O_RDONLY)) == -1) {
    300  1.1  christos         (void) fprintf (stderr, "%s: Open of /stats/cpuinfo failed\n", myname);
    301  1.1  christos 	quit(2);
    302  1.1  christos       }
    303  1.1  christos       if (read(fd_cpu, &num_cpus, sizeof(int)) != sizeof(int)) {
    304  1.1  christos         (void) fprintf (stderr, "%s: Read of /stats/cpuinfo failed\n", myname);
    305  1.1  christos 	quit(2);
    306  1.1  christos       }
    307  1.1  christos       close(fd_cpu);
    308  1.1  christos     }
    309  1.1  christos     if (mpinfo == NULL) {
    310  1.1  christos       mpinfo = (struct sysinfo *)calloc(num_cpus, sizeof(mpinfo[0]));
    311  1.1  christos       if (mpinfo == NULL) {
    312  1.1  christos         (void) fprintf (stderr, "%s: can't allocate space for per-processor sysinfos\n", myname);
    313  1.1  christos         quit(12);
    314  1.1  christos       }
    315  1.1  christos     }
    316  1.1  christos     /* Read the per cpu sysinfo structures into mpinfo struct. */
    317  1.1  christos     read_sysinfos(num_cpus, mpinfo);
    318  1.1  christos     /* Add up all of the percpu sysinfos to get global sysinfo */
    319  1.1  christos     sysinfo_data(num_cpus, &sysinfo, mpinfo);
    320  1.1  christos   } else {
    321  1.1  christos     (void) getkval (sysinfo_offset, &sysinfo, sizeof (struct sysinfo), "sysinfo");
    322  1.1  christos   }
    323  1.1  christos 
    324  1.1  christos   /* convert cp_time counts to percentages */
    325  1.1  christos   (void) percentages (CPUSTATES, cpu_states, sysinfo.cpu, cp_old, cp_diff);
    326  1.1  christos 
    327  1.1  christos   /* get mpid -- process id of last process */
    328  1.1  christos   (void) getkval (mpid_offset, &(si->last_pid), sizeof (si->last_pid),
    329  1.1  christos 		  "mpid");
    330  1.1  christos 
    331  1.1  christos   /* get load average array */
    332  1.1  christos   (void) getkval (avenrun_offset, (int *) avenrun, sizeof (avenrun), "avenrun");
    333  1.1  christos 
    334  1.1  christos   /* convert load averages to doubles */
    335  1.1  christos   for (i = 0; i < 3; i++)
    336  1.1  christos     si->load_avg[i] = loaddouble (avenrun[i]);
    337  1.1  christos 
    338  1.1  christos   /* get total -- systemwide main memory usage structure */
    339  1.1  christos   (void) getkval (total_offset, (int *) (&total), sizeof (total), "total");
    340  1.1  christos   /* convert memory stats to Kbytes */
    341  1.1  christos   memory_stats[0] = pagetok (total.t_rm);
    342  1.1  christos   memory_stats[1] = pagetok (total.t_arm);
    343  1.1  christos   memory_stats[2] = pagetok (total.t_free);
    344  1.1  christos   (void) getkval (anoninfo_offset, (int *) (&anoninfo), sizeof (anoninfo),
    345  1.1  christos 		  "anoninfo");
    346  1.1  christos   memory_stats[3] = pagetok (anoninfo.ani_max - anoninfo.ani_free);
    347  1.1  christos   memory_stats[4] = pagetok (anoninfo.ani_max - anoninfo.ani_resv);
    348  1.1  christos 
    349  1.1  christos   /* set arrays and strings */
    350  1.1  christos   si->cpustates = cpu_states;
    351  1.1  christos   si->memory = memory_stats;
    352  1.1  christos }
    353  1.1  christos 
    354  1.1  christos static struct handle handle;
    355  1.1  christos 
    356  1.1  christos caddr_t
    357  1.1  christos get_process_info (
    358  1.1  christos 		   struct system_info *si,
    359  1.1  christos 		   struct process_select *sel,
    360  1.1  christos 		   int x)
    361  1.1  christos {
    362  1.1  christos   register int i;
    363  1.1  christos   register int total_procs;
    364  1.1  christos   register int active_procs;
    365  1.1  christos   register struct prpsinfo **prefp;
    366  1.1  christos   register struct prpsinfo *pp;
    367  1.1  christos 
    368  1.1  christos   /* these are copied out of sel for speed */
    369  1.1  christos   int show_idle;
    370  1.1  christos   int show_system;
    371  1.1  christos   int show_uid;
    372  1.1  christos 
    373  1.1  christos   /* Get current number of processes */
    374  1.1  christos   (void) getkval (nproc_offset, (int *) (&nproc), sizeof (nproc), "nproc");
    375  1.1  christos 
    376  1.1  christos   /* read all the proc structures */
    377  1.1  christos   getptable (pbase);
    378  1.1  christos 
    379  1.1  christos   /* get a pointer to the states summary array */
    380  1.1  christos   si->procstates = process_states;
    381  1.1  christos 
    382  1.1  christos   /* set up flags which define what we are going to select */
    383  1.1  christos   show_idle = sel->idle;
    384  1.1  christos   show_system = sel->system;
    385  1.1  christos   show_uid = sel->uid != -1;
    386  1.1  christos 
    387  1.1  christos   /* count up process states and get pointers to interesting procs */
    388  1.1  christos   total_procs = 0;
    389  1.1  christos   active_procs = 0;
    390  1.1  christos   (void) memset (process_states, 0, sizeof (process_states));
    391  1.1  christos   prefp = pref;
    392  1.1  christos 
    393  1.1  christos   for (pp = pbase, i = 0; i < nproc; pp++, i++)
    394  1.1  christos     {
    395  1.1  christos       /*
    396  1.1  christos 	 *  Place pointers to each valid proc structure in pref[].
    397  1.1  christos 	 *  Process slots that are actually in use have a non-zero
    398  1.1  christos 	 *  status field.  Processes with SSYS set are system
    399  1.1  christos 	 *  processes---these get ignored unless show_sysprocs is set.
    400  1.1  christos 	 */
    401  1.1  christos       if (pp->pr_state != 0 &&
    402  1.1  christos 	  (show_system || ((pp->pr_flag & SSYS) == 0)))
    403  1.1  christos 	{
    404  1.1  christos 	  total_procs++;
    405  1.1  christos 	  process_states[pp->pr_state]++;
    406  1.1  christos 	  if ((!pp->pr_zomb) &&
    407  1.1  christos 	      (show_idle || (pp->pr_state == SRUN) || (pp->pr_state == SONPROC)) &&
    408  1.1  christos 	      (!show_uid || pp->pr_uid == (uid_t) sel->uid))
    409  1.1  christos 	    {
    410  1.1  christos 	      *prefp++ = pp;
    411  1.1  christos 	      active_procs++;
    412  1.1  christos 	    }
    413  1.1  christos 	}
    414  1.1  christos     }
    415  1.1  christos 
    416  1.1  christos   /* if requested, sort the "interesting" processes */
    417  1.1  christos   qsort ((char *) pref, active_procs, sizeof (struct prpsinfo *), proc_compare);
    418  1.1  christos 
    419  1.1  christos   /* remember active and total counts */
    420  1.1  christos   si->p_total = total_procs;
    421  1.1  christos   si->p_active = active_procs;
    422  1.1  christos 
    423  1.1  christos   /* pass back a handle */
    424  1.1  christos   handle.next_proc = pref;
    425  1.1  christos   handle.remaining = active_procs;
    426  1.1  christos   return ((caddr_t) & handle);
    427  1.1  christos }
    428  1.1  christos 
    429  1.1  christos char fmt[MAX_COLS];			/* static area where result is built */
    430  1.1  christos 
    431  1.1  christos char *
    432  1.1  christos format_next_process (
    433  1.1  christos 		      caddr_t handle,
    434  1.1  christos 		      char *(*get_userid) ())
    435  1.1  christos {
    436  1.1  christos   register struct prpsinfo *pp;
    437  1.1  christos   struct handle *hp;
    438  1.1  christos   register long cputime;
    439  1.1  christos   register double pctcpu;
    440  1.1  christos 
    441  1.1  christos   /* find and remember the next proc structure */
    442  1.1  christos   hp = (struct handle *) handle;
    443  1.1  christos   pp = *(hp->next_proc++);
    444  1.1  christos   hp->remaining--;
    445  1.1  christos 
    446  1.1  christos   /* get the cpu usage and calculate the cpu percentages */
    447  1.1  christos   cputime = pp->pr_time.tv_sec;
    448  1.1  christos   pctcpu = percent_cpu (pp);
    449  1.1  christos 
    450  1.1  christos   /* format this entry */
    451  1.1  christos   (void) sprintf (fmt,
    452  1.1  christos 		  Proc_format,
    453  1.1  christos 		  pp->pr_pid,
    454  1.1  christos 		  (*get_userid) (pp->pr_uid),
    455  1.1  christos 		  pp->pr_pri - PZERO,
    456  1.1  christos 		  pp->pr_nice - NZERO,
    457  1.1  christos 		  format_k(pagetok (pp->pr_size)),
    458  1.1  christos 		  format_k(pagetok (pp->pr_rssize)),
    459  1.1  christos 		  state_abbrev[pp->pr_state],
    460  1.1  christos 		  format_time(cputime),
    461  1.1  christos 		  (pp->pr_cpu & 0377),
    462  1.1  christos 		  100.0 * pctcpu,
    463  1.1  christos 		  printable(pp->pr_fname));
    464  1.1  christos 
    465  1.1  christos   /* return the result */
    466  1.1  christos   return (fmt);
    467  1.1  christos }
    468  1.1  christos 
    469  1.1  christos /*
    470  1.1  christos  * check_nlist(nlst) - checks the nlist to see if any symbols were not
    471  1.1  christos  *		found.  For every symbol that was not found, a one-line
    472  1.1  christos  *		message is printed to stderr.  The routine returns the
    473  1.1  christos  *		number of symbols NOT found.
    474  1.1  christos  */
    475  1.1  christos int
    476  1.1  christos check_nlist (register struct nlist *nlst)
    477  1.1  christos {
    478  1.1  christos   register int i;
    479  1.1  christos   struct stat stat_buf;
    480  1.1  christos 
    481  1.1  christos   /* check to see if we got ALL the symbols we requested */
    482  1.1  christos   /* this will write one line to stderr for every symbol not found */
    483  1.1  christos 
    484  1.1  christos   i = 0;
    485  1.1  christos   while (nlst->n_name != NULL)
    486  1.1  christos     {
    487  1.1  christos       if (nlst->n_type == 0)
    488  1.1  christos 	{
    489  1.1  christos 	  if (strcmp("sysinfo", nlst->n_name) == 0)
    490  1.1  christos 	    {
    491  1.1  christos 		/* check to see if /stats file system exists. If so, 	*/
    492  1.1  christos 		/* ignore error. 					*/
    493  1.1  christos 		if ( !((stat("/stats/sysinfo", &stat_buf) == 0) &&
    494  1.1  christos 		  (stat_buf.st_mode & S_IFREG)) )
    495  1.1  christos 		  {
    496  1.1  christos 		    (void) fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
    497  1.1  christos 		    i = 1;
    498  1.1  christos 		  } else {
    499  1.1  christos 		    use_stats = 1;
    500  1.1  christos 		  }
    501  1.1  christos 	    } else {
    502  1.1  christos 
    503  1.1  christos 	      /* this one wasn't found */
    504  1.1  christos 	      (void) fprintf (stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
    505  1.1  christos 	      i = 1;
    506  1.1  christos 	    }
    507  1.1  christos 	}
    508  1.1  christos       nlst++;
    509  1.1  christos     }
    510  1.1  christos   return (i);
    511  1.1  christos }
    512  1.1  christos 
    513  1.1  christos 
    514  1.1  christos /*
    515  1.1  christos  *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
    516  1.1  christos  *	"offset" is the byte offset into the kernel for the desired value,
    517  1.1  christos  *  	"ptr" points to a buffer into which the value is retrieved,
    518  1.1  christos  *  	"size" is the size of the buffer (and the object to retrieve),
    519  1.1  christos  *  	"refstr" is a reference string used when printing error meessages,
    520  1.1  christos  *	    if "refstr" starts with a '!', then a failure on read will not
    521  1.1  christos  *  	    be fatal (this may seem like a silly way to do things, but I
    522  1.1  christos  *  	    really didn't want the overhead of another argument).
    523  1.1  christos  *
    524  1.1  christos  */
    525  1.1  christos int
    526  1.1  christos getkval (
    527  1.1  christos 	  unsigned long offset,
    528  1.1  christos 	  int *ptr,
    529  1.1  christos 	  int size,
    530  1.1  christos 	  char *refstr)
    531  1.1  christos {
    532  1.1  christos #ifdef MIPS
    533  1.1  christos   if (lseek (kmem, (long) (offset & 0x7fffffff), 0) == -1)
    534  1.1  christos #else
    535  1.1  christos   if (lseek (kmem, (long) offset, 0) == -1)
    536  1.1  christos #endif
    537  1.1  christos     {
    538  1.1  christos       if (*refstr == '!')
    539  1.1  christos 	refstr++;
    540  1.1  christos       (void) fprintf (stderr, "%s: lseek to %s: %s\n",
    541  1.1  christos 		      myname, refstr, sys_errlist[errno]);
    542  1.1  christos       quit (22);
    543  1.1  christos     }
    544  1.1  christos   if (read (kmem, (char *) ptr, size) == -1)
    545  1.1  christos     if (*refstr == '!')
    546  1.1  christos       /* we lost the race with the kernel, process isn't in memory */
    547  1.1  christos       return (0);
    548  1.1  christos     else
    549  1.1  christos       {
    550  1.1  christos 	(void) fprintf (stderr, "%s: reading %s: %s\n",
    551  1.1  christos 			myname, refstr, sys_errlist[errno]);
    552  1.1  christos 	quit (23);
    553  1.1  christos       }
    554  1.1  christos   return (1);
    555  1.1  christos }
    556  1.1  christos 
    557  1.1  christos /* comparison routine for qsort */
    558  1.1  christos 
    559  1.1  christos /*
    560  1.1  christos  *  proc_compare - comparison function for "qsort"
    561  1.1  christos  *	Compares the resource consumption of two processes using five
    562  1.1  christos  *  	distinct keys.  The keys (in descending order of importance) are:
    563  1.1  christos  *  	percent cpu, cpu ticks, state, resident set size, total virtual
    564  1.1  christos  *  	memory usage.  The process states are ordered as follows (from least
    565  1.1  christos  *  	to most important):  WAIT, zombie, sleep, stop, start, run.  The
    566  1.1  christos  *  	array declaration below maps a process state index into a number
    567  1.1  christos  *  	that reflects this ordering.
    568  1.1  christos  */
    569  1.1  christos 
    570  1.1  christos 
    571  1.1  christos unsigned char sorted_state[] =
    572  1.1  christos {
    573  1.1  christos   0,				/* not used		*/
    574  1.1  christos   3,				/* sleep		*/
    575  1.1  christos   6,				/* run			*/
    576  1.1  christos   2,				/* zombie		*/
    577  1.1  christos   4,				/* stop			*/
    578  1.1  christos   5,				/* start		*/
    579  1.1  christos   7,				/* run on a processor   */
    580  1.1  christos   1				/* being swapped (WAIT)	*/
    581  1.1  christos };
    582  1.1  christos 
    583  1.1  christos int
    584  1.1  christos proc_compare (
    585  1.1  christos 	       struct prpsinfo **pp1,
    586  1.1  christos 	       struct prpsinfo **pp2)
    587  1.1  christos {
    588  1.1  christos     register struct prpsinfo *p1;
    589  1.1  christos     register struct prpsinfo *p2;
    590  1.1  christos     register long result;
    591  1.1  christos 
    592  1.1  christos     /* remove one level of indirection */
    593  1.1  christos     p1 = *pp1;
    594  1.1  christos     p2 = *pp2;
    595  1.1  christos 
    596  1.1  christos     /* compare percent cpu (pctcpu) */
    597  1.1  christos     if ((result = (long) (p2->pr_cpu - p1->pr_cpu)) == 0)
    598  1.1  christos       {
    599  1.1  christos 	/* use cpticks to break the tie */
    600  1.1  christos 	if ((result = p2->pr_time.tv_sec - p1->pr_time.tv_sec) == 0)
    601  1.1  christos 	  {
    602  1.1  christos 	    /* use process state to break the tie */
    603  1.1  christos 	    if ((result = (long) (sorted_state[p2->pr_state] -
    604  1.1  christos 				  sorted_state[p1->pr_state])) == 0)
    605  1.1  christos 	      {
    606  1.1  christos 		/* use priority to break the tie */
    607  1.1  christos 		if ((result = p2->pr_oldpri - p1->pr_oldpri) == 0)
    608  1.1  christos 		  {
    609  1.1  christos 		    /* use resident set size (rssize) to break the tie */
    610  1.1  christos 		    if ((result = p2->pr_rssize - p1->pr_rssize) == 0)
    611  1.1  christos 		      {
    612  1.1  christos 			/* use total memory to break the tie */
    613  1.1  christos 			result = (p2->pr_size - p1->pr_size);
    614  1.1  christos 		      }
    615  1.1  christos 		  }
    616  1.1  christos 	      }
    617  1.1  christos 	  }
    618  1.1  christos       }
    619  1.1  christos     return (result);
    620  1.1  christos   }
    621  1.1  christos 
    622  1.1  christos /*
    623  1.1  christos get process table
    624  1.1  christos */
    625  1.1  christos void
    626  1.1  christos getptable (struct prpsinfo *baseptr)
    627  1.1  christos {
    628  1.1  christos   struct prpsinfo *currproc;	/* pointer to current proc structure	*/
    629  1.1  christos   int numprocs = 0;
    630  1.1  christos   struct dirent *direntp;
    631  1.1  christos 
    632  1.1  christos   for (rewinddir (proc_dir); direntp = readdir (proc_dir);)
    633  1.1  christos     {
    634  1.1  christos       int fd;
    635  1.1  christos 
    636  1.1  christos       if ((fd = open (direntp->d_name, O_RDONLY)) < 0)
    637  1.1  christos 	continue;
    638  1.1  christos 
    639  1.1  christos       currproc = &baseptr[numprocs];
    640  1.1  christos       if (ioctl (fd, PIOCPSINFO, currproc) < 0)
    641  1.1  christos 	{
    642  1.1  christos 	  (void) close (fd);
    643  1.1  christos 	  continue;
    644  1.1  christos 	}
    645  1.1  christos 
    646  1.1  christos       numprocs++;
    647  1.1  christos       (void) close (fd);
    648  1.1  christos     }
    649  1.1  christos 
    650  1.1  christos   if (nproc != numprocs)
    651  1.1  christos     nproc = numprocs;
    652  1.1  christos }
    653  1.1  christos 
    654  1.1  christos /* return the owner of the specified process, for use in commands.c as we're
    655  1.1  christos    running setuid root */
    656  1.1  christos int
    657  1.1  christos proc_owner (int pid)
    658  1.1  christos {
    659  1.1  christos   register struct prpsinfo *p;
    660  1.1  christos   int i;
    661  1.1  christos   for (i = 0, p = pbase; i < nproc; i++, p++)
    662  1.1  christos     if (p->pr_pid == (pid_t)pid)
    663  1.1  christos       return (p->pr_uid);
    664  1.1  christos 
    665  1.1  christos   return (-1);
    666  1.1  christos }
    667  1.1  christos 
    668  1.1  christos #ifndef HAVE_SETPRIORITY
    669  1.1  christos int
    670  1.1  christos setpriority (int dummy, int who, int niceval)
    671  1.1  christos {
    672  1.1  christos   int scale;
    673  1.1  christos   int prio;
    674  1.1  christos   pcinfo_t pcinfo;
    675  1.1  christos   pcparms_t pcparms;
    676  1.1  christos   tsparms_t *tsparms;
    677  1.1  christos 
    678  1.1  christos   strcpy (pcinfo.pc_clname, "TS");
    679  1.1  christos   if (priocntl (0, 0, PC_GETCID, (caddr_t) & pcinfo) == -1)
    680  1.1  christos     return (-1);
    681  1.1  christos 
    682  1.1  christos   prio = niceval;
    683  1.1  christos   if (prio > PRIO_MAX)
    684  1.1  christos     prio = PRIO_MAX;
    685  1.1  christos   else if (prio < PRIO_MIN)
    686  1.1  christos     prio = PRIO_MIN;
    687  1.1  christos 
    688  1.1  christos   tsparms = (tsparms_t *) pcparms.pc_clparms;
    689  1.1  christos   scale = ((tsinfo_t *) pcinfo.pc_clinfo)->ts_maxupri;
    690  1.1  christos   tsparms->ts_uprilim = tsparms->ts_upri = -(scale * prio) / 20;
    691  1.1  christos   pcparms.pc_cid = pcinfo.pc_cid;
    692  1.1  christos 
    693  1.1  christos   if (priocntl (P_PID, who, PC_SETPARMS, (caddr_t) & pcparms) == -1)
    694  1.1  christos     return (-1);
    695  1.1  christos 
    696  1.1  christos   return (0);
    697  1.1  christos }
    698  1.1  christos #endif
    699  1.1  christos 
    700  1.1  christos /****************************************************************
    701  1.1  christos  * read_sysinfos() -						*
    702  1.1  christos  *	Read all of the CPU specific sysinfo sturctures in from	*
    703  1.1  christos  *	the /stats file system.					*
    704  1.1  christos  ****************************************************************/
    705  1.1  christos read_sysinfos(num_cpus, buf)
    706  1.1  christos 	int num_cpus;
    707  1.1  christos 	struct sysinfo	*buf;
    708  1.1  christos {
    709  1.1  christos 
    710  1.1  christos 	static int	fd1=0;	/* file descriptor for /stats/sysinfo */
    711  1.1  christos 	int		read_sz;
    712  1.1  christos 
    713  1.1  christos 	/* Open /stats/sysinfo one time only and leave it open */
    714  1.1  christos 	if (fd1==0) {
    715  1.1  christos 		if ((fd1 = open("/stats/sysinfo", O_RDONLY)) == -1)
    716  1.1  christos 			(void) fprintf (stderr, "%s: Open of /stats/sysinfo failed\n", myname);
    717  1.1  christos 	}
    718  1.1  christos 	/* reset the read pointer to the beginning of the file */
    719  1.1  christos 	if (lseek(fd1, 0L, SEEK_SET) == -1)
    720  1.1  christos 		(void) fprintf (stderr, "%s: lseek to beginning of /stats/sysinfo failed\n", myname);
    721  1.1  christos 	read_sz = num_cpus * sizeof(buf[0]);
    722  1.1  christos 	if (read(fd1, buf, read_sz) != read_sz)
    723  1.1  christos 		(void) fprintf (stderr, "%s: Read of /stats/sysinfo failed\n", myname);
    724  1.1  christos }
    725  1.1  christos 
    726  1.1  christos /****************************************************************
    727  1.1  christos  * sysinfo_data() -						*
    728  1.1  christos  *	Add up all of the CPU specific sysinfo sturctures to	*
    729  1.1  christos  *	make the GLOBAL sysinfo.				*
    730  1.1  christos  ****************************************************************/
    731  1.1  christos sysinfo_data(num_cpus, global_si, percpu_si)
    732  1.1  christos 	int num_cpus;
    733  1.1  christos 	struct sysinfo	*global_si;
    734  1.1  christos 	struct sysinfo	*percpu_si;
    735  1.1  christos {
    736  1.1  christos 	struct sysinfo	*percpu_p;
    737  1.1  christos 	int		cpu, i, *global, *src;
    738  1.1  christos 
    739  1.1  christos 	/* null out the global statistics from last sample */
    740  1.1  christos 	memset(global_si, 0, sizeof(struct sysinfo));
    741  1.1  christos 
    742  1.1  christos 	percpu_p = (struct sysinfo *)percpu_si;
    743  1.1  christos 	for(cpu = 0; cpu < num_cpus; cpu++) {
    744  1.1  christos 		global = (int *)global_si;
    745  1.1  christos 		src = (int *)percpu_p;
    746  1.1  christos 
    747  1.1  christos 		/* assume sysinfo ends on an int boundary */
    748  1.1  christos 		/* Currently, all of the struct sysinfo members are the same
    749  1.1  christos 		 * size as an int. If that changes, we may not be able to
    750  1.1  christos 		 * do this. But this should be safe.
    751  1.1  christos 		 */
    752  1.1  christos 		for(i=0; i<sizeof(struct sysinfo)/sizeof(int); i++) {
    753  1.1  christos 			*global++ += *src++;
    754  1.1  christos 		}
    755  1.1  christos 		percpu_p++;
    756  1.1  christos 	}
    757  1.1  christos }
    758