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

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