home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume27 / top-3.2 / part06 < prev    next >
Text File  |  1993-08-08  |  56KB  |  2,214 lines

  1. Newsgroups: comp.sources.unix
  2. From: phil@eecs.nwu.edu (William LeFebvre)
  3. Subject: v27i006: top - a top process display, version 3.2, Part06/13
  4. References: <1.744843136.4744@gw.home.vix.com>
  5. Sender: unix-sources-moderator@gw.home.vix.com
  6. Approved: vixie@gw.home.vix.com
  7.  
  8. Submitted-By: phil@eecs.nwu.edu (William LeFebvre)
  9. Posting-Number: Volume 27, Issue 6
  10. Archive-Name: top-3.2/part06
  11.  
  12. #! /bin/sh
  13. # This is a shell archive.  Remove anything before this line, then unpack
  14. # it by saving it into a file and typing "sh file".  To overwrite existing
  15. # files, type "sh file -c".  You can also feed this as standard input via
  16. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  17. # will see the following message at the end:
  18. #        "End of archive 6 (of 13)."
  19. # Contents:  machine/m_386bsd.c machine/m_bsd386.c machine/m_dynix.c
  20. # Wrapped by phil@pex on Wed Aug  4 14:22:43 1993
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'machine/m_386bsd.c' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'machine/m_386bsd.c'\"
  24. else
  25. echo shar: Extracting \"'machine/m_386bsd.c'\" \(17022 characters\)
  26. sed "s/^X//" >'machine/m_386bsd.c' <<'END_OF_FILE'
  27. X/*
  28. X * top - a top users display for Unix
  29. X *
  30. X * SYNOPSIS:  For a 386BSD system
  31. X *          Note memory statistisc and process sizes could be wrong,
  32. X *          by ps gets them wrong too...
  33. X *
  34. X * DESCRIPTION:
  35. X * This is the machine-dependent module for BSD4.3  NET/2 386bsd
  36. X * Works for:
  37. X *    i386 PC
  38. X *
  39. X * LIBS: -lutil
  40. X *
  41. X * AUTHOR:  Steve Hocking (adapted from Christos Zoulas <christos@ee.cornell.edu>)
  42. X *        Updated by Andrew Herbert <andrew@werple.apana.org.au>
  43. X */
  44. X
  45. X#include <sys/types.h>
  46. X#include <sys/signal.h>
  47. X#include <sys/param.h>
  48. X
  49. X#include <stdio.h>
  50. X#include <nlist.h>
  51. X#include <math.h>
  52. X#include <kvm.h>
  53. X#include <sys/errno.h>
  54. X#include <sys/kinfo.h>
  55. X#include <sys/kinfo_proc.h>
  56. X#ifdef notyet
  57. X#define time __time
  58. X#define hz __hz
  59. X#include <sys/kernel.h>
  60. X#undef time
  61. X#undef hz
  62. X#endif
  63. X#include <sys/dir.h>
  64. X#include <sys/dkstat.h>
  65. X#include <sys/file.h>
  66. X#include <sys/time.h>
  67. X#include <sys/vmmeter.h>
  68. X
  69. X
  70. X/* #define PATCHED_KVM        /* YOU PROBABLY DON'T NEED THIS DEFINED! */
  71. X                /* define this if you have a kvm.c */
  72. X                /* that has been patched not to freshly */
  73. X                /* alloc an array of procs each time */
  74. X                /* kvm_getprocs is called, but to do a */
  75. X                /* realloc when the no. of processes inc. */
  76. X
  77. X/* #define TOTAL_WORKING */    /* Uncomment when the total structure in */
  78. X                /* the kernel actually works */
  79. X#define DOSWAP
  80. X
  81. X#include "top.h"
  82. X#include "machine.h"
  83. X
  84. X#define VMUNIX    "/386bsd"
  85. X#define KMEM    "/dev/kmem"
  86. X#define MEM    "/dev/mem"
  87. X#ifdef DOSWAP
  88. X#define SWAP    "/dev/drum"
  89. X#endif
  90. X
  91. Xtypedef struct _kinfo {
  92. X        struct proc ki_p;      /* proc structure */
  93. X        struct eproc ki_e;     /* extra stuff */
  94. X} KINFO;
  95. X
  96. X/* get_process_info passes back a handle.  This is what it looks like: */
  97. X
  98. Xstruct handle
  99. X{
  100. X    KINFO **next_proc;    /* points to next valid proc pointer */
  101. X    int remaining;        /* number of pointers remaining */
  102. X};
  103. X
  104. X/* declarations for load_avg */
  105. X#include "loadavg.h"
  106. X
  107. X#define PP(pp, field) ((pp)->ki_p . field)
  108. X#define EP(pp, field) ((pp)->ki_e . field)
  109. X#define VP(pp, field) ((pp)->ki_e.e_vm . field)
  110. X
  111. X/* define what weighted cpu is.  */
  112. X#define weighted_cpu(pct, pp) (PP((pp), p_time) == 0 ? 0.0 : \
  113. X             ((pct) / (1.0 - exp(PP((pp), p_time) * logcpu))))
  114. X
  115. X/* what we consider to be process size: */
  116. X#define PROCSIZE(pp) (VP((pp), vm_tsize) + VP((pp), vm_dsize) + VP((pp), vm_ssize))
  117. X
  118. X/* definitions for indices in the nlist array */
  119. X#define X_CCPU        0
  120. X#define X_CP_TIME    1
  121. X#define X_HZ        2
  122. X#define X_AVENRUN    3
  123. X#define X_TOTAL        4
  124. X#define X_PG_FREE    5
  125. X#define X_PG_ACTIVE    6
  126. X#define X_PG_INACTIVE    7
  127. X#define X_PG_WIRED    8
  128. X
  129. Xstatic struct nlist nlst[] = {
  130. X    { "_ccpu" },        /* 0 */
  131. X    { "_cp_time" },        /* 1 */
  132. X    { "_hz" },            /* 2 */
  133. X    { "_averunnable" },        /* 3 */
  134. X    { "_total"},        /* 4 */
  135. X    { "_vm_page_free_count" },    /* 5 */
  136. X    { "_vm_page_active_count" },    /* 6 */
  137. X    { "_vm_page_inactive_count" },/* 7 */
  138. X    { "_vm_page_wire_count" },    /* 8 */
  139. X    { 0 }
  140. X};
  141. X
  142. X/*
  143. X *  These definitions control the format of the per-process area
  144. X */
  145. X
  146. Xstatic char header[] =
  147. X  "  PID X        PRI NICE   SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
  148. X/* 0123456   -- field to fill in starts at header+6 */
  149. X#define UNAME_START 6
  150. X
  151. X#define Proc_format \
  152. X    "%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %5.2f%% %5.2f%% %.14s"
  153. X
  154. X
  155. X/* process state names for the "STATE" column of the display */
  156. X/* the extra nulls in the string "run" are for adding a slash and
  157. X   the processor number when needed */
  158. X
  159. Xchar *state_abbrev[] =
  160. X{
  161. X    "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
  162. X};
  163. X
  164. X
  165. X/* values that we stash away in _init and use in later routines */
  166. X
  167. Xstatic double logcpu;
  168. X
  169. X/* these are retrieved from the kernel in _init */
  170. X
  171. Xstatic          long hz;
  172. Xstatic load_avg  ccpu;
  173. Xstatic          int  ncpu = 0;
  174. X
  175. X/* these are offsets obtained via nlist and used in the get_ functions */
  176. X
  177. Xstatic unsigned long cp_time_offset;
  178. Xstatic unsigned long avenrun_offset;
  179. X
  180. X/* these are for calculating cpu state percentages */
  181. X
  182. Xstatic long cp_time[CPUSTATES];
  183. Xstatic long cp_old[CPUSTATES];
  184. Xstatic long cp_diff[CPUSTATES];
  185. X
  186. X/* these are for detailing the process states */
  187. X
  188. Xint process_states[7];
  189. Xchar *procstatenames[] = {
  190. X    "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
  191. X    " zombie, ", " stopped, ",
  192. X    NULL
  193. X};
  194. X
  195. X/* these are for detailing the cpu states */
  196. X
  197. Xint cpu_states[4];
  198. Xchar *cpustatenames[] = {
  199. X    "user", "nice", "system", "idle", NULL
  200. X};
  201. X
  202. X/* these are for detailing the memory statistics */
  203. X
  204. Xint memory_stats[8];
  205. Xchar *memorynames[] = {
  206. X#ifdef    TOTAL_WORKING
  207. X    "Real: ", "K/", "K ", "Virt: ", "K/",
  208. X    "K ", "Free: ", "K", NULL
  209. X#else
  210. X    " Free: ", "K ", " Active: ", "K ", " Inactive: ",
  211. X    "K ", " Wired: ", "K ", NULL
  212. X#endif
  213. X};
  214. X
  215. X/* these are for keeping track of the proc array */
  216. X
  217. Xstatic int bytes;
  218. Xstatic int nproc;
  219. Xstatic int onproc = -1;
  220. Xstatic int pref_len;
  221. Xstatic KINFO *pbase;
  222. Xstatic KINFO **pref;
  223. X
  224. X/* these are for getting the memory statistics */
  225. X
  226. Xstatic int pageshift;        /* log base 2 of the pagesize */
  227. X
  228. X/* define pagetok in terms of pageshift */
  229. X
  230. X#define pagetok(size) ((size) << pageshift)
  231. X
  232. X/* useful externals */
  233. Xlong percentages();
  234. X
  235. Xmachine_init(statics)
  236. X
  237. Xstruct statics *statics;
  238. X
  239. X{
  240. X    register int i = 0;
  241. X    register int pagesize;
  242. X    char buf[1024];
  243. X
  244. X#if 0        /* some funny stuff going on here */
  245. X    if (kvm_openfiles(NULL, NULL, NULL) == -1);
  246. X    return -1;
  247. X#else
  248. X    kvm_openfiles(VMUNIX, NULL, NULL);
  249. X#endif
  250. X
  251. X    /* get the list of symbols we want to access in the kernel */
  252. X    (void) kvm_nlist(nlst);
  253. X    if (nlst[0].n_type == 0)
  254. X    {
  255. X    fprintf(stderr, "top: nlist failed\n");
  256. X    return(-1);
  257. X    }
  258. X
  259. X    /* make sure they were all found */
  260. X    if (i > 0 && check_nlist(nlst) > 0)
  261. X    {
  262. X    return(-1);
  263. X    }
  264. X
  265. X    /* get the symbol values out of kmem */
  266. X    (void) getkval(nlst[X_HZ].n_value,     (int *)(&hz),    sizeof(hz),
  267. X        nlst[X_HZ].n_name);
  268. X    (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),    sizeof(ccpu),
  269. X        nlst[X_CCPU].n_name);
  270. X
  271. X    /* stash away certain offsets for later use */
  272. X    cp_time_offset = nlst[X_CP_TIME].n_value;
  273. X    avenrun_offset = nlst[X_AVENRUN].n_value;
  274. X
  275. X    /* this is used in calculating WCPU -- calculate it ahead of time */
  276. X    logcpu = log(loaddouble(ccpu));
  277. X
  278. X    pbase = NULL;
  279. X    pref = NULL;
  280. X    nproc = 0;
  281. X    onproc = -1;
  282. X    /* get the page size with "getpagesize" and calculate pageshift from it */
  283. X    pagesize = getpagesize();
  284. X    pageshift = 0;
  285. X    while (pagesize > 1)
  286. X    {
  287. X    pageshift++;
  288. X    pagesize >>= 1;
  289. X    }
  290. X
  291. X    /* we only need the amount of log(2)1024 for our conversion */
  292. X    pageshift -= LOG1024;
  293. X
  294. X    /* fill in the statics information */
  295. X    statics->procstate_names = procstatenames;
  296. X    statics->cpustate_names = cpustatenames;
  297. X    statics->memory_names = memorynames;
  298. X
  299. X    /* all done! */
  300. X    return(0);
  301. X}
  302. X
  303. Xchar *format_header(uname_field)
  304. X
  305. Xregister char *uname_field;
  306. X
  307. X{
  308. X    register char *ptr;
  309. X
  310. X    ptr = header + UNAME_START;
  311. X    while (*uname_field != '\0')
  312. X    {
  313. X    *ptr++ = *uname_field++;
  314. X    }
  315. X
  316. X    return(header);
  317. X}
  318. X
  319. Xget_system_info(si)
  320. X
  321. Xstruct system_info *si;
  322. X
  323. X{
  324. X    long total;
  325. X    load_avg avenrun[3];
  326. X
  327. X    /* get the cp_time array */
  328. X    (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
  329. X           "_cp_time");
  330. X    (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
  331. X           "_avenrun");
  332. X
  333. X    /* convert load averages to doubles */
  334. X    {
  335. X    register int i;
  336. X    register double *infoloadp;
  337. X    load_avg *avenrunp;
  338. X
  339. X#ifdef KINFO_LOADAVG
  340. X    struct loadavg sysload;
  341. X    int size;
  342. X    getkerninfo(KINFO_LOADAVG, &sysload, &size, 0);
  343. X#endif
  344. X
  345. X    infoloadp = si->load_avg;
  346. X    avenrunp = avenrun;
  347. X    for (i = 0; i < 3; i++)
  348. X    {
  349. X#ifdef KINFO_LOADAVG
  350. X        *infoloadp++ = ((double) sysload.ldavg[i]) / sysload.fscale;
  351. X#endif
  352. X        *infoloadp++ = loaddouble(*avenrunp++);
  353. X    }
  354. X    }
  355. X
  356. X    /* convert cp_time counts to percentages */
  357. X    total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
  358. X
  359. X    /* sum memory statistics */
  360. X    {
  361. X#ifdef TOTAL_WORKING
  362. X    static struct vmtotal total;
  363. X    int size;
  364. X
  365. X    /* get total -- systemwide main memory usage structure */
  366. X#ifdef KINFO_METER
  367. X    getkerninfo(KINFO_METER, &total, &size, 0);
  368. X#else
  369. X    (void) getkval(nlst[X_TOTAL].n_value, (int *)(&total), sizeof(total),
  370. X        nlst[X_TOTAL].n_name);
  371. X#endif
  372. X    /* convert memory stats to Kbytes */
  373. X    memory_stats[0] = -1;
  374. X    memory_stats[1] = pagetok(total.t_arm);
  375. X    memory_stats[2] = pagetok(total.t_rm);
  376. X    memory_stats[3] = -1;
  377. X    memory_stats[4] = pagetok(total.t_avm);
  378. X    memory_stats[5] = pagetok(total.t_vm);
  379. X    memory_stats[6] = -1;
  380. X    memory_stats[7] = pagetok(total.t_free);
  381. X#else
  382. X        static int free, active, inactive, wired;
  383. X
  384. X    (void) getkval(nlst[X_PG_FREE].n_value, (int *)(&free), sizeof(free),
  385. X                nlst[X_PG_FREE].n_name);
  386. X    (void) getkval(nlst[X_PG_ACTIVE].n_value, (int *)(&active), sizeof(active),
  387. X                nlst[X_PG_ACTIVE].n_name);
  388. X    (void) getkval(nlst[X_PG_INACTIVE].n_value, (int *)(&inactive), sizeof(inactive),
  389. X                nlst[X_PG_INACTIVE].n_name);
  390. X    (void) getkval(nlst[X_PG_WIRED].n_value, (int *)(&wired), sizeof(wired),
  391. X                nlst[X_PG_WIRED].n_name);
  392. X    memory_stats[0] = -1;
  393. X    memory_stats[1] = pagetok(free);
  394. X    memory_stats[2] = -1;
  395. X    memory_stats[3] = pagetok(active);
  396. X    memory_stats[4] = -1;
  397. X    memory_stats[5] = pagetok(inactive);
  398. X    memory_stats[6] = -1;
  399. X    memory_stats[7] = pagetok(wired);
  400. X#endif
  401. X    }
  402. X
  403. X    /* set arrays and strings */
  404. X    si->cpustates = cpu_states;
  405. X    si->memory = memory_stats;
  406. X    si->last_pid = -1;
  407. X}
  408. X
  409. Xstatic struct handle handle;
  410. X
  411. Xcaddr_t get_process_info(si, sel, compare)
  412. X
  413. Xstruct system_info *si;
  414. Xstruct process_select *sel;
  415. Xint (*compare)();
  416. X
  417. X{
  418. X    register int i;
  419. X    register int total_procs;
  420. X    register int active_procs;
  421. X    register KINFO **prefp;
  422. X    KINFO *pp;
  423. X    struct proc *pr;
  424. X    struct eproc *epr;
  425. X
  426. X    /* these are copied out of sel for speed */
  427. X    int show_idle;
  428. X    int show_system;
  429. X    int show_uid;
  430. X    int show_command;
  431. X
  432. X    
  433. X    nproc = kvm_getprocs(KINFO_PROC_ALL, 0);
  434. X    if (nproc > onproc)
  435. X    {
  436. X    pref = (KINFO **) realloc(pref, sizeof(KINFO *)
  437. X        * nproc);
  438. X        pbase = (KINFO *) realloc(pbase, sizeof(KINFO)
  439. X                * (nproc + 2));
  440. X        onproc = nproc;
  441. X    }
  442. X    if (pref == NULL || pbase == NULL) {
  443. X    (void) fprintf(stderr, "top: Out of memory.\n");
  444. X    quit(23);
  445. X    }
  446. X    /* get a pointer to the states summary array */
  447. X    si->procstates = process_states;
  448. X
  449. X    /* set up flags which define what we are going to select */
  450. X    show_idle = sel->idle;
  451. X    show_system = sel->system;
  452. X    show_uid = sel->uid != -1;
  453. X    show_command = sel->command != NULL;
  454. X
  455. X    /* count up process states and get pointers to interesting procs */
  456. X    total_procs = 0;
  457. X    active_procs = 0;
  458. X    memset((char *)process_states, 0, sizeof(process_states));
  459. X    prefp = pref;
  460. X    for (pp = pbase, i = 0; pr = kvm_nextproc(); pp++, i++)
  461. X    {
  462. X    /*
  463. X     *  Place pointers to each valid proc structure in pref[].
  464. X     *  Process slots that are actually in use have a non-zero
  465. X     *  status field.  Processes with SSYS set are system
  466. X     *  processes---these get ignored unless show_sysprocs is set.
  467. X     */
  468. X        epr = kvm_geteproc(pr);
  469. X        pp->ki_p = *pr;
  470. X        pp->ki_e = *epr;
  471. X    if (PP(pp, p_stat) != 0 &&
  472. X        (show_system || ((PP(pp, p_flag) & SSYS) == 0)))
  473. X    {
  474. X        total_procs++;
  475. X        process_states[PP(pp, p_stat)]++;
  476. X        if ((PP(pp, p_stat) != SZOMB) &&
  477. X        (show_idle || (PP(pp, p_pctcpu) != 0) || 
  478. X         (PP(pp, p_stat) == SRUN)) &&
  479. X        (!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t)sel->uid))
  480. X        {
  481. X        *prefp++ = pp;
  482. X        active_procs++;
  483. X        }
  484. X    }
  485. X    }
  486. X
  487. X    /* if requested, sort the "interesting" processes */
  488. X    if (compare != NULL)
  489. X    {
  490. X    qsort((char *)pref, active_procs, sizeof(KINFO *), compare);
  491. X    }
  492. X
  493. X    /* remember active and total counts */
  494. X    si->p_total = total_procs;
  495. X    si->p_active = pref_len = active_procs;
  496. X
  497. X    /* pass back a handle */
  498. X    handle.next_proc = pref;
  499. X    handle.remaining = active_procs;
  500. X#ifndef PATCHED_KVM
  501. X    kvm_freeprocs();
  502. X#endif
  503. X    return((caddr_t)&handle);
  504. X}
  505. X
  506. Xchar fmt[128];        /* static area where result is built */
  507. X
  508. Xchar *format_next_process(handle, get_userid)
  509. X
  510. Xcaddr_t handle;
  511. Xchar *(*get_userid)();
  512. X
  513. X{
  514. X    register KINFO *pp;
  515. X    register long cputime;
  516. X    register double pct;
  517. X    int where;
  518. X    struct handle *hp;
  519. X
  520. X    /* find and remember the next proc structure */
  521. X    hp = (struct handle *)handle;
  522. X    pp = *(hp->next_proc++);
  523. X    hp->remaining--;
  524. X    
  525. X
  526. X    /* get the process's user struct and set cputime */
  527. X    cputime = PP(pp, p_utime.tv_sec) + PP(pp, p_stime.tv_sec);
  528. X
  529. X    /* calculate the base for cpu percentages */
  530. X    pct = pctdouble(PP(pp, p_pctcpu));
  531. X
  532. X    /* format this entry */
  533. X    sprintf(fmt,
  534. X        Proc_format,
  535. X        PP(pp, p_pid),
  536. X        (*get_userid)(EP(pp, e_pcred.p_ruid)),
  537. X        PP(pp, p_pri) - PZERO,
  538. X        PP(pp, p_nice) - NZERO,
  539. X        pagetok(PROCSIZE(pp)),
  540. X#ifdef notyet
  541. X        pagetok(VP(pp, vm_rssize)),
  542. X#else
  543. X            pagetok(pp->ki_e.e_vm.vm_pmap.pm_stats.resident_count),
  544. X#endif
  545. X        state_abbrev[PP(pp, p_stat)],
  546. X        cputime / 60l,
  547. X        cputime % 60l,
  548. X        100.0 * weighted_cpu(pct, pp),
  549. X        100.0 * pct,
  550. X        printable(PP(pp, p_comm)));
  551. X
  552. X    /* return the result */
  553. X    return(fmt);
  554. X}
  555. X
  556. X
  557. X/*
  558. X * check_nlist(nlst) - checks the nlist to see if any symbols were not
  559. X *        found.  For every symbol that was not found, a one-line
  560. X *        message is printed to stderr.  The routine returns the
  561. X *        number of symbols NOT found.
  562. X */
  563. X
  564. Xint check_nlist(nlst)
  565. X
  566. Xregister struct nlist *nlst;
  567. X
  568. X{
  569. X    register int i;
  570. X
  571. X    /* check to see if we got ALL the symbols we requested */
  572. X    /* this will write one line to stderr for every symbol not found */
  573. X
  574. X    i = 0;
  575. X    while (nlst->n_name != NULL)
  576. X    {
  577. X    if (nlst->n_type == 0)
  578. X    {
  579. X        /* this one wasn't found */
  580. X        fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
  581. X        i = 1;
  582. X    }
  583. X    nlst++;
  584. X    }
  585. X
  586. X    return(i);
  587. X}
  588. X
  589. X
  590. X/*
  591. X *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
  592. X *    "offset" is the byte offset into the kernel for the desired value,
  593. X *      "ptr" points to a buffer into which the value is retrieved,
  594. X *      "size" is the size of the buffer (and the object to retrieve),
  595. X *      "refstr" is a reference string used when printing error meessages,
  596. X *        if "refstr" starts with a '!', then a failure on read will not
  597. X *          be fatal (this may seem like a silly way to do things, but I
  598. X *          really didn't want the overhead of another argument).
  599. X *      
  600. X */
  601. X
  602. Xgetkval(offset, ptr, size, refstr)
  603. X
  604. Xunsigned long offset;
  605. Xint *ptr;
  606. Xint size;
  607. Xchar *refstr;
  608. X
  609. X{
  610. X    if (kvm_read((void *) offset, (void *) ptr, size) != size)
  611. X    {
  612. X    if (*refstr == '!')
  613. X    {
  614. X        return(0);
  615. X    }
  616. X    else
  617. X    {
  618. X        fprintf(stderr, "top: kvm_read for %s: %s\n",
  619. X        refstr, strerror(errno));
  620. X        quit(23);
  621. X    }
  622. X    }
  623. X    return(1);
  624. X}
  625. X    
  626. X/* comparison routine for qsort */
  627. X
  628. X/*
  629. X *  proc_compare - comparison function for "qsort"
  630. X *    Compares the resource consumption of two processes using five
  631. X *      distinct keys.  The keys (in descending order of importance) are:
  632. X *      percent cpu, cpu ticks, state, resident set size, total virtual
  633. X *      memory usage.  The process states are ordered as follows (from least
  634. X *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
  635. X *      array declaration below maps a process state index into a number
  636. X *      that reflects this ordering.
  637. X */
  638. X
  639. Xstatic unsigned char sorted_state[] =
  640. X{
  641. X    0,    /* not used        */
  642. X    3,    /* sleep        */
  643. X    1,    /* ABANDONED (WAIT)    */
  644. X    6,    /* run            */
  645. X    5,    /* start        */
  646. X    2,    /* zombie        */
  647. X    4    /* stop            */
  648. X};
  649. Xproc_compare(pp1, pp2)
  650. X
  651. XKINFO **pp1;
  652. XKINFO **pp2;
  653. X
  654. X{
  655. X    register KINFO *p1;
  656. X    register KINFO *p2;
  657. X    register int result;
  658. X    register pctcpu lresult;
  659. X
  660. X    /* remove one level of indirection */
  661. X    p1 = *pp1;
  662. X    p2 = *pp2;
  663. X
  664. X    /* compare percent cpu (pctcpu) */
  665. X    if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0)
  666. X    {
  667. X    /* use cpticks to break the tie */
  668. X    if ((result = PP(p2, p_cpticks) - PP(p1, p_cpticks)) == 0)
  669. X    {
  670. X        /* use process state to break the tie */
  671. X        if ((result = sorted_state[PP(p2, p_stat)] -
  672. X              sorted_state[PP(p1, p_stat)])  == 0)
  673. X        {
  674. X        /* use priority to break the tie */
  675. X        if ((result = PP(p2, p_pri) - PP(p1, p_pri)) == 0)
  676. X        {
  677. X            /* use resident set size (rssize) to break the tie */
  678. X            if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
  679. X            {
  680. X            /* use total memory to break the tie */
  681. X            result = PROCSIZE(p2) - PROCSIZE(p1);
  682. X            }
  683. X        }
  684. X        }
  685. X    }
  686. X    }
  687. X    else
  688. X    {
  689. X    result = lresult < 0 ? -1 : 1;
  690. X    }
  691. X
  692. X    return(result);
  693. X}
  694. X
  695. X/*
  696. X * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
  697. X *        the process does not exist.
  698. X *        It is EXTREMLY IMPORTANT that this function work correctly.
  699. X *        If top runs setuid root (as in SVR4), then this function
  700. X *        is the only thing that stands in the way of a serious
  701. X *        security problem.  It validates requests for the "kill"
  702. X *        and "renice" commands.
  703. X */
  704. X
  705. Xint proc_owner(pid)
  706. X
  707. Xint pid;
  708. X
  709. X{
  710. X    register int cnt;
  711. X    register KINFO **prefp;
  712. X    register KINFO *pp;
  713. X
  714. X    prefp = pref;
  715. X    cnt = pref_len;
  716. X    while (--cnt >= 0)
  717. X    {
  718. X    pp = *prefp++;
  719. X    if (PP(pp, p_pid) == (pid_t)pid)
  720. X    {
  721. X        return((int)EP(pp, e_pcred.p_ruid));
  722. X    }
  723. X    }
  724. X    return(-1);
  725. X}
  726. END_OF_FILE
  727. if test 17022 -ne `wc -c <'machine/m_386bsd.c'`; then
  728.     echo shar: \"'machine/m_386bsd.c'\" unpacked with wrong size!
  729. fi
  730. # end of 'machine/m_386bsd.c'
  731. fi
  732. if test -f 'machine/m_bsd386.c' -a "${1}" != "-c" ; then 
  733.   echo shar: Will not clobber existing file \"'machine/m_bsd386.c'\"
  734. else
  735. echo shar: Extracting \"'machine/m_bsd386.c'\" \(16548 characters\)
  736. sed "s/^X//" >'machine/m_bsd386.c' <<'END_OF_FILE'
  737. X/*
  738. X * top - a top users display for Unix
  739. X *
  740. X * SYNOPSIS:  For a BSD/386 system
  741. X *          Note memory statistic and process sizes could be wrong,
  742. X *          but ps gets them wrong too...
  743. X *
  744. X * DESCRIPTION:
  745. X * This is the machine-dependent module for BSD/386
  746. X * Works for:
  747. X *    hp300
  748. X *    i386
  749. X *
  750. X * LIBS: -lkvm
  751. X *
  752. X * AUTHOR:  Christos Zoulas <christos@ee.cornell.edu>
  753. X */
  754. X
  755. X#include <sys/types.h>
  756. X#include <sys/signal.h>
  757. X#include <sys/param.h>
  758. X
  759. X#include <stdio.h>
  760. X#include <nlist.h>
  761. X#include <math.h>
  762. X#ifdef __bsdi__
  763. X#include <sys/time.h>
  764. X#include <sys/proc.h>
  765. X#include <sys/vmmeter.h>
  766. X#endif
  767. X#include <kvm.h>
  768. X#include <sys/errno.h>
  769. X#include <sys/kinfo.h>
  770. X#include <sys/kinfo_proc.h>
  771. X#ifdef notyet
  772. X#define time __time
  773. X#define hz __hz
  774. X#include <sys/kernel.h>
  775. X#undef time
  776. X#undef hz
  777. X#endif
  778. X#include <sys/dir.h>
  779. X#ifdef __bsdi__
  780. X#include <sys/cpustats.h>
  781. X#include <sys/sysinfo.h>
  782. X#else
  783. X#include <sys/dkstat.h>
  784. X#endif
  785. X#include <sys/file.h>
  786. X#include <sys/time.h>
  787. X
  788. X
  789. X#define DOSWAP
  790. X
  791. X#include "top.h"
  792. X#include "machine.h"
  793. X
  794. X#ifdef __bsdi__
  795. X#define    VMUNIX    "/bsd"
  796. X#else
  797. X#define VMUNIX    "/vmunix"
  798. X#endif
  799. X#define KMEM    "/dev/kmem"
  800. X#define MEM    "/dev/mem"
  801. X#ifdef DOSWAP
  802. X#define SWAP    "/dev/drum"
  803. X#endif
  804. X
  805. X/* get_process_info passes back a handle.  This is what it looks like: */
  806. X
  807. Xstruct handle
  808. X{
  809. X    struct kinfo_proc **next_proc;    /* points to next valid proc pointer */
  810. X    int remaining;        /* number of pointers remaining */
  811. X};
  812. X
  813. X/* declarations for load_avg */
  814. X#include "loadavg.h"
  815. X
  816. X#define PP(pp, field) ((pp)->kp_proc . field)
  817. X#define EP(pp, field) ((pp)->kp_eproc . field)
  818. X#define VP(pp, field) ((pp)->kp_eproc.e_vm . field)
  819. X
  820. X/* define what weighted cpu is.  */
  821. X#define weighted_cpu(pct, pp) (PP((pp), p_time) == 0 ? 0.0 : \
  822. X             ((pct) / (1.0 - exp(PP((pp), p_time) * logcpu))))
  823. X
  824. X/* what we consider to be process size: */
  825. X#define PROCSIZE(pp) (VP((pp), vm_tsize) \
  826. X              + VP((pp), vm_dsize) \
  827. X              + VP((pp), vm_ssize))
  828. X
  829. X/* definitions for indices in the nlist array */
  830. X#define X_CCPU        0
  831. X#ifdef __bsdi__
  832. X#define X_TOTAL    1
  833. X#else
  834. X#define X_CP_TIME    1
  835. X#endif
  836. X#define X_HZ        2
  837. X#define X_AVENRUN    3
  838. X
  839. Xstatic struct nlist nlst[] = {
  840. X    { "_ccpu" },        /* 0 */
  841. X#ifdef __bsdi__
  842. X    { "_total" },        /* 1 */
  843. X#else
  844. X    { "_cp_time" },        /* 1 */
  845. X#endif
  846. X    { "_hz" },            /* 2 */
  847. X    { "_averunnable" },        /* 3 */
  848. X    { 0 }
  849. X};
  850. X
  851. X/*
  852. X *  These definitions control the format of the per-process area
  853. X */
  854. X
  855. Xstatic char header[] =
  856. X  "  PID X        PRI NICE   SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
  857. X/* 0123456   -- field to fill in starts at header+6 */
  858. X#define UNAME_START 6
  859. X
  860. X#define Proc_format \
  861. X    "%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %5.2f%% %5.2f%% %.14s"
  862. X
  863. X
  864. X/* process state names for the "STATE" column of the display */
  865. X/* the extra nulls in the string "run" are for adding a slash and
  866. X   the processor number when needed */
  867. X
  868. Xstatic char *state_abbrev[] =
  869. X{
  870. X    "", "sleep", "WAIT", "run\0\0\0", "start", "zomb", "stop"
  871. X};
  872. X
  873. X
  874. Xstatic kvm_t *kd;
  875. X
  876. X/* values that we stash away in _init and use in later routines */
  877. X
  878. Xstatic double logcpu;
  879. X
  880. X/* these are retrieved from the kernel in _init */
  881. X
  882. Xstatic long    hz;
  883. Xstatic load_avg    ccpu;
  884. Xstatic int    ncpu = 0;
  885. X
  886. X/* these are offsets obtained via nlist and used in the get_ functions */
  887. X
  888. X#ifdef __bsdi__
  889. Xstatic unsigned long total_offset;
  890. X#else
  891. Xstatic unsigned long cp_time_offset;
  892. X#endif
  893. Xstatic unsigned long avenrun_offset;
  894. X
  895. X#ifndef __bsdi__
  896. X/* these are for calculating cpu state percentages */
  897. X
  898. Xstatic u_long cp_time[CPUSTATES];
  899. Xstatic u_long cp_old[CPUSTATES];
  900. Xstatic u_long cp_diff[CPUSTATES];
  901. X#endif
  902. X
  903. X/* these are for detailing the process states */
  904. X
  905. Xstatic int process_states[7];
  906. Xstatic char *procstatenames[] = {
  907. X    "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
  908. X    " zombie, ", " stopped, ",
  909. X    NULL
  910. X};
  911. X
  912. X/* these are for detailing the cpu states */
  913. X
  914. Xstatic int cpu_states[CPUSTATES];
  915. Xstatic char *cpustatenames[CPUSTATES+1] = {
  916. X    "user", "nice", "system", "idle", NULL
  917. X};
  918. X
  919. X/* these are for detailing the memory statistics */
  920. X
  921. Xstatic int memory_stats[8];
  922. Xstatic char *memorynames[] = {
  923. X    "Real: ", "K/", "K ", "Virt: ", "K/",
  924. X    "K ", "Free: ", "K", NULL
  925. X};
  926. X
  927. X/* these are for keeping track of the proc array */
  928. X
  929. Xstatic int bytes;
  930. Xstatic int nproc;
  931. Xstatic int onproc = -1;
  932. Xstatic int pref_len;
  933. Xstatic struct kinfo_proc *pbase;
  934. Xstatic struct kinfo_proc **pref;
  935. X
  936. X/* these are for getting the memory statistics */
  937. X
  938. Xstatic int pageshift;        /* log base 2 of the pagesize */
  939. X
  940. X/* define pagetok in terms of pageshift */
  941. X
  942. X#define pagetok(size) ((size) << pageshift)
  943. X
  944. X/* useful externals */
  945. Xlong percentages();
  946. X
  947. Xmachine_init(statics)
  948. X
  949. Xstruct statics *statics;
  950. X
  951. X{
  952. X    register int i = 0;
  953. X    register int pagesize;
  954. X
  955. X    if ((kd = kvm_open(VMUNIX, MEM, SWAP, O_RDONLY, "kvm_open")) == NULL)
  956. X    return -1;
  957. X
  958. X
  959. X    /* get the list of symbols we want to access in the kernel */
  960. X    (void) kvm_nlist(kd, nlst);
  961. X    if (nlst[0].n_type == 0)
  962. X    {
  963. X    fprintf(stderr, "top: nlist failed\n");
  964. X    return(-1);
  965. X    }
  966. X
  967. X    /* make sure they were all found */
  968. X    if (i > 0 && check_nlist(nlst) > 0)
  969. X    {
  970. X    return(-1);
  971. X    }
  972. X
  973. X    /* get the symbol values out of kmem */
  974. X    (void) getkval(nlst[X_HZ].n_value,     (int *)(&hz),    sizeof(hz),
  975. X        nlst[X_HZ].n_name);
  976. X    (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),    sizeof(ccpu),
  977. X        nlst[X_CCPU].n_name);
  978. X
  979. X    /* stash away certain offsets for later use */
  980. X#ifdef __bsdi__
  981. X    total_offset = nlst[X_TOTAL].n_value;
  982. X#else
  983. X    cp_time_offset = nlst[X_CP_TIME].n_value;
  984. X#endif
  985. X    avenrun_offset = nlst[X_AVENRUN].n_value;
  986. X
  987. X    /* this is used in calculating WCPU -- calculate it ahead of time */
  988. X    logcpu = log(loaddouble(ccpu));
  989. X
  990. X    pbase = NULL;
  991. X    pref = NULL;
  992. X    nproc = 0;
  993. X    onproc = -1;
  994. X    /* get the page size with "getpagesize" and calculate pageshift from it */
  995. X    pagesize = getpagesize();
  996. X    pageshift = 0;
  997. X    while (pagesize > 1)
  998. X    {
  999. X    pageshift++;
  1000. X    pagesize >>= 1;
  1001. X    }
  1002. X
  1003. X    /* we only need the amount of log(2)1024 for our conversion */
  1004. X    pageshift -= LOG1024;
  1005. X
  1006. X    /* fill in the statics information */
  1007. X    statics->procstate_names = procstatenames;
  1008. X    statics->cpustate_names = cpustatenames;
  1009. X    statics->memory_names = memorynames;
  1010. X
  1011. X    /* all done! */
  1012. X    return(0);
  1013. X}
  1014. X
  1015. Xchar *format_header(uname_field)
  1016. X
  1017. Xregister char *uname_field;
  1018. X
  1019. X{
  1020. X    register char *ptr;
  1021. X
  1022. X    ptr = header + UNAME_START;
  1023. X    while (*uname_field != '\0')
  1024. X    {
  1025. X    *ptr++ = *uname_field++;
  1026. X    }
  1027. X
  1028. X    return(header);
  1029. X}
  1030. X
  1031. Xget_system_info(si)
  1032. X
  1033. Xstruct system_info *si;
  1034. X
  1035. X{
  1036. X    register u_long total;
  1037. X    load_avg avenrun[3];
  1038. X#ifdef __bsdi__
  1039. X    struct cpustats cpu;
  1040. X    struct sysinfo sys;
  1041. X    int size;
  1042. X#else
  1043. X    load_avg *avenrunp = avenrun;
  1044. X#endif
  1045. X
  1046. X    /* get the various high-level data structures */
  1047. X#ifdef __bsdi__
  1048. X    size = sizeof(struct cpustats);
  1049. X    if (getkerninfo(KINFO_CPU, &cpu, &size, 0) < 0) {
  1050. X    perror("getkerninfo#1");
  1051. X    abort();
  1052. X    }
  1053. X#ifdef notyet
  1054. X    size = sizeof(struct sysinfo);
  1055. X    if (getkerninfo(KINFO_SYSINFO, &sys, &size, 0) < 0) {
  1056. X    perror("getkerninfo#2");
  1057. X    abort();
  1058. X    }
  1059. X#endif /*notyet*/
  1060. X#else
  1061. X    (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
  1062. X           "_cp_time");
  1063. X    (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
  1064. X           "_avenrun");
  1065. X#endif
  1066. X
  1067. X    /* convert load averages to doubles */
  1068. X    {
  1069. X    register int i;
  1070. X    register double *infoloadp = si->load_avg;
  1071. X
  1072. X    for (i = 0; i < CPUSTATES; i++)
  1073. X    {
  1074. X#ifdef __bsdi__
  1075. X        *infoloadp++ = ((double) cpu.cp_averunnable[i]) / FSCALE;
  1076. X#else
  1077. X        *infoloadp++ = loaddouble(*avenrunp++);
  1078. X#endif
  1079. X    }
  1080. X    }
  1081. X
  1082. X    /* convert cp_time counts to percentages */
  1083. X#ifdef __bsdi__
  1084. X    {
  1085. X    register int i;
  1086. X    register double total, pct;
  1087. X
  1088. X    total = 0.0;
  1089. X    for (i = 0; i < CPUSTATES; i++)
  1090. X        total += (double) cpu.cp_time[i];
  1091. X    if (total == 0)
  1092. X        pct = 0;
  1093. X    else
  1094. X        pct = 100 / total;
  1095. X    for (i = 0; i < CPUSTATES; i++)
  1096. X        cpu_states[i] = 10.0 * ((double)cpu.cp_time[i]) * pct;
  1097. X    }
  1098. X#else
  1099. X    total = percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
  1100. X#endif
  1101. X
  1102. X    /* sum memory statistics */
  1103. X    {
  1104. X    struct vmtotal total;
  1105. X    int size;
  1106. X
  1107. X#ifdef __bsdi__
  1108. X    (void) getkval(total_offset, (int*)&total, sizeof(total),
  1109. X               "_total");
  1110. X#else
  1111. X    /* get total -- systemwide main memory usage structure */
  1112. X    size = sizeof(struct vmtotal);
  1113. X    getkerninfo(KINFO_METER, &total, &size, 0);
  1114. X#endif
  1115. X    /* convert memory stats to Kbytes */
  1116. X    memory_stats[0] = -1;
  1117. X    memory_stats[1] = pagetok(total.t_arm);
  1118. X    memory_stats[2] = pagetok(total.t_rm);
  1119. X    memory_stats[3] = -1;
  1120. X    memory_stats[4] = pagetok(total.t_avm);
  1121. X    memory_stats[5] = pagetok(total.t_vm);
  1122. X    memory_stats[6] = -1;
  1123. X    memory_stats[7] = pagetok(total.t_free);
  1124. X    }
  1125. X
  1126. X    /* set arrays and strings */
  1127. X    si->cpustates = cpu_states;
  1128. X    si->memory = memory_stats;
  1129. X    si->last_pid = -1;
  1130. X}
  1131. X
  1132. Xstatic struct handle handle;
  1133. X
  1134. Xcaddr_t get_process_info(si, sel, compare)
  1135. X
  1136. Xstruct system_info *si;
  1137. Xstruct process_select *sel;
  1138. Xint (*compare)();
  1139. X
  1140. X{
  1141. X    register int i;
  1142. X    register int total_procs;
  1143. X    register int active_procs;
  1144. X    register struct kinfo_proc **prefp;
  1145. X    register struct kinfo_proc *pp;
  1146. X
  1147. X    /* these are copied out of sel for speed */
  1148. X    int show_idle;
  1149. X    int show_system;
  1150. X    int show_uid;
  1151. X    int show_command;
  1152. X
  1153. X    
  1154. X    pbase = kvm_getprocs(kd, KINFO_PROC_ALL, 0, &nproc);
  1155. X    if (nproc > onproc)
  1156. X    pref = (struct kinfo_proc **) realloc(pref, sizeof(struct kinfo_proc *)
  1157. X        * (onproc = nproc));
  1158. X    if (pref == NULL || pbase == NULL) {
  1159. X    (void) fprintf(stderr, "top: Out of memory.\n");
  1160. X    quit(23);
  1161. X    }
  1162. X    /* get a pointer to the states summary array */
  1163. X    si->procstates = process_states;
  1164. X
  1165. X    /* set up flags which define what we are going to select */
  1166. X    show_idle = sel->idle;
  1167. X    show_system = sel->system;
  1168. X    show_uid = sel->uid != -1;
  1169. X    show_command = sel->command != NULL;
  1170. X
  1171. X    /* count up process states and get pointers to interesting procs */
  1172. X    total_procs = 0;
  1173. X    active_procs = 0;
  1174. X    memset((char *)process_states, 0, sizeof(process_states));
  1175. X    prefp = pref;
  1176. X    for (pp = pbase, i = 0; i < nproc; pp++, i++)
  1177. X    {
  1178. X    /*
  1179. X     *  Place pointers to each valid proc structure in pref[].
  1180. X     *  Process slots that are actually in use have a non-zero
  1181. X     *  status field.  Processes with SSYS set are system
  1182. X     *  processes---these get ignored unless show_sysprocs is set.
  1183. X     */
  1184. X    if (PP(pp, p_stat) != 0 &&
  1185. X        (show_system || ((PP(pp, p_flag) & SSYS) == 0)))
  1186. X    {
  1187. X        int p_stat = PP(pp, p_stat);
  1188. X
  1189. X        total_procs++;
  1190. X        if (p_stat < 1 || p_stat > 6)
  1191. X        abort();
  1192. X        process_states[p_stat]++;
  1193. X        if ((PP(pp, p_stat) != SZOMB) &&
  1194. X        (show_idle || (PP(pp, p_pctcpu) != 0) || 
  1195. X         (PP(pp, p_stat) == SRUN)) &&
  1196. X        (!show_uid || EP(pp, e_pcred.p_ruid) == (uid_t)sel->uid))
  1197. X        {
  1198. X        *prefp++ = pp;
  1199. X        active_procs++;
  1200. X        }
  1201. X    }
  1202. X    }
  1203. X
  1204. X    /* if requested, sort the "interesting" processes */
  1205. X    if (compare != NULL)
  1206. X    {
  1207. X    qsort((char *)pref, active_procs, sizeof(struct kinfo_proc *), compare);
  1208. X    }
  1209. X
  1210. X    /* remember active and total counts */
  1211. X    si->p_total = total_procs;
  1212. X    si->p_active = pref_len = active_procs;
  1213. X
  1214. X    /* pass back a handle */
  1215. X    handle.next_proc = pref;
  1216. X    handle.remaining = active_procs;
  1217. X    return((caddr_t)&handle);
  1218. X}
  1219. X
  1220. Xchar fmt[128];        /* static area where result is built */
  1221. X
  1222. Xchar *format_next_process(handle, get_userid)
  1223. X
  1224. Xcaddr_t handle;
  1225. Xchar *(*get_userid)();
  1226. X
  1227. X{
  1228. X    register struct kinfo_proc *pp;
  1229. X    register long cputime;
  1230. X    register double pct;
  1231. X    int where;
  1232. X    struct handle *hp;
  1233. X
  1234. X    /* find and remember the next proc structure */
  1235. X    hp = (struct handle *)handle;
  1236. X    pp = *(hp->next_proc++);
  1237. X    hp->remaining--;
  1238. X    
  1239. X
  1240. X    /* get the process's user struct and set cputime */
  1241. X    if ((PP(pp, p_flag) & SLOAD) == 0) {
  1242. X    /*
  1243. X     * Print swapped processes as <pname>
  1244. X     */
  1245. X    char *comm = PP(pp, p_comm);
  1246. X#define COMSIZ sizeof(PP(pp, p_comm))
  1247. X    char buf[COMSIZ];
  1248. X    (void) strncpy(buf, comm, COMSIZ);
  1249. X    comm[0] = '<';
  1250. X    (void) strncpy(&comm[1], buf, COMSIZ - 2);
  1251. X    comm[COMSIZ - 2] = '\0';
  1252. X    (void) strncat(comm, ">", COMSIZ - 1);
  1253. X    comm[COMSIZ - 1] = '\0';
  1254. X    }
  1255. X
  1256. X    cputime = PP(pp, p_utime.tv_sec) + PP(pp, p_stime.tv_sec);
  1257. X
  1258. X    /* calculate the base for cpu percentages */
  1259. X    pct = pctdouble(PP(pp, p_pctcpu));
  1260. X
  1261. X    /* format this entry */
  1262. X    sprintf(fmt,
  1263. X        Proc_format,
  1264. X        PP(pp, p_pid),
  1265. X        (*get_userid)(EP(pp, e_pcred.p_ruid)),
  1266. X        PP(pp, p_pri) - PZERO,
  1267. X        PP(pp, p_nice) - NZERO,
  1268. X        pagetok(PROCSIZE(pp)),
  1269. X        pagetok(VP(pp, vm_rssize)),
  1270. X        state_abbrev[PP(pp, p_stat)],
  1271. X        cputime / 60l,
  1272. X        cputime % 60l,
  1273. X        100.0 * weighted_cpu(pct, pp),
  1274. X        100.0 * pct,
  1275. X        printable(PP(pp, p_comm)));
  1276. X
  1277. X    /* return the result */
  1278. X    return(fmt);
  1279. X}
  1280. X
  1281. X
  1282. X/*
  1283. X * check_nlist(nlst) - checks the nlist to see if any symbols were not
  1284. X *        found.  For every symbol that was not found, a one-line
  1285. X *        message is printed to stderr.  The routine returns the
  1286. X *        number of symbols NOT found.
  1287. X */
  1288. X
  1289. Xint check_nlist(nlst)
  1290. X
  1291. Xregister struct nlist *nlst;
  1292. X
  1293. X{
  1294. X    register int i;
  1295. X
  1296. X    /* check to see if we got ALL the symbols we requested */
  1297. X    /* this will write one line to stderr for every symbol not found */
  1298. X
  1299. X    i = 0;
  1300. X    while (nlst->n_name != NULL)
  1301. X    {
  1302. X    if (nlst->n_type == 0)
  1303. X    {
  1304. X        /* this one wasn't found */
  1305. X        fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
  1306. X        i = 1;
  1307. X    }
  1308. X    nlst++;
  1309. X    }
  1310. X
  1311. X    return(i);
  1312. X}
  1313. X
  1314. X
  1315. X/*
  1316. X *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
  1317. X *    "offset" is the byte offset into the kernel for the desired value,
  1318. X *      "ptr" points to a buffer into which the value is retrieved,
  1319. X *      "size" is the size of the buffer (and the object to retrieve),
  1320. X *      "refstr" is a reference string used when printing error meessages,
  1321. X *        if "refstr" starts with a '!', then a failure on read will not
  1322. X *          be fatal (this may seem like a silly way to do things, but I
  1323. X *          really didn't want the overhead of another argument).
  1324. X *      
  1325. X */
  1326. X
  1327. Xgetkval(offset, ptr, size, refstr)
  1328. X
  1329. Xunsigned long offset;
  1330. Xint *ptr;
  1331. Xint size;
  1332. Xchar *refstr;
  1333. X
  1334. X{
  1335. X    if (kvm_read(kd, offset, (char *) ptr, size) != size)
  1336. X    {
  1337. X    if (*refstr == '!')
  1338. X    {
  1339. X        return(0);
  1340. X    }
  1341. X    else
  1342. X    {
  1343. X        fprintf(stderr, "top: kvm_read for %s: %s\n",
  1344. X        refstr, strerror(errno));
  1345. X        quit(23);
  1346. X    }
  1347. X    }
  1348. X    return(1);
  1349. X}
  1350. X    
  1351. X/* comparison routine for qsort */
  1352. X
  1353. X/*
  1354. X *  proc_compare - comparison function for "qsort"
  1355. X *    Compares the resource consumption of two processes using five
  1356. X *      distinct keys.  The keys (in descending order of importance) are:
  1357. X *      percent cpu, cpu ticks, state, resident set size, total virtual
  1358. X *      memory usage.  The process states are ordered as follows (from least
  1359. X *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
  1360. X *      array declaration below maps a process state index into a number
  1361. X *      that reflects this ordering.
  1362. X */
  1363. X
  1364. Xstatic unsigned char sorted_state[] =
  1365. X{
  1366. X    0,    /* not used        */
  1367. X    3,    /* sleep        */
  1368. X    1,    /* ABANDONED (WAIT)    */
  1369. X    6,    /* run            */
  1370. X    5,    /* start        */
  1371. X    2,    /* zombie        */
  1372. X    4    /* stop            */
  1373. X};
  1374. Xproc_compare(pp1, pp2)
  1375. X
  1376. Xstruct kinfo_proc **pp1;
  1377. Xstruct kinfo_proc **pp2;
  1378. X
  1379. X{
  1380. X    register struct kinfo_proc *p1;
  1381. X    register struct kinfo_proc *p2;
  1382. X    register int result;
  1383. X    register pctcpu lresult;
  1384. X
  1385. X    /* remove one level of indirection */
  1386. X    p1 = *pp1;
  1387. X    p2 = *pp2;
  1388. X
  1389. X    /* compare percent cpu (pctcpu) */
  1390. X    if ((lresult = PP(p2, p_pctcpu) - PP(p1, p_pctcpu)) == 0)
  1391. X    {
  1392. X    /* use cpticks to break the tie */
  1393. X    if ((result = PP(p2, p_cpticks) - PP(p1, p_cpticks)) == 0)
  1394. X    {
  1395. X        /* use process state to break the tie */
  1396. X        if ((result = sorted_state[PP(p2, p_stat)] -
  1397. X              sorted_state[PP(p1, p_stat)])  == 0)
  1398. X        {
  1399. X        /* use priority to break the tie */
  1400. X        if ((result = PP(p2, p_pri) - PP(p1, p_pri)) == 0)
  1401. X        {
  1402. X            /* use resident set size (rssize) to break the tie */
  1403. X            if ((result = VP(p2, vm_rssize) - VP(p1, vm_rssize)) == 0)
  1404. X            {
  1405. X            /* use total memory to break the tie */
  1406. X            result = PROCSIZE(p2) - PROCSIZE(p1);
  1407. X            }
  1408. X        }
  1409. X        }
  1410. X    }
  1411. X    }
  1412. X    else
  1413. X    {
  1414. X    result = lresult < 0 ? -1 : 1;
  1415. X    }
  1416. X
  1417. X    return(result);
  1418. X}
  1419. X
  1420. X/*
  1421. X * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
  1422. X *        the process does not exist.
  1423. X *        It is EXTREMLY IMPORTANT that this function work correctly.
  1424. X *        If top runs setuid root (as in SVR4), then this function
  1425. X *        is the only thing that stands in the way of a serious
  1426. X *        security problem.  It validates requests for the "kill"
  1427. X *        and "renice" commands.
  1428. X */
  1429. X
  1430. Xint proc_owner(pid)
  1431. X
  1432. Xint pid;
  1433. X
  1434. X{
  1435. X    register int cnt;
  1436. X    register struct kinfo_proc **prefp;
  1437. X    register struct kinfo_proc *pp;
  1438. X
  1439. X    prefp = pref;
  1440. X    cnt = pref_len;
  1441. X    while (--cnt >= 0)
  1442. X    {
  1443. X    pp = *prefp++;    
  1444. X    if (PP(pp, p_pid) == (pid_t)pid)
  1445. X    {
  1446. X        return((int)EP(pp, e_pcred.p_ruid));
  1447. X    }
  1448. X    }
  1449. X    return(-1);
  1450. X}
  1451. END_OF_FILE
  1452. if test 16548 -ne `wc -c <'machine/m_bsd386.c'`; then
  1453.     echo shar: \"'machine/m_bsd386.c'\" unpacked with wrong size!
  1454. fi
  1455. # end of 'machine/m_bsd386.c'
  1456. fi
  1457. if test -f 'machine/m_dynix.c' -a "${1}" != "-c" ; then 
  1458.   echo shar: Will not clobber existing file \"'machine/m_dynix.c'\"
  1459. else
  1460. echo shar: Extracting \"'machine/m_dynix.c'\" \(17507 characters\)
  1461. sed "s/^X//" >'machine/m_dynix.c' <<'END_OF_FILE'
  1462. X/*
  1463. X * top - a top users display for Unix
  1464. X *
  1465. X * SYNOPSIS:  any Sequent Running Dynix 3.0.x
  1466. X *
  1467. X * DESCRIPTION:
  1468. X * This is the machine-dependent module for Sequent Dynix 3
  1469. X * This makes top work on the following systems:
  1470. X *    Sequent Semmetry, Dynix 3.0.12
  1471. X *    Sequent Balance,  Dynix 3.0.4
  1472. X *
  1473. X * AUTHOR:  Daniel Trinkle <trinkle@cs.purdue.edu>
  1474. X */
  1475. X
  1476. X#include <sys/types.h>
  1477. X#include <sys/signal.h>
  1478. X#include <sys/param.h>
  1479. X
  1480. X#include <stdio.h>
  1481. X#include <nlist.h>
  1482. X#include <math.h>
  1483. X#include <sys/dir.h>
  1484. X#include <sys/user.h>
  1485. X#include <sys/proc.h>
  1486. X#include <sys/dk.h>
  1487. X#include <sys/vm.h>
  1488. X#include <machine/pte.h>
  1489. X#include <machine/plocal.h>
  1490. X#include <machine/engine.h>
  1491. X#include <sys/file.h>
  1492. X
  1493. X#include "top.h"
  1494. X#include "machine.h"
  1495. X
  1496. X#ifndef uid_t
  1497. X/* some early versions of DYNIX don't have uid_t */
  1498. X#define uid_t int
  1499. X#endif
  1500. X
  1501. Xstruct engine *engine;
  1502. Xstruct engine *pengine;
  1503. Xstruct plocal **pplocal;
  1504. Xint Nengine;
  1505. X
  1506. X/* get_process_info passes back a handle.  This is what it looks like: */
  1507. X
  1508. Xstruct handle
  1509. X{
  1510. X    struct proc **next_proc;    /* points to next valid proc pointer */
  1511. X    int remaining;        /* number of pointers remaining */
  1512. X};
  1513. X
  1514. X/* declarations for load_avg */
  1515. Xtypedef long load_avg;
  1516. Xtypedef long pctcpu;
  1517. X#define loaddouble(la) ((double)(la) / FSCALE)
  1518. X#define intload(i) ((int)((i) * FSCALE))
  1519. X#define pctdouble(p) ((double)(p) / FSCALE)
  1520. X
  1521. X/* define what weighted cpu is.  */
  1522. X#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
  1523. X             ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
  1524. X
  1525. X/* what we consider to be process size: */
  1526. X#define PROCSIZE(pp) ((pp)->p_dsize + (pp)->p_ssize)
  1527. X
  1528. X/* definitions for indices in the nlist array */
  1529. X#define X_AVENRUN    0
  1530. X#define X_CCPU        1
  1531. X#define X_MPID        2
  1532. X#define X_NPROC        3
  1533. X#define X_PROC        4
  1534. X#define X_TOTAL        5
  1535. X#define X_ENGINE    6
  1536. X#define X_NENGINE    7
  1537. X
  1538. Xstatic struct nlist nlst[] = {
  1539. X    { "_avenrun" },        /* 0 */
  1540. X    { "_ccpu" },        /* 1 */
  1541. X    { "_mpid" },        /* 2 */
  1542. X    { "_nproc" },        /* 3 */
  1543. X    { "_proc" },        /* 4 */
  1544. X    { "_total" },        /* 5 */
  1545. X    { "_engine" },        /* 6 */
  1546. X    { "_Nengine" },        /* 7 */
  1547. X    { 0 }
  1548. X};
  1549. X
  1550. X/*
  1551. X *  These definitions control the format of the per-process area
  1552. X */
  1553. X
  1554. Xstatic char header[] =
  1555. X  "  PID X        PRI NICE   SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
  1556. X/* 0123456   -- field to fill in starts at header+6 */
  1557. X#define UNAME_START 6
  1558. X
  1559. X#define Proc_format \
  1560. X    "%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %5.2f%% %5.2f%% %.14s"
  1561. X
  1562. X
  1563. X/* process state names for the "STATE" column of the display */
  1564. X/* the extra nulls in the string "run" are for adding a slash and
  1565. X   the processor number when needed */
  1566. X
  1567. Xchar *state_abbrev[] =
  1568. X{
  1569. X    "", "sleep", "WAIT", "run", "start", "zomb", "stop", "RUN"
  1570. X};
  1571. X
  1572. X/* values that we stash away in _init and use in later routines */
  1573. X
  1574. Xstatic double logcpu;
  1575. X
  1576. X#define VMUNIX "/dynix"
  1577. X#define KMEM "/dev/kmem"
  1578. X#define MEM "/dev/mem"
  1579. X
  1580. Xstatic int kmem = -1;
  1581. Xstatic int mem = -1;
  1582. X
  1583. Xstruct vmtotal total;
  1584. X
  1585. X/* these are retrieved from the kernel in _init */
  1586. X
  1587. Xstatic unsigned long proc;
  1588. Xstatic          int  nproc;
  1589. Xstatic load_avg  ccpu;
  1590. X
  1591. X/* these are offsets obtained via nlist and used in the get_ functions */
  1592. X
  1593. Xstatic unsigned long mpid_offset;
  1594. Xstatic unsigned long avenrun_offset;
  1595. Xstatic unsigned long total_offset;
  1596. X
  1597. X/* these are for calculating cpu state percentages */
  1598. X
  1599. Xstatic long cp_time[CPUSTATES];
  1600. Xstatic long cp_old[CPUSTATES];
  1601. Xstatic long cp_diff[CPUSTATES];
  1602. X
  1603. X/* these are for detailing the process states */
  1604. X
  1605. Xint process_states[8];
  1606. Xchar *procstatenames[] = {
  1607. X    "", " sleeping, ", " ABANDONED, ", " runable, ", " starting, ",
  1608. X    " zombie, ", " stopped, ", " running, ",
  1609. X    NULL
  1610. X};
  1611. X
  1612. X/* these are for detailing the cpu states */
  1613. X
  1614. Xint cpu_states[CPUSTATES];
  1615. Xchar *cpustatenames[] = {
  1616. X    "user", "nice", "system", "idle",
  1617. X    NULL
  1618. X};
  1619. X
  1620. X/* these are for detailing the memory statistics */
  1621. X
  1622. Xint memory_stats[5];
  1623. Xchar *memorynames[] = {
  1624. X    "K (", "K) real, ", "K (", "K) virtual, ", "K free", NULL
  1625. X};
  1626. X
  1627. X/* these are for keeping track of the proc array */
  1628. X
  1629. Xstatic int bytes;
  1630. Xstatic int pref_len;
  1631. Xstatic struct proc *pbase;
  1632. Xstatic struct proc **pref;
  1633. X
  1634. X#define pagetok(size)    ((size) << (PGSHIFT - LOG1024))
  1635. X
  1636. X/* useful externals */
  1637. Xextern int errno;
  1638. Xextern char *sys_errlist[];
  1639. X
  1640. Xlong lseek();
  1641. Xlong percentages();
  1642. X
  1643. Xmachine_init(statics)
  1644. X
  1645. Xstruct statics *statics;
  1646. X
  1647. X{
  1648. X    register int i;
  1649. X
  1650. X    /* open kernel memory */
  1651. X    if ((kmem = open(KMEM, 0)) < 0)
  1652. X    {
  1653. X    perror(KMEM);
  1654. X    exit(20);
  1655. X    }
  1656. X    if ((mem = open(MEM, 0)) < 0)
  1657. X    {
  1658. X    perror(MEM);
  1659. X    exit(21);
  1660. X    }
  1661. X
  1662. X    /* get the list of symbols we want to access in the kernel */
  1663. X    if ((i = nlist(VMUNIX, nlst)) < 0)
  1664. X    {
  1665. X    fprintf(stderr, "top: nlist failed\n");
  1666. X    return(-1);
  1667. X    }
  1668. X
  1669. X    /* make sure they were all found */
  1670. X    if (i > 0 && check_nlist(nlst) > 0)
  1671. X    {
  1672. X    return(-1);
  1673. X    }
  1674. X
  1675. X    /* get the symbol values out of kmem */
  1676. X    (void) getkval(nlst[X_PROC].n_value,   (int *)(&proc),    sizeof(proc),
  1677. X        nlst[X_PROC].n_name);
  1678. X    (void) getkval(nlst[X_NPROC].n_value,  &nproc,        sizeof(nproc),
  1679. X        nlst[X_NPROC].n_name);
  1680. X    (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),    sizeof(ccpu),
  1681. X        nlst[X_CCPU].n_name);
  1682. X    (void) getkval(nlst[X_NENGINE].n_value,  &Nengine,  sizeof(int),
  1683. X        nlst[X_NENGINE].n_name);
  1684. X    (void) getkval(nlst[X_ENGINE].n_value,  &pengine,  sizeof(struct engine *),
  1685. X        nlst[X_ENGINE].n_name);
  1686. X
  1687. X    engine = (struct engine *)calloc(Nengine, sizeof(struct engine));
  1688. X    if (engine == NULL)
  1689. X    {
  1690. X    fprintf(stderr, "Cannot allocate memory for engine structure\n");
  1691. X    exit(2);
  1692. X    }
  1693. X    (void) getkval(pengine,  &engine[0],  Nengine * sizeof(struct engine),
  1694. X        "engine array");
  1695. X    pplocal = (struct plocal **)calloc(Nengine, sizeof(struct plocal *));
  1696. X    if (pplocal == NULL)
  1697. X    {
  1698. X    fprintf(stderr, "Cannot allocate memory for plocal structures\n");
  1699. X    exit(2);
  1700. X    }
  1701. X    for (i = 0; i < Nengine; i++) {
  1702. X    pplocal[i] = (struct plocal *)&engine[i].e_local->pp_local[0][0];
  1703. X    }
  1704. X
  1705. X    /* stash away certain offsets for later use */
  1706. X    mpid_offset = nlst[X_MPID].n_value;
  1707. X    avenrun_offset = nlst[X_AVENRUN].n_value;
  1708. X    total_offset = nlst[X_TOTAL].n_value;
  1709. X
  1710. X    /* this is used in calculating WCPU -- calculate it ahead of time */
  1711. X    logcpu = log(loaddouble(ccpu));
  1712. X
  1713. X    /* allocate space for proc structure array and array of pointers */
  1714. X    bytes = nproc * sizeof(struct proc);
  1715. X    pbase = (struct proc *)malloc(bytes);
  1716. X    pref  = (struct proc **)malloc(nproc * sizeof(struct proc *));
  1717. X
  1718. X    /* Just in case ... */
  1719. X    if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
  1720. X    {
  1721. X    fprintf(stderr, "top: can't allocate sufficient memory\n");
  1722. X    return(-1);
  1723. X    }
  1724. X
  1725. X    /* fill in the statics information */
  1726. X    statics->procstate_names = procstatenames;
  1727. X    statics->cpustate_names = cpustatenames;
  1728. X    statics->memory_names = memorynames;
  1729. X
  1730. X    /* all done! */
  1731. X    return(0);
  1732. X}
  1733. X
  1734. Xchar *format_header(uname_field)
  1735. X
  1736. Xregister char *uname_field;
  1737. X
  1738. X{
  1739. X    register char *ptr;
  1740. X
  1741. X    ptr = header + UNAME_START;
  1742. X    while (*uname_field != '\0')
  1743. X    {
  1744. X    *ptr++ = *uname_field++;
  1745. X    }
  1746. X
  1747. X    return(header);
  1748. X}
  1749. X
  1750. Xget_system_info(si)
  1751. X
  1752. Xstruct system_info *si;
  1753. X
  1754. X{
  1755. X    load_avg avenrun[3];
  1756. X    struct plocal plocal;
  1757. X    register int i, j;
  1758. X
  1759. X    /* get the cp_time array */
  1760. X    for (j = 0; j < CPUSTATES; j++)
  1761. X    cp_time[j] = 0L;
  1762. X    for (i = 0; i < Nengine; i++) {
  1763. X    (void) getkval(pplocal[i], &plocal, sizeof(struct plocal), "plocal array");
  1764. X    for (j = 0; j < CPUSTATES; j++)
  1765. X        cp_time[j] += (long)plocal.cnt.v_time[j];
  1766. X    }
  1767. X
  1768. X    /* get load average array */
  1769. X    (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
  1770. X           "_avenrun");
  1771. X
  1772. X    /* get mpid -- process id of last process */
  1773. X    (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
  1774. X           "_mpid");
  1775. X
  1776. X    /* convert load averages to doubles */
  1777. X    {
  1778. X    register int i;
  1779. X    register double *infoloadp;
  1780. X    register load_avg *sysloadp;
  1781. X
  1782. X    infoloadp = si->load_avg;
  1783. X    sysloadp = avenrun;
  1784. X    for (i = 0; i < 3; i++)
  1785. X    {
  1786. X        *infoloadp++ = loaddouble(*sysloadp++);
  1787. X    }
  1788. X    }
  1789. X
  1790. X    /* convert cp_time counts to percentages */
  1791. X    (void) percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
  1792. X
  1793. X    /* get total -- systemwide main memory usage structure */
  1794. X    (void) getkval(total_offset, (int *)(&total), sizeof(total),
  1795. X           "_total");
  1796. X    /* convert memory stats to Kbytes */
  1797. X    memory_stats[0] = pagetok(total.t_rm);
  1798. X    memory_stats[1] = pagetok(total.t_arm);
  1799. X    memory_stats[2] = pagetok(total.t_vm);
  1800. X    memory_stats[3] = pagetok(total.t_avm);
  1801. X    memory_stats[4] = pagetok(total.t_free);
  1802. X
  1803. X    /* set arrays and strings */
  1804. X    si->cpustates = cpu_states;
  1805. X    si->memory = memory_stats;
  1806. X}
  1807. X
  1808. Xstatic struct handle handle;
  1809. X
  1810. Xcaddr_t get_process_info(si, sel, compare)
  1811. X
  1812. Xstruct system_info *si;
  1813. Xstruct process_select *sel;
  1814. Xint (*compare)();
  1815. X
  1816. X{
  1817. X    register int i;
  1818. X    register int total_procs;
  1819. X    register int active_procs;
  1820. X    register struct proc **prefp;
  1821. X    register struct proc *pp;
  1822. X
  1823. X    /* these are copied out of sel for speed */
  1824. X    int show_idle;
  1825. X    int show_system;
  1826. X    int show_uid;
  1827. X
  1828. X    /* read all the proc structures in one fell swoop */
  1829. X    (void) getkval(proc, (int *)pbase, bytes, "proc array");
  1830. X
  1831. X    /* get a pointer to the states summary array */
  1832. X    si->procstates = process_states;
  1833. X
  1834. X    /* set up flags which define what we are going to select */
  1835. X    show_idle = sel->idle;
  1836. X    show_system = sel->system;
  1837. X    show_uid = sel->uid != -1;
  1838. X
  1839. X    /* count up process states and get pointers to interesting procs */
  1840. X    total_procs = 0;
  1841. X    active_procs = 0;
  1842. X    bzero((char *)process_states, sizeof(process_states));
  1843. X    prefp = pref;
  1844. X    for (pp = pbase, i = 0; i < nproc; pp++, i++)
  1845. X    {
  1846. X    /*
  1847. X     *  Place pointers to each valid proc structure in pref[].
  1848. X     *  Process slots that are actually in use have a non-zero
  1849. X     *  status field.  Processes with SSYS set are system
  1850. X     *  processes---these get ignored unless show_sysprocs is set.
  1851. X     */
  1852. X    if (pp->p_stat != 0 &&
  1853. X        (show_system || ((pp->p_flag & SSYS) == 0)))
  1854. X    {
  1855. X        total_procs++;
  1856. X        process_states[pp->p_stat]++;
  1857. X        if ((pp->p_stat != SZOMB) &&
  1858. X        (show_idle || (pp->p_pctcpu != 0) || (pp->p_stat == SRUN)) &&
  1859. X        (!show_uid || pp->p_uid == (uid_t)sel->uid))
  1860. X        {
  1861. X        *prefp++ = pp;
  1862. X        active_procs++;
  1863. X        }
  1864. X    }
  1865. X    }
  1866. X
  1867. X    /* if requested, sort the "interesting" processes */
  1868. X    if (compare != NULL)
  1869. X    {
  1870. X    qsort((char *)pref, active_procs, sizeof(struct proc *), compare);
  1871. X    }
  1872. X
  1873. X    /* remember active and total counts */
  1874. X    si->p_total = total_procs;
  1875. X    si->p_active = pref_len = active_procs;
  1876. X
  1877. X    /* pass back a handle */
  1878. X    handle.next_proc = pref;
  1879. X    handle.remaining = active_procs;
  1880. X    return((caddr_t)&handle);
  1881. X}
  1882. X
  1883. Xchar fmt[128];        /* static area where result is built */
  1884. X
  1885. Xchar *format_next_process(handle, get_userid)
  1886. X
  1887. Xcaddr_t handle;
  1888. Xchar *(*get_userid)();
  1889. X
  1890. X{
  1891. X    register struct proc *pp;
  1892. X    register long cputime;
  1893. X    register double pct;
  1894. X    struct user u;
  1895. X    struct handle *hp;
  1896. X
  1897. X    /* find and remember the next proc structure */
  1898. X    hp = (struct handle *)handle;
  1899. X    pp = *(hp->next_proc++);
  1900. X    hp->remaining--;
  1901. X    
  1902. X
  1903. X    /* get the process's user struct and set cputime */
  1904. X    if (getu(pp, &u) == -1)
  1905. X    {
  1906. X    (void) strcpy(u.u_comm, "<swapped>");
  1907. X    cputime = 0;
  1908. X    }
  1909. X    else
  1910. X    {
  1911. X    /* set u_comm for system processes */
  1912. X    if (u.u_comm[0] == '\0')
  1913. X    {
  1914. X        if (pp->p_pid == 0)
  1915. X        {
  1916. X        (void) strcpy(u.u_comm, "Swapper");
  1917. X        }
  1918. X        else if (pp->p_pid == 2)
  1919. X        {
  1920. X        (void) strcpy(u.u_comm, "Pager");
  1921. X        }
  1922. X    }
  1923. X
  1924. X    cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
  1925. X    }
  1926. X
  1927. X    /* calculate the base for cpu percentages */
  1928. X    pct = pctdouble(pp->p_pctcpu);
  1929. X
  1930. X    /* format this entry */
  1931. X    sprintf(fmt,
  1932. X        Proc_format,
  1933. X        pp->p_pid,
  1934. X        (*get_userid)(pp->p_uid),
  1935. X        pp->p_pri - PZERO,
  1936. X        pp->p_nice - NZERO,
  1937. X        pagetok(PROCSIZE(pp)),
  1938. X        pagetok(pp->p_rssize),
  1939. X        state_abbrev[pp->p_stat],
  1940. X        cputime / 60l,
  1941. X        cputime % 60l,
  1942. X        100.0 * weighted_cpu(pct, pp),
  1943. X        100.0 * pct,
  1944. X        printable(u.u_comm));
  1945. X
  1946. X    /* return the result */
  1947. X    return(fmt);
  1948. X}
  1949. X
  1950. X/*
  1951. X *  getu(p, u) - get the user structure for the process whose proc structure
  1952. X *    is pointed to by p.  The user structure is put in the buffer pointed
  1953. X *    to by u.  Return 0 if successful, -1 on failure (such as the process
  1954. X *    being swapped out).
  1955. X */
  1956. X
  1957. Xgetu(p, u)
  1958. X
  1959. Xregister struct proc *p;
  1960. Xstruct user *u;
  1961. X
  1962. X{
  1963. X    struct pte uptes[UPAGES];
  1964. X    register caddr_t upage;
  1965. X    register struct pte *pte;
  1966. X    register nbytes, n;
  1967. X
  1968. X    /*
  1969. X     *  Check if the process is currently loaded or swapped out.  The way we
  1970. X     *  get the u area is totally different for the two cases.  For this
  1971. X     *  application, we just don't bother if the process is swapped out.
  1972. X     */
  1973. X    if ((p->p_flag & SLOAD) == 0)
  1974. X    {
  1975. X    return(-1);
  1976. X    }
  1977. X
  1978. X    /*
  1979. X     *  Process is currently in memory, we hope!
  1980. X     */
  1981. X#ifdef ns32000
  1982. X    if (!getkval(p->p_upte, uptes, sizeof(uptes), "!p->p_upte"))
  1983. X#else
  1984. X    if (!getkval(p->p_pttop, uptes, sizeof(uptes), "!p->p_upte"))
  1985. X#endif
  1986. X    {
  1987. X    /* we can't seem to get to it, so pretend it's swapped out */
  1988. X    return(-1);
  1989. X    } 
  1990. X    upage = (caddr_t)u;
  1991. X    pte = uptes;
  1992. X    for (nbytes = sizeof(struct user); nbytes > 0; nbytes -= NBPG)
  1993. X    {
  1994. X        (void) lseek(mem, (long)(pte++->pg_pfnum * NBPG), 0);
  1995. X    n = MIN(nbytes, NBPG);
  1996. X    if (read(mem, upage, n) != n)
  1997. X    {
  1998. X        /* we can't seem to get to it, so pretend it's swapped out */
  1999. X        return(-1);
  2000. X    }
  2001. X    upage += n;
  2002. X    }
  2003. X    return(0);
  2004. X}
  2005. X
  2006. X/*
  2007. X * check_nlist(nlst) - checks the nlist to see if any symbols were not
  2008. X *        found.  For every symbol that was not found, a one-line
  2009. X *        message is printed to stderr.  The routine returns the
  2010. X *        number of symbols NOT found.
  2011. X */
  2012. X
  2013. Xint check_nlist(nlst)
  2014. X
  2015. Xregister struct nlist *nlst;
  2016. X
  2017. X{
  2018. X    register int i;
  2019. X
  2020. X    /* check to see if we got ALL the symbols we requested */
  2021. X    /* this will write one line to stderr for every symbol not found */
  2022. X
  2023. X    i = 0;
  2024. X    while (nlst->n_name != NULL)
  2025. X    {
  2026. X    if (nlst->n_type == 0)
  2027. X    {
  2028. X        /* this one wasn't found */
  2029. X        fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
  2030. X        i = 1;
  2031. X    }
  2032. X    nlst++;
  2033. X    }
  2034. X
  2035. X    return(i);
  2036. X}
  2037. X
  2038. X
  2039. X/*
  2040. X *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
  2041. X *    "offset" is the byte offset into the kernel for the desired value,
  2042. X *      "ptr" points to a buffer into which the value is retrieved,
  2043. X *      "size" is the size of the buffer (and the object to retrieve),
  2044. X *      "refstr" is a reference string used when printing error meessages,
  2045. X *        if "refstr" starts with a '!', then a failure on read will not
  2046. X *          be fatal (this may seem like a silly way to do things, but I
  2047. X *          really didn't want the overhead of another argument).
  2048. X *      
  2049. X */
  2050. X
  2051. Xgetkval(offset, ptr, size, refstr)
  2052. X
  2053. Xunsigned long offset;
  2054. Xint *ptr;
  2055. Xint size;
  2056. Xchar *refstr;
  2057. X
  2058. X{
  2059. X    if (lseek(kmem, (long)offset, 0) == -1)
  2060. X    {
  2061. X    if (*refstr == '!')
  2062. X    {
  2063. X        refstr++;
  2064. X    }
  2065. X    fprintf(stderr, "%s: lseek to %s: %s\n",
  2066. X        KMEM, refstr, sys_errlist[errno]);
  2067. X    quit(22);
  2068. X    }
  2069. X    if (read(kmem, (char *)ptr, size) == -1)
  2070. X    {
  2071. X    if (*refstr == '!')
  2072. X    {
  2073. X        /* we lost the race with the kernel, process isn't in memory */
  2074. X        return(0);
  2075. X    } 
  2076. X    else 
  2077. X    {
  2078. X        fprintf(stderr, "%s: reading %s: %s\n",
  2079. X        KMEM, refstr, sys_errlist[errno]);
  2080. X        quit(23);
  2081. X    }
  2082. X    }
  2083. X    return(1);
  2084. X}
  2085. X    
  2086. X/* comparison routine for qsort */
  2087. X
  2088. X/*
  2089. X *  proc_compare - comparison function for "qsort"
  2090. X *    Compares the resource consumption of two processes using five
  2091. X *      distinct keys.  The keys (in descending order of importance) are:
  2092. X *      percent cpu, cpu ticks, state, resident set size, total virtual
  2093. X *      memory usage.  The process states are ordered as follows (from least
  2094. X *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
  2095. X *      array declaration below maps a process state index into a number
  2096. X *      that reflects this ordering.
  2097. X */
  2098. X
  2099. Xstatic unsigned char sorted_state[] =
  2100. X{
  2101. X    0,    /* not used        */
  2102. X    3,    /* sleep        */
  2103. X    1,    /* ABANDONED (WAIT)    */
  2104. X    6,    /* run            */
  2105. X    5,    /* start        */
  2106. X    2,    /* zombie        */
  2107. X    4,    /* stop            */
  2108. X    7    /* RUN            */
  2109. X};
  2110. Xproc_compare(pp1, pp2)
  2111. X
  2112. Xstruct proc **pp1;
  2113. Xstruct proc **pp2;
  2114. X
  2115. X{
  2116. X    register struct proc *p1;
  2117. X    register struct proc *p2;
  2118. X    register int result;
  2119. X    register pctcpu lresult;
  2120. X
  2121. X    /* remove one level of indirection */
  2122. X    p1 = *pp1;
  2123. X    p2 = *pp2;
  2124. X
  2125. X    /* compare percent cpu (pctcpu) */
  2126. X    if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0)
  2127. X    {
  2128. X    /* use cpticks to break the tie */
  2129. X    if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
  2130. X    {
  2131. X        /* use process state to break the tie */
  2132. X        if ((result = sorted_state[p2->p_stat] -
  2133. X              sorted_state[p1->p_stat])  == 0)
  2134. X        {
  2135. X        /* use priority to break the tie */
  2136. X        if ((result = p2->p_pri - p1->p_pri) == 0)
  2137. X        {
  2138. X            /* use resident set size (rssize) to break the tie */
  2139. X            if ((result = p2->p_rssize - p1->p_rssize) == 0)
  2140. X            {
  2141. X            /* use total memory to break the tie */
  2142. X            result = PROCSIZE(p2) - PROCSIZE(p1);
  2143. X            }
  2144. X        }
  2145. X        }
  2146. X    }
  2147. X    }
  2148. X    else
  2149. X    {
  2150. X    result = lresult < 0 ? -1 : 1;
  2151. X    }
  2152. X
  2153. X    return(result);
  2154. X}
  2155. X
  2156. X
  2157. X/*
  2158. X * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
  2159. X *        the process does not exist.
  2160. X *        It is EXTREMLY IMPORTANT that this function work correctly.
  2161. X *        If top runs setuid root (as in SVR4), then this function
  2162. X *        is the only thing that stands in the way of a serious
  2163. X *        security problem.  It validates requests for the "kill"
  2164. X *        and "renice" commands.
  2165. X */
  2166. X
  2167. Xint proc_owner(pid)
  2168. X
  2169. Xint pid;
  2170. X
  2171. X{
  2172. X    register int cnt;
  2173. X    register struct proc **prefp;
  2174. X    register struct proc *pp;
  2175. X
  2176. X    prefp = pref;
  2177. X    cnt = pref_len;
  2178. X    while (--cnt >= 0)
  2179. X    {
  2180. X    if ((pp = *prefp++)->p_pid == (pid_t)pid)
  2181. X    {
  2182. X        return((int)pp->p_uid);
  2183. X    }
  2184. X    }
  2185. X    return(-1);
  2186. X}
  2187. END_OF_FILE
  2188. if test 17507 -ne `wc -c <'machine/m_dynix.c'`; then
  2189.     echo shar: \"'machine/m_dynix.c'\" unpacked with wrong size!
  2190. fi
  2191. # end of 'machine/m_dynix.c'
  2192. fi
  2193. echo shar: End of archive 6 \(of 13\).
  2194. cp /dev/null ark6isdone
  2195. MISSING=""
  2196. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
  2197.     if test ! -f ark${I}isdone ; then
  2198.     MISSING="${MISSING} ${I}"
  2199.     fi
  2200. done
  2201. if test "${MISSING}" = "" ; then
  2202.     echo You have unpacked all 13 archives.
  2203.     echo "Now read README and INSTALL, then run Configure"
  2204.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2205. else
  2206.     echo You still need to unpack the following archives:
  2207.     echo "        " ${MISSING}
  2208. fi
  2209. ##  End of shell archive.
  2210. exit 0
  2211.