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