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