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

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