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

  1. Newsgroups: comp.sources.unix
  2. From: phil@eecs.nwu.edu (William LeFebvre)
  3. Subject: v27i007: top - a top process display, version 3.2, Part07/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 7
  10. Archive-Name: top-3.2/part07
  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 7 (of 13)."
  19. # Contents:  machine/m_dynix32.c machine/m_osmp41a.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_dynix32.c' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'machine/m_dynix32.c'\"
  24. else
  25. echo shar: Extracting \"'machine/m_dynix32.c'\" \(17566 characters\)
  26. sed "s/^X//" >'machine/m_dynix32.c' <<'END_OF_FILE'
  27. X/*
  28. X * top - a top users display for Unix
  29. X *
  30. X * SYNOPSIS:  any Sequent Running Dynix 3.2.x
  31. X *
  32. X * DESCRIPTION:
  33. X * This is the machine-dependent module for Sequent Dynix 3.2.0
  34. X * This makes top work on the following systems:
  35. X *    Dynix 3.2.0 and perhaps later versions
  36. X *
  37. X * CFLAGS: -DBSD
  38. X *
  39. X * AUTHOR:  Daniel Trinkle <trinkle@cs.purdue.edu>
  40. X */
  41. X
  42. X#include <sys/types.h>
  43. X#include <sys/signal.h>
  44. X#include <sys/param.h>
  45. X
  46. X#include <stdio.h>
  47. X#include <nlist.h>
  48. X#include <math.h>
  49. X#include <sys/dir.h>
  50. X#include <sys/user.h>
  51. X#include <sys/proc.h>
  52. X#include <sys/dk.h>
  53. X#include <sys/vm.h>
  54. X#include <machine/pte.h>
  55. X#include <machine/plocal.h>
  56. X#include <machine/engine.h>
  57. X#include <sys/file.h>
  58. X
  59. X#include "top.h"
  60. X#include "machine.h"
  61. X
  62. X#ifndef uid_t
  63. X/* some early versions of DYNIX don't have uid_t */
  64. X#define uid_t int
  65. X#endif
  66. X
  67. X#ifndef pid_t
  68. X/* ditto pid_t */
  69. X#define pid_t short
  70. X#endif
  71. X
  72. Xstruct engine *engine;
  73. Xstruct engine *pengine;
  74. Xstruct plocal **pplocal;
  75. Xint Nengine;
  76. X
  77. X/* get_process_info passes back a handle.  This is what it looks like: */
  78. X
  79. Xstruct handle
  80. X{
  81. X    struct proc **next_proc;    /* points to next valid proc pointer */
  82. X    int remaining;        /* number of pointers remaining */
  83. X};
  84. X
  85. X/* declarations for load_avg */
  86. Xtypedef long load_avg;
  87. Xtypedef long pctcpu;
  88. X#define loaddouble(la) ((double)(la) / FSCALE)
  89. X#define intload(i) ((int)((i) * FSCALE))
  90. X#define pctdouble(p) ((double)(p) / FSCALE)
  91. X
  92. X/* define what weighted cpu is.  */
  93. X#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
  94. X             ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
  95. X
  96. X/* what we consider to be process size: */
  97. X#define PROCSIZE(pp) ((pp)->p_dsize + (pp)->p_ssize)
  98. X
  99. X/* definitions for indices in the nlist array */
  100. X#define X_AVENRUN    0
  101. X#define X_CCPU        1
  102. X#define X_MPID        2
  103. X#define X_NPROC        3
  104. X#define X_PROC        4
  105. X#define X_TOTAL        5
  106. X#define X_ENGINE    6
  107. X#define X_NENGINE    7
  108. X
  109. Xstatic struct nlist nlst[] = {
  110. X    { "_avenrun" },        /* 0 */
  111. X    { "_ccpu" },        /* 1 */
  112. X    { "_mpid" },        /* 2 */
  113. X    { "_nproc" },        /* 3 */
  114. X    { "_proc" },        /* 4 */
  115. X    { "_total" },        /* 5 */
  116. X    { "_engine" },        /* 6 */
  117. X    { "_Nengine" },        /* 7 */
  118. X    { 0 }
  119. X};
  120. X
  121. X/*
  122. X *  These definitions control the format of the per-process area
  123. X */
  124. X
  125. Xstatic char header[] =
  126. X  "  PID X        PRI NICE   SIZE   RES STATE   TIME   WCPU    CPU COMMAND";
  127. X/* 0123456   -- field to fill in starts at header+6 */
  128. X#define UNAME_START 6
  129. X
  130. X#define Proc_format \
  131. X    "%5d %-8.8s %3d %4d%6dK %4dK %-5s%4d:%02d %5.2f%% %5.2f%% %.14s"
  132. X
  133. X
  134. X/* process state names for the "STATE" column of the display */
  135. X/* the extra nulls in the string "run" are for adding a slash and
  136. X   the processor number when needed */
  137. X
  138. Xchar *state_abbrev[] =
  139. X{
  140. X    "", "sleep", "WAIT", "run", "start", "zomb", "stop", "RUN"
  141. X};
  142. X
  143. X/* values that we stash away in _init and use in later routines */
  144. X
  145. Xstatic double logcpu;
  146. X
  147. X#define VMUNIX "/dynix"
  148. X#define KMEM "/dev/kmem"
  149. X#define MEM "/dev/mem"
  150. X
  151. Xstatic int kmem = -1;
  152. Xstatic int mem = -1;
  153. X
  154. Xstruct vmtotal total;
  155. X
  156. X/* these are retrieved from the kernel in _init */
  157. X
  158. Xstatic unsigned long proc;
  159. Xstatic          int  nproc;
  160. Xstatic load_avg  ccpu;
  161. X
  162. X/* these are offsets obtained via nlist and used in the get_ functions */
  163. X
  164. Xstatic unsigned long mpid_offset;
  165. Xstatic unsigned long avenrun_offset;
  166. Xstatic unsigned long total_offset;
  167. X
  168. X/* these are for calculating cpu state percentages */
  169. X
  170. Xstatic long cp_time[CPUSTATES];
  171. Xstatic long cp_old[CPUSTATES];
  172. Xstatic long cp_diff[CPUSTATES];
  173. X
  174. X/* these are for detailing the process states */
  175. X
  176. Xint process_states[8];
  177. Xchar *procstatenames[] = {
  178. X    "", " sleeping, ", " ABANDONED, ", " runable, ", " starting, ",
  179. X    " zombie, ", " stopped, ", " running, ",
  180. X    NULL
  181. X};
  182. X
  183. X/* these are for detailing the cpu states */
  184. X
  185. Xint cpu_states[CPUSTATES];
  186. Xchar *cpustatenames[] = {
  187. X    "user", "nice", "system", "idle",
  188. X    NULL
  189. X};
  190. X
  191. X/* these are for detailing the memory statistics */
  192. X
  193. Xint memory_stats[5];
  194. Xchar *memorynames[] = {
  195. X    "K (", "K) real, ", "K (", "K) virtual, ", "K free", NULL
  196. X};
  197. X
  198. X/* these are for keeping track of the proc array */
  199. X
  200. Xstatic int bytes;
  201. Xstatic int pref_len;
  202. Xstatic struct proc *pbase;
  203. Xstatic struct proc **pref;
  204. X
  205. X#define pagetok(size)    ((size) << (PGSHIFT - LOG1024))
  206. X
  207. X/* useful externals */
  208. Xextern int errno;
  209. Xextern char *sys_errlist[];
  210. X
  211. Xlong lseek();
  212. Xlong percentages();
  213. X
  214. Xmachine_init(statics)
  215. X
  216. Xstruct statics *statics;
  217. X
  218. X{
  219. X    register int i;
  220. X
  221. X    /* open kernel memory */
  222. X    if ((kmem = open(KMEM, 0)) < 0)
  223. X    {
  224. X    perror(KMEM);
  225. X    exit(20);
  226. X    }
  227. X    if ((mem = open(MEM, 0)) < 0)
  228. X    {
  229. X    perror(MEM);
  230. X    exit(21);
  231. X    }
  232. X
  233. X    /* get the list of symbols we want to access in the kernel */
  234. X    if ((i = nlist(VMUNIX, nlst)) < 0)
  235. X    {
  236. X    fprintf(stderr, "top: nlist failed\n");
  237. X    return(-1);
  238. X    }
  239. X
  240. X    /* make sure they were all found */
  241. X    if (i > 0 && check_nlist(nlst) > 0)
  242. X    {
  243. X    return(-1);
  244. X    }
  245. X
  246. X    /* get the symbol values out of kmem */
  247. X    (void) getkval(nlst[X_PROC].n_value,   (int *)(&proc),    sizeof(proc),
  248. X        nlst[X_PROC].n_name);
  249. X    (void) getkval(nlst[X_NPROC].n_value,  &nproc,        sizeof(nproc),
  250. X        nlst[X_NPROC].n_name);
  251. X    (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),    sizeof(ccpu),
  252. X        nlst[X_CCPU].n_name);
  253. X    (void) getkval(nlst[X_NENGINE].n_value,  &Nengine,  sizeof(int),
  254. X        nlst[X_NENGINE].n_name);
  255. X    (void) getkval(nlst[X_ENGINE].n_value,  &pengine,  sizeof(struct engine *),
  256. X        nlst[X_ENGINE].n_name);
  257. X
  258. X    engine = (struct engine *)calloc(Nengine, sizeof(struct engine));
  259. X    if (engine == NULL)
  260. X    {
  261. X    fprintf(stderr, "Cannot allocate memory for engine structure\n");
  262. X    exit(2);
  263. X    }
  264. X    (void) getkval(pengine,  &engine[0],  Nengine * sizeof(struct engine),
  265. X        "engine array");
  266. X    pplocal = (struct plocal **)calloc(Nengine, sizeof(struct plocal *));
  267. X    if (pplocal == NULL)
  268. X    {
  269. X    fprintf(stderr, "Cannot allocate memory for plocal structures\n");
  270. X    exit(2);
  271. X    }
  272. X    for (i = 0; i < Nengine; i++) {
  273. X    pplocal[i] = (struct plocal *)&engine[i].e_local->pp_local[0][0];
  274. X    }
  275. X
  276. X    /* stash away certain offsets for later use */
  277. X    mpid_offset = nlst[X_MPID].n_value;
  278. X    avenrun_offset = nlst[X_AVENRUN].n_value;
  279. X    total_offset = nlst[X_TOTAL].n_value;
  280. X
  281. X    /* this is used in calculating WCPU -- calculate it ahead of time */
  282. X    logcpu = log(loaddouble(ccpu));
  283. X
  284. X    /* allocate space for proc structure array and array of pointers */
  285. X    bytes = nproc * sizeof(struct proc);
  286. X    pbase = (struct proc *)malloc(bytes);
  287. X    pref  = (struct proc **)malloc(nproc * sizeof(struct proc *));
  288. X
  289. X    /* Just in case ... */
  290. X    if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
  291. X    {
  292. X    fprintf(stderr, "top: can't allocate sufficient memory\n");
  293. X    return(-1);
  294. X    }
  295. X
  296. X    /* fill in the statics information */
  297. X    statics->procstate_names = procstatenames;
  298. X    statics->cpustate_names = cpustatenames;
  299. X    statics->memory_names = memorynames;
  300. X
  301. X    /* all done! */
  302. X    return(0);
  303. X}
  304. X
  305. Xchar *format_header(uname_field)
  306. X
  307. Xregister char *uname_field;
  308. X
  309. X{
  310. X    register char *ptr;
  311. X
  312. X    ptr = header + UNAME_START;
  313. X    while (*uname_field != '\0')
  314. X    {
  315. X    *ptr++ = *uname_field++;
  316. X    }
  317. X
  318. X    return(header);
  319. X}
  320. X
  321. Xget_system_info(si)
  322. X
  323. Xstruct system_info *si;
  324. X
  325. X{
  326. X    load_avg avenrun[3];
  327. X    struct plocal plocal;
  328. X    register int i, j;
  329. X
  330. X    /* get the cp_time array */
  331. X    for (j = 0; j < CPUSTATES; j++)
  332. X    cp_time[j] = 0L;
  333. X    for (i = 0; i < Nengine; i++) {
  334. X    (void) getkval(pplocal[i], &plocal, sizeof(struct plocal), "plocal array");
  335. X    for (j = 0; j < CPUSTATES; j++)
  336. X        cp_time[j] += (long)plocal.cnt.v_time[j];
  337. X    }
  338. X
  339. X    /* get load average array */
  340. X    (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
  341. X           "_avenrun");
  342. X
  343. X    /* get mpid -- process id of last process */
  344. X    (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
  345. X           "_mpid");
  346. X
  347. X    /* convert load averages to doubles */
  348. X    {
  349. X    register int i;
  350. X    register double *infoloadp;
  351. X    register load_avg *sysloadp;
  352. X
  353. X    infoloadp = si->load_avg;
  354. X    sysloadp = avenrun;
  355. X    for (i = 0; i < 3; i++)
  356. X    {
  357. X        *infoloadp++ = loaddouble(*sysloadp++);
  358. X    }
  359. X    }
  360. X
  361. X    /* convert cp_time counts to percentages */
  362. X    (void) percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff);
  363. X
  364. X    /* get total -- systemwide main memory usage structure */
  365. X    (void) getkval(total_offset, (int *)(&total), sizeof(total),
  366. X           "_total");
  367. X    /* convert memory stats to Kbytes */
  368. X    memory_stats[0] = pagetok(total.t_rm);
  369. X    memory_stats[1] = pagetok(total.t_arm);
  370. X    memory_stats[2] = pagetok(total.t_vm);
  371. X    memory_stats[3] = pagetok(total.t_avm);
  372. X    memory_stats[4] = pagetok(total.t_free);
  373. X
  374. X    /* set arrays and strings */
  375. X    si->cpustates = cpu_states;
  376. X    si->memory = memory_stats;
  377. X}
  378. X
  379. Xstatic struct handle handle;
  380. X
  381. Xcaddr_t get_process_info(si, sel, compare)
  382. X
  383. Xstruct system_info *si;
  384. Xstruct process_select *sel;
  385. Xint (*compare)();
  386. X
  387. X{
  388. X    register int i;
  389. X    register int total_procs;
  390. X    register int active_procs;
  391. X    register struct proc **prefp;
  392. X    register struct proc *pp;
  393. X
  394. X    /* these are copied out of sel for speed */
  395. X    int show_idle;
  396. X    int show_system;
  397. X    int show_uid;
  398. X
  399. X    /* read all the proc structures in one fell swoop */
  400. X    (void) getkval(proc, (int *)pbase, bytes, "proc array");
  401. X
  402. X    /* get a pointer to the states summary array */
  403. X    si->procstates = process_states;
  404. X
  405. X    /* set up flags which define what we are going to select */
  406. X    show_idle = sel->idle;
  407. X    show_system = sel->system;
  408. X    show_uid = sel->uid != -1;
  409. X
  410. X    /* count up process states and get pointers to interesting procs */
  411. X    total_procs = 0;
  412. X    active_procs = 0;
  413. X    bzero((char *)process_states, sizeof(process_states));
  414. X    prefp = pref;
  415. X    for (pp = pbase, i = 0; i < nproc; pp++, i++)
  416. X    {
  417. X    /*
  418. X     *  Place pointers to each valid proc structure in pref[].
  419. X     *  Process slots that are actually in use have a non-zero
  420. X     *  status field.  Processes with SSYS set are system
  421. X     *  processes---these get ignored unless show_sysprocs is set.
  422. X     */
  423. X    if (pp->p_stat != 0 &&
  424. X        (show_system || ((pp->p_flag & SSYS) == 0)))
  425. X    {
  426. X        total_procs++;
  427. X        process_states[pp->p_stat]++;
  428. X        if ((pp->p_stat != SZOMB) &&
  429. X        (show_idle || (pp->p_pctcpu != 0) || (pp->p_stat == SRUN)) &&
  430. X        (!show_uid || pp->p_uid == (uid_t)sel->uid))
  431. X        {
  432. X        *prefp++ = pp;
  433. X        active_procs++;
  434. X        }
  435. X    }
  436. X    }
  437. X
  438. X    /* if requested, sort the "interesting" processes */
  439. X    if (compare != NULL)
  440. X    {
  441. X    qsort((char *)pref, active_procs, sizeof(struct proc *), compare);
  442. X    }
  443. X
  444. X    /* remember active and total counts */
  445. X    si->p_total = total_procs;
  446. X    si->p_active = pref_len = active_procs;
  447. X
  448. X    /* pass back a handle */
  449. X    handle.next_proc = pref;
  450. X    handle.remaining = active_procs;
  451. X    return((caddr_t)&handle);
  452. X}
  453. X
  454. Xchar fmt[128];        /* static area where result is built */
  455. X
  456. Xchar *format_next_process(handle, get_userid)
  457. X
  458. Xcaddr_t handle;
  459. Xchar *(*get_userid)();
  460. X
  461. X{
  462. X    register struct proc *pp;
  463. X    register long cputime;
  464. X    register double pct;
  465. X    struct user u;
  466. X    struct handle *hp;
  467. X
  468. X    /* find and remember the next proc structure */
  469. X    hp = (struct handle *)handle;
  470. X    pp = *(hp->next_proc++);
  471. X    hp->remaining--;
  472. X    
  473. X
  474. X    /* get the process's user struct and set cputime */
  475. X    if (getu(pp, &u) == -1)
  476. X    {
  477. X    (void) strcpy(u.u_comm, "<swapped>");
  478. X    cputime = 0;
  479. X    }
  480. X    else
  481. X    {
  482. X    /* set u_comm for system processes */
  483. X    if (u.u_comm[0] == '\0')
  484. X    {
  485. X        if (pp->p_pid == 0)
  486. X        {
  487. X        (void) strcpy(u.u_comm, "Swapper");
  488. X        }
  489. X        else if (pp->p_pid == 2)
  490. X        {
  491. X        (void) strcpy(u.u_comm, "Pager");
  492. X        }
  493. X    }
  494. X
  495. X    cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
  496. X    }
  497. X
  498. X    /* calculate the base for cpu percentages */
  499. X    pct = pctdouble(pp->p_pctcpu);
  500. X
  501. X    /* format this entry */
  502. X    sprintf(fmt,
  503. X        Proc_format,
  504. X        pp->p_pid,
  505. X        (*get_userid)(pp->p_uid),
  506. X        pp->p_pri - PZERO,
  507. X        pp->p_nice - NZERO,
  508. X        pagetok(PROCSIZE(pp)),
  509. X        pagetok(pp->p_rssize),
  510. X        state_abbrev[pp->p_stat],
  511. X        cputime / 60l,
  512. X        cputime % 60l,
  513. X        100.0 * weighted_cpu(pct, pp),
  514. X        100.0 * pct,
  515. X        printable(u.u_comm));
  516. X
  517. X    /* return the result */
  518. X    return(fmt);
  519. X}
  520. X
  521. X/*
  522. X *  getu(p, u) - get the user structure for the process whose proc structure
  523. X *    is pointed to by p.  The user structure is put in the buffer pointed
  524. X *    to by u.  Return 0 if successful, -1 on failure (such as the process
  525. X *    being swapped out).
  526. X */
  527. X
  528. Xgetu(p, u)
  529. X
  530. Xregister struct proc *p;
  531. Xstruct user *u;
  532. X
  533. X{
  534. X    struct pte uptes[UPAGES];
  535. X    register caddr_t upage;
  536. X    register struct pte *pte;
  537. X    register nbytes, n;
  538. X
  539. X    /*
  540. X     *  Check if the process is currently loaded or swapped out.  The way we
  541. X     *  get the u area is totally different for the two cases.  For this
  542. X     *  application, we just don't bother if the process is swapped out.
  543. X     */
  544. X    if ((p->p_flag & SLOAD) == 0)
  545. X    {
  546. X    return(-1);
  547. X    }
  548. X
  549. X    /*
  550. X     *  Process is currently in memory, we hope!
  551. X     */
  552. X#ifdef ns32000
  553. X    if (!getkval(p->p_upte, uptes, sizeof(uptes), "!p->p_upte"))
  554. X#else
  555. X    if (!getkval(p->p_pttop, uptes, sizeof(uptes), "!p->p_upte"))
  556. X#endif
  557. X    {
  558. X    /* we can't seem to get to it, so pretend it's swapped out */
  559. X    return(-1);
  560. X    } 
  561. X    upage = (caddr_t)u;
  562. X    pte = uptes;
  563. X    for (nbytes = sizeof(struct user); nbytes > 0; nbytes -= NBPG)
  564. X    {
  565. X        (void) lseek(mem, (long)(pte++->pg_pfnum * NBPG), 0);
  566. X    n = MIN(nbytes, NBPG);
  567. X    if (read(mem, upage, n) != n)
  568. X    {
  569. X        /* we can't seem to get to it, so pretend it's swapped out */
  570. X        return(-1);
  571. X    }
  572. X    upage += n;
  573. X    }
  574. X    return(0);
  575. X}
  576. X
  577. X/*
  578. X * check_nlist(nlst) - checks the nlist to see if any symbols were not
  579. X *        found.  For every symbol that was not found, a one-line
  580. X *        message is printed to stderr.  The routine returns the
  581. X *        number of symbols NOT found.
  582. X */
  583. X
  584. Xint check_nlist(nlst)
  585. X
  586. Xregister struct nlist *nlst;
  587. X
  588. X{
  589. X    register int i;
  590. X
  591. X    /* check to see if we got ALL the symbols we requested */
  592. X    /* this will write one line to stderr for every symbol not found */
  593. X
  594. X    i = 0;
  595. X    while (nlst->n_name != NULL)
  596. X    {
  597. X    if (nlst->n_type == 0)
  598. X    {
  599. X        /* this one wasn't found */
  600. X        fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
  601. X        i = 1;
  602. X    }
  603. X    nlst++;
  604. X    }
  605. X
  606. X    return(i);
  607. X}
  608. X
  609. X
  610. X/*
  611. X *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
  612. X *    "offset" is the byte offset into the kernel for the desired value,
  613. X *      "ptr" points to a buffer into which the value is retrieved,
  614. X *      "size" is the size of the buffer (and the object to retrieve),
  615. X *      "refstr" is a reference string used when printing error meessages,
  616. X *        if "refstr" starts with a '!', then a failure on read will not
  617. X *          be fatal (this may seem like a silly way to do things, but I
  618. X *          really didn't want the overhead of another argument).
  619. X *      
  620. X */
  621. X
  622. Xgetkval(offset, ptr, size, refstr)
  623. X
  624. Xunsigned long offset;
  625. Xint *ptr;
  626. Xint size;
  627. Xchar *refstr;
  628. X
  629. X{
  630. X    if (lseek(kmem, (long)offset, 0) == -1)
  631. X    {
  632. X    if (*refstr == '!')
  633. X    {
  634. X        refstr++;
  635. X    }
  636. X    fprintf(stderr, "%s: lseek to %s: %s\n",
  637. X        KMEM, refstr, sys_errlist[errno]);
  638. X    quit(22);
  639. X    }
  640. X    if (read(kmem, (char *)ptr, size) == -1)
  641. X    {
  642. X    if (*refstr == '!')
  643. X    {
  644. X        /* we lost the race with the kernel, process isn't in memory */
  645. X        return(0);
  646. X    } 
  647. X    else 
  648. X    {
  649. X        fprintf(stderr, "%s: reading %s: %s\n",
  650. X        KMEM, refstr, sys_errlist[errno]);
  651. X        quit(23);
  652. X    }
  653. X    }
  654. X    return(1);
  655. X}
  656. X    
  657. X/* comparison routine for qsort */
  658. X
  659. X/*
  660. X *  proc_compare - comparison function for "qsort"
  661. X *    Compares the resource consumption of two processes using five
  662. X *      distinct keys.  The keys (in descending order of importance) are:
  663. X *      percent cpu, cpu ticks, state, resident set size, total virtual
  664. X *      memory usage.  The process states are ordered as follows (from least
  665. X *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
  666. X *      array declaration below maps a process state index into a number
  667. X *      that reflects this ordering.
  668. X */
  669. X
  670. Xstatic unsigned char sorted_state[] =
  671. X{
  672. X    0,    /* not used        */
  673. X    3,    /* sleep        */
  674. X    1,    /* ABANDONED (WAIT)    */
  675. X    6,    /* run            */
  676. X    5,    /* start        */
  677. X    2,    /* zombie        */
  678. X    4,    /* stop            */
  679. X    7    /* RUN            */
  680. X};
  681. Xproc_compare(pp1, pp2)
  682. X
  683. Xstruct proc **pp1;
  684. Xstruct proc **pp2;
  685. X
  686. X{
  687. X    register struct proc *p1;
  688. X    register struct proc *p2;
  689. X    register int result;
  690. X    register pctcpu lresult;
  691. X
  692. X    /* remove one level of indirection */
  693. X    p1 = *pp1;
  694. X    p2 = *pp2;
  695. X
  696. X    /* compare percent cpu (pctcpu) */
  697. X    if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0)
  698. X    {
  699. X    /* use cpticks to break the tie */
  700. X    if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
  701. X    {
  702. X        /* use process state to break the tie */
  703. X        if ((result = sorted_state[p2->p_stat] -
  704. X              sorted_state[p1->p_stat])  == 0)
  705. X        {
  706. X        /* use priority to break the tie */
  707. X        if ((result = p2->p_pri - p1->p_pri) == 0)
  708. X        {
  709. X            /* use resident set size (rssize) to break the tie */
  710. X            if ((result = p2->p_rssize - p1->p_rssize) == 0)
  711. X            {
  712. X            /* use total memory to break the tie */
  713. X            result = PROCSIZE(p2) - PROCSIZE(p1);
  714. X            }
  715. X        }
  716. X        }
  717. X    }
  718. X    }
  719. X    else
  720. X    {
  721. X    result = lresult < 0 ? -1 : 1;
  722. X    }
  723. X
  724. X    return(result);
  725. X}
  726. X
  727. X
  728. X/*
  729. X * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
  730. X *        the process does not exist.
  731. X *        It is EXTREMLY IMPORTANT that this function work correctly.
  732. X *        If top runs setuid root (as in SVR4), then this function
  733. X *        is the only thing that stands in the way of a serious
  734. X *        security problem.  It validates requests for the "kill"
  735. X *        and "renice" commands.
  736. X */
  737. X
  738. Xint proc_owner(pid)
  739. X
  740. Xint pid;
  741. X
  742. X{
  743. X    register int cnt;
  744. X    register struct proc **prefp;
  745. X    register struct proc *pp;
  746. X
  747. X    prefp = pref;
  748. X    cnt = pref_len;
  749. X    while (--cnt >= 0)
  750. X    {
  751. X    if ((pp = *prefp++)->p_pid == (pid_t)pid)
  752. X    {
  753. X        return((int)pp->p_uid);
  754. X    }
  755. X    }
  756. X    return(-1);
  757. X}
  758. END_OF_FILE
  759. if test 17566 -ne `wc -c <'machine/m_dynix32.c'`; then
  760.     echo shar: \"'machine/m_dynix32.c'\" unpacked with wrong size!
  761. fi
  762. # end of 'machine/m_dynix32.c'
  763. fi
  764. if test -f 'machine/m_osmp41a.c' -a "${1}" != "-c" ; then 
  765.   echo shar: Will not clobber existing file \"'machine/m_osmp41a.c'\"
  766. else
  767. echo shar: Extracting \"'machine/m_osmp41a.c'\" \(17755 characters\)
  768. sed "s/^X//" >'machine/m_osmp41a.c' <<'END_OF_FILE'
  769. X/*
  770. X * top - a top users display for Unix
  771. X *
  772. X * SYNOPSIS:  any Solbourne running OS/MP 4.1A
  773. X *
  774. X * DESCRIPTION:
  775. X * This is the machine-dependent module for OS/MP 4.1A
  776. X * This makes top work on the following systems:
  777. X *    Solbourne machines running OS/MP 4.1A only
  778. X *
  779. X * LIBS:  -lkvm
  780. X *
  781. X * AUTHOR:  William LeFebvre <phil@eecs.nwu.edu>
  782. X *          Brett McCoy <brtmac@maverick.ksu.ksu.edu>
  783. X */
  784. X
  785. X#include <sys/types.h>
  786. X#include <sys/signal.h>
  787. X/* make sure param.h gets loaded with KERNEL defined to get PZERO & NZERO */
  788. X#define KERNEL
  789. X#include <sys/param.h>
  790. X#undef KERNEL
  791. X
  792. X#include <stdio.h>
  793. X#include <kvm.h>
  794. X#include <nlist.h>
  795. X#include <math.h>
  796. X#include <sys/dir.h>
  797. X#include <sys/user.h>
  798. X#include <sys/proc.h>
  799. X#include <sys/dk.h>
  800. X#include <sys/vm.h>
  801. X#include <sys/file.h>
  802. X#include <sys/time.h>
  803. X#include <vm/page.h>
  804. X
  805. X#include "top.h"
  806. X#include "machine.h"
  807. X
  808. X/* declarations for load_avg */
  809. X#include "loadavg.h"
  810. X
  811. X/* get_process_info passes back a handle.  This is what it looks like: */
  812. X
  813. Xstruct handle
  814. X{
  815. X    struct proc **next_proc;    /* points to next valid proc pointer */
  816. X    int remaining;        /* number of pointers remaining */
  817. X};
  818. X
  819. X/* define what weighted cpu is.  */
  820. X#define weighted_cpu(pct, pp) ((pp)->p_time == 0 ? 0.0 : \
  821. X             ((pct) / (1.0 - exp((pp)->p_time * logcpu))))
  822. X
  823. X/* what we consider to be process size: */
  824. X#define PROCSIZE(pp) ((pp)->p_tsize + (pp)->p_dsize + (pp)->p_ssize)
  825. X
  826. X/* definitions for indices in the nlist array */
  827. X#define X_AVENRUN    0
  828. X#define X_CCPU        1
  829. X#define X_MPID        2
  830. X#define X_NPROC        3
  831. X#define X_PROC        4
  832. X#define X_TOTAL        5
  833. X#define X_CP_TIME    6
  834. X#define X_PAGES        7
  835. X#define X_EPAGES    8
  836. X#define X_NCPUS        9
  837. X#define X_CP_MP_TIME    10
  838. X
  839. Xstatic struct nlist nlst[] = {
  840. X    { "_avenrun" },        /* 0 */
  841. X    { "_ccpu" },        /* 1 */
  842. X    { "_mpid" },        /* 2 */
  843. X    { "_nproc" },        /* 3 */
  844. X    { "_proc" },        /* 4 */
  845. X    { "_total" },        /* 5 */
  846. X    { "_cp_time" },        /* 6 */
  847. X    { "_pages" },        /* 7 */
  848. X    { "_epages" },        /* 8 */
  849. X    { "_ncpus" },        /* 9 */
  850. X    { "_cp_mp_time" },        /* 10 */
  851. X    { 0 }
  852. X};
  853. X
  854. X/*
  855. X *  These definitions control the format of the per-process area
  856. X */
  857. X
  858. Xstatic char header[] =
  859. X  "  PID X        PRI  NI   SIZE    RES STATE    TIME   WCPU    CPU COMMAND";
  860. X/* 0123456   -- field to fill in starts at header+6 */
  861. X#define UNAME_START 6
  862. X
  863. X#define Proc_format \
  864. X    "%5d %-8.8s %3d %3d%6dK %5dK %-5s%5d:%02d %5.2f%% %5.2f%% %.14s"
  865. X
  866. X
  867. X/* process state names for the "STATE" column of the display */
  868. X/* the extra nulls in the string "run" are for adding a slash and
  869. X   the processor number when needed */
  870. X
  871. Xchar *state_abbrev[] =
  872. X{
  873. X    "", "sleep", "WAIT", "run/\0\0", "start", "zomb", "stop"
  874. X};
  875. X
  876. X/* values that we stash away in _init and use in later routines */
  877. X
  878. Xstatic double logcpu;
  879. Xkvm_t *kd;
  880. X
  881. X/* these are retrieved from the kernel in _init */
  882. X
  883. Xstatic unsigned long proc;
  884. Xstatic          int  nproc;
  885. Xstatic load_avg ccpu;
  886. Xstatic unsigned long pages;
  887. Xstatic unsigned long epages;
  888. Xstatic        int  ncpus;
  889. X
  890. X/* these are offsets obtained via nlist and used in the get_ functions */
  891. X
  892. Xstatic unsigned long mpid_offset;
  893. Xstatic unsigned long avenrun_offset;
  894. Xstatic unsigned long total_offset;
  895. Xstatic unsigned long cp_time_offset;
  896. Xstatic unsigned long cp_mp_time_offset;
  897. X
  898. X/* these are for calculating cpu state percentages */
  899. X
  900. Xstatic long cp_time[CPUSTATES];
  901. Xstatic long cp_old[CPUSTATES];
  902. Xstatic long cp_diff[CPUSTATES];
  903. Xstatic long cp_mp_time[MAXNCPUS][CPUSTATES];
  904. Xstatic long cp_mp_old[MAXNCPUS][CPUSTATES];
  905. Xstatic long cp_mp_diff[MAXNCPUS][CPUSTATES];
  906. Xint which_cpu_states = 9;
  907. X
  908. X/* these are for detailing the process states */
  909. X
  910. Xint process_states[7];
  911. Xchar *procstatenames[] = {
  912. X    "", " sleeping, ", " ABANDONED, ", " running, ", " starting, ",
  913. X    " zombie, ", " stopped, ",
  914. X    NULL
  915. X};
  916. X
  917. X/* these are for detailing the cpu states */
  918. X
  919. Xint cpu_states[5];
  920. Xint cpu_mp_states[MAXNCPUS][5];
  921. Xchar *cpustatenames[] = {
  922. X    "user", "nice", "system", "idle",
  923. X    NULL
  924. X};
  925. X
  926. X/* these are for detailing the memory statistics */
  927. X
  928. Xint memory_stats[4];
  929. Xchar *memorynames[] = {
  930. X    "K available, ", "K in use, ", "K free, ", "K locked", NULL
  931. X};
  932. X
  933. X/* these are for keeping track of the proc array */
  934. X
  935. Xstatic int bytes;
  936. Xstatic int pref_len;
  937. Xstatic struct proc *pbase;
  938. Xstatic struct proc **pref;
  939. X
  940. X/* these are for getting the memory statistics */
  941. X
  942. Xstatic struct page *physpage;
  943. Xstatic int bytesize;
  944. Xstatic int count;
  945. Xstatic int pageshift;        /* log base 2 of the pagesize */
  946. X
  947. X/* define pagetok in terms of pageshift */
  948. X
  949. X#define pagetok(size) ((size) << pageshift)
  950. X
  951. X/* useful externals */
  952. Xextern int errno;
  953. Xextern char *sys_errlist[];
  954. X
  955. Xlong lseek();
  956. Xlong time();
  957. Xlong percentages();
  958. X
  959. Xmachine_init(statics)
  960. X
  961. Xstruct statics *statics;
  962. X
  963. X{
  964. X    register int i;
  965. X    register int pagesize;
  966. X
  967. X    /* initialize the kernel interface */
  968. X    if ((kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "top")) == NULL)
  969. X    {
  970. X    perror("kvm_open");
  971. X    return(-1);
  972. X    }
  973. X
  974. X    /* get the list of symbols we want to access in the kernel */
  975. X    if ((i = kvm_nlist(kd, nlst)) < 0)
  976. X    {
  977. X    fprintf(stderr, "top: nlist failed\n");
  978. X    return(-1);
  979. X    }
  980. X
  981. X    /* make sure they were all found */
  982. X    if (i > 0 && check_nlist(nlst) > 0)
  983. X    {
  984. X    return(-1);
  985. X    }
  986. X
  987. X    /* get the symbol values out of kmem */
  988. X    (void) getkval(nlst[X_PROC].n_value,   (int *)(&proc),    sizeof(proc),
  989. X        nlst[X_PROC].n_name);
  990. X    (void) getkval(nlst[X_NPROC].n_value,  &nproc,        sizeof(nproc),
  991. X        nlst[X_NPROC].n_name);
  992. X    (void) getkval(nlst[X_CCPU].n_value,   (int *)(&ccpu),    sizeof(ccpu),
  993. X        nlst[X_CCPU].n_name);
  994. X    (void) getkval(nlst[X_PAGES].n_value,  (int *)(&pages),    sizeof(pages),
  995. X        nlst[X_PAGES].n_name);
  996. X    (void) getkval(nlst[X_EPAGES].n_value, (int *)(&epages),    sizeof(epages),
  997. X        nlst[X_EPAGES].n_name);
  998. X
  999. X    /* stash away certain offsets for later use */
  1000. X    mpid_offset = nlst[X_MPID].n_value;
  1001. X    avenrun_offset = nlst[X_AVENRUN].n_value;
  1002. X    total_offset = nlst[X_TOTAL].n_value;
  1003. X    cp_time_offset = nlst[X_CP_TIME].n_value;
  1004. X    cp_mp_time_offset = nlst[X_CP_MP_TIME].n_value;
  1005. X    (void) getkval(nlst[X_NCPUS].n_value, (int *)(&ncpus), sizeof(ncpus),
  1006. X           nlst[X_NCPUS].n_name);
  1007. X
  1008. X    /* this is used in calculating WCPU -- calculate it ahead of time */
  1009. X    logcpu = log(loaddouble(ccpu));
  1010. X
  1011. X    /* allocate space for proc structure array and array of pointers */
  1012. X    bytes = nproc * sizeof(struct proc);
  1013. X    pbase = (struct proc *)malloc(bytes);
  1014. X    pref  = (struct proc **)malloc(nproc * sizeof(struct proc *));
  1015. X
  1016. X    /* Just in case ... */
  1017. X    if (pbase == (struct proc *)NULL || pref == (struct proc **)NULL)
  1018. X    {
  1019. X    fprintf(stderr, "top: can't allocate sufficient memory\n");
  1020. X    return(-1);
  1021. X    }
  1022. X
  1023. X    /* allocate a table to hold all the page structs */
  1024. X    bytesize = epages - pages;
  1025. X    count = bytesize / sizeof(struct page);
  1026. X    physpage = (struct page *)malloc(epages - pages);
  1027. X    if (physpage == NULL)
  1028. X    {
  1029. X    fprintf(stderr, "top: can't allocate sufficient memory\n");
  1030. X    return(-1);
  1031. X    }
  1032. X   
  1033. X    /* get the page size with "getpagesize" and calculate pageshift from it */
  1034. X    pagesize = getpagesize();
  1035. X    pageshift = 0;
  1036. X    while (pagesize > 1)
  1037. X    {
  1038. X    pageshift++;
  1039. X    pagesize >>= 1;
  1040. X    }
  1041. X
  1042. X    /* we only need the amount of log(2)1024 for our conversion */
  1043. X    pageshift -= LOG1024;
  1044. X
  1045. X    /* fill in the statics information */
  1046. X    statics->procstate_names = procstatenames;
  1047. X    statics->cpustate_names = cpustatenames;
  1048. X    statics->memory_names = memorynames;
  1049. X
  1050. X    /* all done! */
  1051. X    return(0);
  1052. X}
  1053. X
  1054. Xchar *format_header(uname_field)
  1055. X
  1056. Xregister char *uname_field;
  1057. X
  1058. X{
  1059. X    register char *ptr;
  1060. X
  1061. X    ptr = header + UNAME_START;
  1062. X    while (*uname_field != '\0')
  1063. X    {
  1064. X    *ptr++ = *uname_field++;
  1065. X    }
  1066. X
  1067. X    return(header);
  1068. X}
  1069. X
  1070. Xget_system_info(si)
  1071. X
  1072. Xstruct system_info *si;
  1073. X
  1074. X{
  1075. X    load_avg avenrun[3];
  1076. X    int        i;
  1077. X    int         j;
  1078. X
  1079. X    /* get the cp_time array */
  1080. X    (void) getkval(cp_time_offset, (int *)cp_time, sizeof(cp_time),
  1081. X           "_cp_time");
  1082. X
  1083. X    /* get the cp_mp_time arrays as well */
  1084. X    (void) getkval(cp_mp_time_offset, (int *) cp_mp_time, sizeof(cp_mp_time),
  1085. X         "_cp_mp_time");
  1086. X
  1087. X    /* get load average array */
  1088. X    (void) getkval(avenrun_offset, (int *)avenrun, sizeof(avenrun),
  1089. X           "_avenrun");
  1090. X
  1091. X    /* get mpid -- process id of last process */
  1092. X    (void) getkval(mpid_offset, &(si->last_pid), sizeof(si->last_pid),
  1093. X           "_mpid");
  1094. X
  1095. X    /* get the array of physpage descriptors */
  1096. X    (void) getkval(pages, (int *)physpage, bytesize, "array _page");
  1097. X
  1098. X    /* convert load averages to doubles */
  1099. X    {
  1100. X    register double *infoloadp;
  1101. X    register load_avg *sysloadp;
  1102. X
  1103. X    infoloadp = si->load_avg;
  1104. X    sysloadp = avenrun;
  1105. X    for (i = 0; i < 3; i++)
  1106. X    {
  1107. X        *infoloadp++ = loaddouble(*sysloadp++);
  1108. X    }
  1109. X    }
  1110. X
  1111. X    /* calculate percentages for each of the cpu's */
  1112. X    for (i = 0; i < ncpus; i++)
  1113. X    (void) percentages(CPUSTATES, cpu_mp_states[i], cp_mp_time[i],
  1114. X               cp_mp_old[i], cp_mp_diff[i]);
  1115. X
  1116. X    /* if the selected cpu doesn't exist show summary of all cpu's */
  1117. X    /* otherwise, show stats for selected cpu */
  1118. X    if (which_cpu_states >= ncpus) {
  1119. X    for (i = 0; i < CPUSTATES; i++) {
  1120. X        cpu_states[i] = 0;
  1121. X        for (j = 0; j < ncpus; j++)
  1122. X        cpu_states[i] += cpu_mp_states[j][i];
  1123. X    }
  1124. X    } else {
  1125. X    for (i = 0; i < CPUSTATES; i++) {
  1126. X        cpu_states[i] = cpu_mp_states[which_cpu_states][i];
  1127. X    }
  1128. X    }
  1129. X
  1130. X    /* sum memory statistics */
  1131. X    {
  1132. X    register struct page *pp;
  1133. X    register int cnt;
  1134. X    register int inuse;
  1135. X    register int free;
  1136. X    register int locked;
  1137. X
  1138. X    /* bop thru the array counting page types */
  1139. X    pp = physpage;
  1140. X    inuse = free = locked = 0;
  1141. X    for (cnt = count; --cnt >= 0; pp++)
  1142. X    {
  1143. X        if (pp->p_free)
  1144. X            free++;
  1145. X        else if (pp->p_lock || pp->p_keepcnt > 0)
  1146. X            locked++;
  1147. X        else
  1148. X            inuse++;
  1149. X    }
  1150. X
  1151. X    /* convert memory stats to Kbytes */
  1152. X    memory_stats[0] = pagetok(inuse + free);
  1153. X    memory_stats[1] = pagetok(inuse);
  1154. X    memory_stats[2] = pagetok(free);
  1155. X    memory_stats[3] = pagetok(locked);
  1156. X    }
  1157. X
  1158. X    /* set arrays and strings */
  1159. X    si->cpustates = cpu_states;
  1160. X    si->memory = memory_stats;
  1161. X}
  1162. X
  1163. Xstatic struct handle handle;
  1164. X
  1165. Xcaddr_t get_process_info(si, sel, compare)
  1166. X
  1167. Xstruct system_info *si;
  1168. Xstruct process_select *sel;
  1169. Xint (*compare)();
  1170. X
  1171. X{
  1172. X    register int i;
  1173. X    register int total_procs;
  1174. X    register int active_procs;
  1175. X    register struct proc **prefp;
  1176. X    register struct proc *pp;
  1177. X
  1178. X    /* these are copied out of sel for speed */
  1179. X    int show_idle;
  1180. X    int show_system;
  1181. X    int show_uid;
  1182. X    int show_command;
  1183. X
  1184. X    /* read all the proc structures in one fell swoop */
  1185. X    (void) getkval(proc, (int *)pbase, bytes, "proc array");
  1186. X
  1187. X    /* get a pointer to the states summary array */
  1188. X    si->procstates = process_states;
  1189. X
  1190. X    /* set up flags which define what we are going to select */
  1191. X    show_idle = sel->idle;
  1192. X    show_system = sel->system;
  1193. X    show_uid = sel->uid != -1;
  1194. X    show_command = sel->command != NULL;
  1195. X
  1196. X    /* count up process states and get pointers to interesting procs */
  1197. X    total_procs = 0;
  1198. X    active_procs = 0;
  1199. X    bzero((char *)process_states, sizeof(process_states));
  1200. X    prefp = pref;
  1201. X    for (pp = pbase, i = 0; i < nproc; pp++, i++)
  1202. X    {
  1203. X    /*
  1204. X     *  Place pointers to each valid proc structure in pref[].
  1205. X     *  Process slots that are actually in use have a non-zero
  1206. X     *  status field.  Processes with SSYS set are system
  1207. X     *  processes---these get ignored unless show_sysprocs is set.
  1208. X     */
  1209. X    if (pp->p_stat != 0 &&
  1210. X        (show_system || ((pp->p_flag & SSYS) == 0)))
  1211. X    {
  1212. X        total_procs++;
  1213. X        process_states[pp->p_stat]++;
  1214. X        if ((pp->p_stat != SZOMB) &&
  1215. X        (show_idle || (pp->p_pctcpu != 0) || (pp->p_stat == SRUN)) &&
  1216. X        (!show_uid || pp->p_uid == (uid_t)sel->uid))
  1217. X        {
  1218. X        *prefp++ = pp;
  1219. X        active_procs++;
  1220. X        }
  1221. X    }
  1222. X    }
  1223. X
  1224. X    /* if requested, sort the "interesting" processes */
  1225. X    if (compare != NULL)
  1226. X    {
  1227. X    qsort((char *)pref, active_procs, sizeof(struct proc *), compare);
  1228. X    }
  1229. X
  1230. X    /* remember active and total counts */
  1231. X    si->p_total = total_procs;
  1232. X    si->p_active = pref_len = active_procs;
  1233. X
  1234. X    /* pass back a handle */
  1235. X    handle.next_proc = pref;
  1236. X    handle.remaining = active_procs;
  1237. X    return((caddr_t)&handle);
  1238. X}
  1239. X
  1240. Xchar fmt[128];        /* static area where result is built */
  1241. X
  1242. Xchar *format_next_process(handle, get_userid)
  1243. X
  1244. Xcaddr_t handle;
  1245. Xchar *(*get_userid)();
  1246. X
  1247. X{
  1248. X    register struct proc *pp;
  1249. X    register long cputime;
  1250. X    register double pct;
  1251. X    struct user u;
  1252. X    struct handle *hp;
  1253. X
  1254. X    /* find and remember the next proc structure */
  1255. X    hp = (struct handle *)handle;
  1256. X    pp = *(hp->next_proc++);
  1257. X    hp->remaining--;
  1258. X    
  1259. X    /* get the process's user struct and set cputime */
  1260. X    if (getu(pp, &u) == -1)
  1261. X    {
  1262. X    (void) strcpy(u.u_comm, "<swapped>");
  1263. X    cputime = 0;
  1264. X    }
  1265. X    else
  1266. X    {
  1267. X    /* set u_comm for system processes */
  1268. X    if (u.u_comm[0] == '\0')
  1269. X    {
  1270. X        if (pp->p_pid == 0)
  1271. X        {
  1272. X        (void) strcpy(u.u_comm, "Swapper");
  1273. X        }
  1274. X        else if (pp->p_pid == 2)
  1275. X        {
  1276. X        (void) strcpy(u.u_comm, "Pager");
  1277. X        }
  1278. X    }
  1279. X
  1280. X    cputime = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec;
  1281. X    }
  1282. X
  1283. X    /* calculate the base for cpu percentages */
  1284. X    pct = pctdouble(pp->p_pctcpu);
  1285. X
  1286. X    state_abbrev[SRUN][4] = (pp->p_lastcpu) + '0';
  1287. X
  1288. X    /* format this entry */
  1289. X    sprintf(fmt,
  1290. X        Proc_format,
  1291. X        pp->p_pid,
  1292. X        (*get_userid)(pp->p_uid),
  1293. X        pp->p_pri - PZERO,
  1294. X        pp->p_nice - NZERO,
  1295. X        pagetok(PROCSIZE(pp)),
  1296. X        pagetok(pp->p_rssize),
  1297. X        state_abbrev[pp->p_stat],
  1298. X        cputime / 60l,
  1299. X        cputime % 60l,
  1300. X        100.0 * weighted_cpu(pct, pp),
  1301. X        100.0 * pct,
  1302. X        printable(u.u_comm));
  1303. X
  1304. X    /* return the result */
  1305. X    return(fmt);
  1306. X}
  1307. X
  1308. X/*
  1309. X *  getu(p, u) - get the user structure for the process whose proc structure
  1310. X *    is pointed to by p.  The user structure is put in the buffer pointed
  1311. X *    to by u.  Return 0 if successful, -1 on failure (such as the process
  1312. X *    being swapped out).
  1313. X */
  1314. X
  1315. Xgetu(p, u)
  1316. X
  1317. Xregister struct proc *p;
  1318. Xstruct user *u;
  1319. X
  1320. X{
  1321. X    register struct user *lu;
  1322. X
  1323. X    lu = kvm_getu(kd, p);
  1324. X    if (lu == NULL)
  1325. X    {
  1326. X    return(-1);
  1327. X    }
  1328. X    else
  1329. X    {
  1330. X    *u = *lu;
  1331. X    return(0);
  1332. X    }
  1333. X}
  1334. X
  1335. X/*
  1336. X * check_nlist(nlst) - checks the nlist to see if any symbols were not
  1337. X *        found.  For every symbol that was not found, a one-line
  1338. X *        message is printed to stderr.  The routine returns the
  1339. X *        number of symbols NOT found.
  1340. X */
  1341. X
  1342. Xint check_nlist(nlst)
  1343. X
  1344. Xregister struct nlist *nlst;
  1345. X
  1346. X{
  1347. X    register int i;
  1348. X
  1349. X    /* check to see if we got ALL the symbols we requested */
  1350. X    /* this will write one line to stderr for every symbol not found */
  1351. X
  1352. X    i = 0;
  1353. X    while (nlst->n_name != NULL)
  1354. X    {
  1355. X    if (nlst->n_type == 0)
  1356. X    {
  1357. X        /* this one wasn't found */
  1358. X        fprintf(stderr, "kernel: no symbol named `%s'\n", nlst->n_name);
  1359. X        i = 1;
  1360. X    }
  1361. X    nlst++;
  1362. X    }
  1363. X
  1364. X    return(i);
  1365. X}
  1366. X
  1367. X
  1368. X/*
  1369. X *  getkval(offset, ptr, size, refstr) - get a value out of the kernel.
  1370. X *    "offset" is the byte offset into the kernel for the desired value,
  1371. X *      "ptr" points to a buffer into which the value is retrieved,
  1372. X *      "size" is the size of the buffer (and the object to retrieve),
  1373. X *      "refstr" is a reference string used when printing error meessages,
  1374. X *        if "refstr" starts with a '!', then a failure on read will not
  1375. X *          be fatal (this may seem like a silly way to do things, but I
  1376. X *          really didn't want the overhead of another argument).
  1377. X *      
  1378. X */
  1379. X
  1380. Xgetkval(offset, ptr, size, refstr)
  1381. X
  1382. Xunsigned long offset;
  1383. Xint *ptr;
  1384. Xint size;
  1385. Xchar *refstr;
  1386. X
  1387. X{
  1388. X    if (kvm_read(kd, offset, ptr, size) != size)
  1389. X    {
  1390. X    if (*refstr == '!')
  1391. X    {
  1392. X        return(0);
  1393. X    }
  1394. X    else
  1395. X    {
  1396. X        fprintf(stderr, "top: kvm_read for %s: %s\n",
  1397. X        refstr, sys_errlist[errno]);
  1398. X        quit(23);
  1399. X        /*NOTREACHED*/
  1400. X    }
  1401. X    }
  1402. X    return(1);
  1403. X}
  1404. X    
  1405. X/* comparison routine for qsort */
  1406. X
  1407. X/*
  1408. X *  proc_compare - comparison function for "qsort"
  1409. X *    Compares the resource consumption of two processes using five
  1410. X *      distinct keys.  The keys (in descending order of importance) are:
  1411. X *      percent cpu, cpu ticks, state, resident set size, total virtual
  1412. X *      memory usage.  The process states are ordered as follows (from least
  1413. X *      to most important):  WAIT, zombie, sleep, stop, start, run.  The
  1414. X *      array declaration below maps a process state index into a number
  1415. X *      that reflects this ordering.
  1416. X */
  1417. X
  1418. Xstatic unsigned char sorted_state[] =
  1419. X{
  1420. X    0,    /* not used        */
  1421. X    3,    /* sleep        */
  1422. X    1,    /* ABANDONED (WAIT)    */
  1423. X    6,    /* run            */
  1424. X    5,    /* start        */
  1425. X    2,    /* zombie        */
  1426. X    4    /* stop            */
  1427. X};
  1428. Xproc_compare(pp1, pp2)
  1429. X
  1430. Xstruct proc **pp1;
  1431. Xstruct proc **pp2;
  1432. X
  1433. X{
  1434. X    register struct proc *p1;
  1435. X    register struct proc *p2;
  1436. X    register int result;
  1437. X    register pctcpu lresult;
  1438. X
  1439. X    /* remove one level of indirection */
  1440. X    p1 = *pp1;
  1441. X    p2 = *pp2;
  1442. X
  1443. X    /* compare percent cpu (pctcpu) */
  1444. X    if ((lresult = p2->p_pctcpu - p1->p_pctcpu) == 0)
  1445. X    {
  1446. X    /* use cpticks to break the tie */
  1447. X    if ((result = p2->p_cpticks - p1->p_cpticks) == 0)
  1448. X    {
  1449. X        /* use process state to break the tie */
  1450. X        if ((result = sorted_state[p2->p_stat] -
  1451. X              sorted_state[p1->p_stat])  == 0)
  1452. X        {
  1453. X        /* use priority to break the tie */
  1454. X        if ((result = p2->p_pri - p1->p_pri) == 0)
  1455. X        {
  1456. X            /* use resident set size (rssize) to break the tie */
  1457. X            if ((result = p2->p_rssize - p1->p_rssize) == 0)
  1458. X            {
  1459. X            /* use total memory to break the tie */
  1460. X            result = PROCSIZE(p2) - PROCSIZE(p1);
  1461. X            }
  1462. X        }
  1463. X        }
  1464. X    }
  1465. X    }
  1466. X    else
  1467. X    {
  1468. X    result = lresult < 0 ? -1 : 1;
  1469. X    }
  1470. X
  1471. X    return(result);
  1472. X}
  1473. X
  1474. X/*
  1475. X * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
  1476. X *        the process does not exist.
  1477. X *        It is EXTREMLY IMPORTANT that this function work correctly.
  1478. X *        If top runs setuid root (as in SVR4), then this function
  1479. X *        is the only thing that stands in the way of a serious
  1480. X *        security problem.  It validates requests for the "kill"
  1481. X *        and "renice" commands.
  1482. X */
  1483. X
  1484. Xint proc_owner(pid)
  1485. X
  1486. Xint pid;
  1487. X
  1488. X{
  1489. X    register int cnt;
  1490. X    register struct proc **prefp;
  1491. X    register struct proc *pp;
  1492. X
  1493. X    prefp = pref;
  1494. X    cnt = pref_len;
  1495. X    while (--cnt >= 0)
  1496. X    {
  1497. X    if ((pp = *prefp++)->p_pid == (pid_t)pid)
  1498. X    {
  1499. X        return((int)pp->p_uid);
  1500. X    }
  1501. X    }
  1502. X    return(-1);
  1503. X}
  1504. END_OF_FILE
  1505. if test 17755 -ne `wc -c <'machine/m_osmp41a.c'`; then
  1506.     echo shar: \"'machine/m_osmp41a.c'\" unpacked with wrong size!
  1507. fi
  1508. # end of 'machine/m_osmp41a.c'
  1509. fi
  1510. echo shar: End of archive 7 \(of 13\).
  1511. cp /dev/null ark7isdone
  1512. MISSING=""
  1513. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
  1514.     if test ! -f ark${I}isdone ; then
  1515.     MISSING="${MISSING} ${I}"
  1516.     fi
  1517. done
  1518. if test "${MISSING}" = "" ; then
  1519.     echo You have unpacked all 13 archives.
  1520.     echo "Now read README and INSTALL, then run Configure"
  1521.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1522. else
  1523.     echo You still need to unpack the following archives:
  1524.     echo "        " ${MISSING}
  1525. fi
  1526. ##  End of shell archive.
  1527. exit 0
  1528.