home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Utilities / top-0.5-MI / machine / m_dgux.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-03  |  12.0 KB  |  465 lines

  1. /*
  2.  * top - a top users display for Unix
  3.  *
  4.  * SYNOPSIS:  for DG AViiON with DG/UX 5.4+
  5.  *
  6.  * DESCRIPTION:
  7.  * A top module for DG/UX 5.4 systems.
  8.  * Uses DG/UX system calls to get info from the kernel.
  9.  * (NB. top DOES NOT need to be installed setuid root under DG/UX 5.4.2)
  10.  *
  11.  * AUTHOR:  Mike Williams <mike@inform.co.nz>
  12.  */
  13.  
  14. /*
  15.  * NOTE: This module will only work with top versions 3.1 and later!
  16.  */
  17.  
  18. #include <stdlib.h> 
  19. #include <unistd.h>
  20. #include <stdio.h>
  21.  
  22. #include <sys/dg_sys_info.h>
  23. #include <sys/dg_process_info.h>
  24. #include <sys/systeminfo.h> 
  25. #include <sys/sysmacros.h> 
  26.  
  27. #include "top.h"
  28. #include "machine.h"
  29. #include "utils.h"
  30.  
  31. /*--- process formatting --------------------------------------------------*/
  32.  
  33. static char header[] =
  34.   "  PID X         PRI NICE C    SIZE STATE    TIME    CPU COMMAND";
  35. /* ddddd ssssssss dddd ddd dd ddddddK ssssssdddd:dd dd.dd% sssssssssssssssss...
  36.  * 0123456   -- field to fill in starts at header+6 */
  37. #define UNAME_START 6
  38.  
  39. #define Proc_format \
  40.      "%5d %-8.8s %4d %3d %2d %7s %-6s %6s %5.2f%% %.20s"
  41.  
  42. /*--- process states ------------------------------------------------------*/
  43.  
  44. static char* procStateNames[] = {
  45.     "", " sleeping, ", " waiting, ", " running, ", " starting, ",
  46.     " zombie, ", " stopped, ",
  47.     NULL
  48. };
  49.  
  50. static char* procStateAbbrevs[] = {
  51.     "", "sleep", "wait", "run", "start", "zombie", "stop",
  52.     NULL
  53. };
  54.  
  55. #define N_PROCESS_STATES \
  56. (sizeof (procStateNames) / sizeof (procStateNames[0]) - 1)
  57.  
  58. static int processStats[N_PROCESS_STATES];
  59.  
  60. /*--- cpu states ----------------------------------------------------------*/
  61.  
  62. enum {
  63.     CPU_user,
  64.     CPU_system,
  65.     CPU_idle,
  66.     CPU_io_wait,
  67. };
  68.  
  69. static char* cpuStateNames[] = {
  70.     "user", "system", "idle", "io_wait",
  71.     NULL
  72. };
  73.  
  74. #define N_CPU_STATES \
  75. (sizeof (cpuStateNames) / sizeof (cpuStateNames[0]) - 1)
  76.  
  77. static int cpuStats[N_CPU_STATES];
  78.  
  79. /*--- memory statistics ---------------------------------------------------*/
  80.  
  81. enum {
  82.     MEM_available,
  83.     MEM_used,
  84.     MEM_free,
  85.     MEM_freeswap,
  86. };
  87.  
  88. static char* memoryNames[] = {
  89.     "K physical, ", "K in use, ", "K free, ", "K free swap, ", NULL
  90. };
  91.  
  92. #define N_MEMORY_STATS \
  93. (sizeof (memoryNames) / sizeof (memoryNames[0]) - 1)
  94.  
  95. static int memoryStats[N_MEMORY_STATS];
  96.  
  97. /*--- conversion macros ---------------------------------------------------*/
  98.  
  99. /* Convert clicks (kernel pages) to kbytes ... */
  100. #define pagetok(size) ctob(size) >> LOG1024
  101.  
  102. /* Convert timeval's to double */
  103. #define tvtod(tval) (1000000.0 * (tval).tv_sec + 1.0 * (tval).tv_usec)
  104.  
  105. /* Scale timeval's onto longs */
  106. #define scaledtv(tval) (tvtod (tval) / 4096) 
  107.  
  108. /*--- process table -------------------------------------------------------*/
  109.  
  110. typedef struct _ProcInfo {
  111.     struct dg_process_info    p_info;
  112.     double               cpu_time;
  113.     double               fraction_cpu;
  114. } ProcInfo;
  115.  
  116. static ProcInfo*           processInfo;
  117. static ProcInfo**           activeProcessInfo;
  118.  
  119. int                   activeIndex;
  120.  
  121. typedef struct _ProcTime {
  122.     pid_t               pid;
  123.     double               cpu_time;
  124. } ProcTime;
  125.  
  126. static ProcTime*           oldProcessTimes;
  127. static int               n_oldProcessTimes;
  128.  
  129. static double               lastTime;
  130. static double               thisTime;
  131. static double               timeSlice;
  132.  
  133. /*=========================================================================*/
  134. /*=== top "Callback" routines =============================================*/
  135.  
  136. static int IntCmp (i1, i2)
  137.   int*             i1;
  138.   int*             i2;
  139. {
  140.     return (*i2 - *i1);
  141. }
  142.  
  143. /*=== Data collection =====================================================*/
  144.  
  145. int machine_init (statics)
  146.   /*~~~~~~~~~~~~
  147.    */
  148.   struct statics *statics;
  149. {
  150.     struct dg_sys_info_pm_info pm_info;
  151.     int               table_size;
  152.  
  153.     /* fill in the statics information */
  154.     statics->procstate_names = procStateNames;
  155.     statics->cpustate_names = cpuStateNames;
  156.     statics->memory_names = memoryNames;
  157.  
  158.     dg_sys_info ((long *)&pm_info,
  159.          DG_SYS_INFO_PM_INFO_TYPE,
  160.          DG_SYS_INFO_PM_VERSION_0);
  161.     table_size = pm_info.process_table_size + 1;
  162.  
  163.     processInfo = (ProcInfo *) 
  164.     malloc (sizeof (processInfo[0]) * table_size);
  165.     activeProcessInfo = (ProcInfo **) 
  166.     malloc (sizeof (activeProcessInfo[0]) * table_size);
  167.     oldProcessTimes = (ProcTime *) 
  168.     malloc (sizeof (oldProcessTimes[0]) * table_size);
  169.  
  170.     lastTime = 0;
  171.  
  172.     return(0);
  173. }
  174.  
  175. int get_system_info (si)
  176.   /*~~~~~~~~~~~~~~~
  177.    */
  178.   struct system_info *si;
  179. {
  180.     struct dg_sys_info_vm_info    vm_info;
  181.     struct dg_sys_info_pm_info    pm_info;
  182.     struct dg_sys_info_load_info  load_info;
  183.  
  184.     static long cpu_time [N_CPU_STATES];
  185.     static long cpu_old [N_CPU_STATES];
  186.     static long cpu_diff [N_CPU_STATES];
  187.  
  188.     /* memory info */
  189.     
  190.     dg_sys_info ((long *)&vm_info,
  191.          DG_SYS_INFO_VM_INFO_TYPE,
  192.          DG_SYS_INFO_VM_VERSION_0);
  193.  
  194.     memoryStats[MEM_available] = sysconf (_SC_AVAILMEM);
  195.     memoryStats[MEM_free]      = pagetok (vm_info.freemem);
  196.     memoryStats[MEM_used]      = memoryStats[0] - memoryStats[2];
  197.     memoryStats[MEM_freeswap]  = pagetok (vm_info.freeswap);
  198.     si->memory                = memoryStats;
  199.  
  200.     /* process info */
  201.     
  202.     dg_sys_info ((long *)&pm_info,
  203.          DG_SYS_INFO_PM_INFO_TYPE,
  204.          DG_SYS_INFO_PM_VERSION_0);
  205.  
  206.     si->last_pid           = 0;
  207.     si->p_total           = pm_info.process_count;
  208.     si->p_active           = pm_info.bound_runnable_process_count;
  209.  
  210.     cpu_time[CPU_user]        = scaledtv (pm_info.user_time);
  211.     cpu_time[CPU_system]      = scaledtv (pm_info.system_time);
  212.     cpu_time[CPU_idle]           = scaledtv (pm_info.idle_time);
  213.     cpu_time[CPU_io_wait]     = scaledtv (pm_info.io_wait_time);
  214.     percentages (N_CPU_STATES, cpuStats, cpu_time, cpu_old, cpu_diff);
  215.     si->cpustates           = cpuStats;
  216.  
  217.     /* calculate timescale */
  218.  
  219.     thisTime = tvtod (pm_info.current_time);
  220.     timeSlice = thisTime - lastTime;
  221.     lastTime = thisTime;
  222.     
  223.     /* load info */
  224.     
  225.     dg_sys_info ((long *)&load_info,
  226.          DG_SYS_INFO_LOAD_INFO_TYPE,
  227.          DG_SYS_INFO_LOAD_VERSION_0);
  228.  
  229.     si->load_avg[0]     = load_info.one_minute;
  230.     si->load_avg[1]     = load_info.five_minute;
  231.     si->load_avg[2]     = load_info.fifteen_minute;
  232.  
  233.     return 1;
  234. }
  235.  
  236. caddr_t get_process_info (si, sel, compare)
  237.   /*    ~~~~~~~~~~~~~~~~ 
  238.    */
  239.   struct system_info*     si;
  240.   struct process_select* sel;
  241.   int             (*compare)();
  242. {
  243.     long         key = DG_PROCESS_INFO_INITIAL_KEY;
  244.              
  245.     int         n_total = 0;
  246.     int         n_active = 0;
  247.  
  248.     ProcInfo*         pp;
  249.     int         i;
  250.  
  251.     bzero((char *)processStats, sizeof(processStats));
  252.  
  253.     while (dg_process_info (DG_PROCESS_INFO_SELECTOR_ALL_PROCESSES, 0,
  254.                 DG_PROCESS_INFO_CMD_NAME_ONLY,
  255.                 &key,
  256.                 &(processInfo[n_total].p_info),
  257.                 DG_PROCESS_INFO_CURRENT_VERSION) == 1) {
  258.  
  259.     ProcInfo*       pp = &(processInfo[n_total++]);
  260.     int         pid = pp->p_info.process_id;
  261.     ProcTime*     old_time;
  262.  
  263.     /* Increment count for this process state */
  264.     ++processStats[pp->p_info.state];
  265.  
  266.     /* Calculate % CPU usage */
  267.     pp->cpu_time = (tvtod (pp->p_info.system_time) + 
  268.             tvtod (pp->p_info.user_time));
  269.     old_time = (ProcTime *) 
  270.         bsearch (&pid, oldProcessTimes, 
  271.              n_oldProcessTimes, sizeof (ProcTime),
  272.              IntCmp);
  273.     pp->fraction_cpu = (old_time 
  274.                 ? ((pp->cpu_time - old_time->cpu_time)
  275.                    / timeSlice) 
  276.                 : 0.0);
  277.  
  278.     /* Skip if process not classed as "active" */
  279.     if ((pp->p_info.state == DG_PROCESS_INFO_STATUS_TERMINATED) ||
  280.         (!sel->idle 
  281.          && (pp->p_info.state != DG_PROCESS_INFO_STATUS_RUNNING)
  282.          && (pp->p_info.state != DG_PROCESS_INFO_STATUS_WAITING)) ||
  283.         (sel->uid != -1 && pp->p_info.user_id != (uid_t)sel->uid) ||
  284.         (!sel->system && (pp->p_info.user_id == 0 &&
  285.                  pp->p_info.parent_process_id == 1)) ||
  286.         (sel->command && strcmp (pp->p_info.cmd, sel->command) != 0))
  287.         continue;
  288.  
  289.     activeProcessInfo[n_active++] = pp;
  290.     
  291.     }
  292.  
  293.     activeProcessInfo[n_active] = NULL;
  294.  
  295.     si->p_total     = n_total;
  296.     si->p_active     = n_active;
  297.     si->procstates     = processStats;
  298.  
  299.     /* If requested, sort the "interesting" processes */
  300.     if (compare != NULL) qsort((void *)activeProcessInfo, 
  301.                    n_active, 
  302.                    sizeof (ProcInfo *), 
  303.                    compare);
  304.  
  305.     /* Record scaled CPU totals, for calculating %CPU */
  306.     n_oldProcessTimes = n_total;
  307.     for (i = 0; i < n_oldProcessTimes; i++) {
  308.     oldProcessTimes[i].pid = processInfo[i].p_info.process_id;
  309.     oldProcessTimes[i].cpu_time = processInfo[i].cpu_time;
  310.     }
  311.     qsort (oldProcessTimes, n_oldProcessTimes, sizeof (ProcTime), IntCmp);
  312.  
  313.     /* pass back a handle */
  314.     activeIndex = 0;
  315.     return ((caddr_t) &activeIndex);
  316. }
  317.  
  318. /*=== Process comparison routine ==========================================*/
  319.  
  320. /*
  321.  * Sort keys are (in descending order of importance):
  322.  *     - percent cpu
  323.  *     - cpu ticks
  324.  *     - state
  325.  *     - resident set size
  326.  *     
  327.  * The process states are ordered as follows:
  328.  *     - zombie
  329.  *     - wait
  330.  *     - sleep
  331.  *     - stop
  332.  *     - start
  333.  *     - run
  334.  */
  335.  
  336. static unsigned char sortedState[] =
  337. {
  338.     0,                                    /* not used */
  339.     3,                                    /* sleep */
  340.     1,                                    /* wait    */
  341.     6,                                    /* run */
  342.     5,                                    /* start */
  343.     2,                                    /* zombie */
  344.     4,                                    /* stop */
  345. };
  346.  
  347. int proc_compare(pp1, pp2)
  348.   /*~~~~~~~~~~~~
  349.    */
  350.   ProcInfo**         pp1;
  351.   ProcInfo**         pp2;
  352. {
  353.     register ProcInfo*     p1;
  354.     register ProcInfo*     p2;
  355.     register int     result;
  356.     register float     lresult;
  357.  
  358.     register long     p1_cpu;
  359.     register long     p2_cpu;
  360.  
  361.     /* remove one level of indirection */
  362.     p1 = *pp1;
  363.     p2 = *pp2;
  364.  
  365.     /* calculate cpu totals */
  366.     p1_cpu = p1->p_info.system_time.tv_sec + p1->p_info.user_time.tv_sec;
  367.     p2_cpu = p2->p_info.system_time.tv_sec + p2->p_info.user_time.tv_sec;
  368.  
  369.     /* Compare %CPU usage */
  370.     if ((lresult = (p2->fraction_cpu - p1->fraction_cpu)) != 0)
  371.     return lresult < 0 ? -1 : 1;
  372.  
  373.     /* Compare other fields until one differs */
  374.     ((result = (p2->p_info.cpu_usage - p1->p_info.cpu_usage)) ||
  375.      (result = (sortedState [p2->p_info.state] - 
  376.         sortedState [p1->p_info.state])) ||
  377.      (result = (p2->p_info.priority - p1->p_info.priority)) ||
  378.      (result = (p2->p_info.resident_process_size - 
  379.         p1->p_info.resident_process_size)) ||
  380.      (result = (p1->p_info.process_id - p2->p_info.process_id)));
  381.  
  382.     return result;
  383. }
  384.  
  385. /*=== Process owner validation ============================================*/
  386.  
  387. /*
  388.  * proc_owner(pid) - returns the uid that owns process "pid", or -1 if
  389.  *        the process does not exist.
  390.  *        It is EXTREMLY IMPORTANT that this function work correctly.
  391.  *        If top runs setuid root (as in SVR4), then this function
  392.  *        is the only thing that stands in the way of a serious
  393.  *        security problem.  It validates requests for the "kill"
  394.  *        and "renice" commands.
  395.  */
  396.  
  397. int proc_owner (pid)
  398.   /*~~~~~~~~~~
  399.    */
  400.   int pid;
  401. {
  402.     register int      i;
  403.     ProcInfo*           pp;
  404.  
  405.     for (i = 0; (pp = activeProcessInfo [i]); i++) {
  406.     if (pp->p_info.process_id == pid) 
  407.         return (int)pp->p_info.user_id;
  408.     }
  409.     return(-1);
  410. }
  411.  
  412. /*=== Output formatting ===================================================*/
  413.  
  414. char* format_header (uname_field)
  415.   /*  ~~~~~~~~~~~~~
  416.    */
  417.   register char*     uname_field;
  418. {
  419.     register char*     ptr;
  420.  
  421.     ptr = header + UNAME_START;
  422.     while (*uname_field != '\0')
  423.     {
  424.     *ptr++ = *uname_field++;
  425.     }
  426.  
  427.     return(header);
  428. }
  429.  
  430. char* format_next_process (index_ptr, get_userid)
  431.   /*  ~~~~~~~~~~~~~~~~~~~
  432.    */
  433.   int*             index_ptr;
  434.   char*         (*get_userid)();
  435. {
  436.     static char     fmt[MAX_COLS];
  437.  
  438.     int         proc_index;
  439.     ProcInfo*         pp;
  440.     long         proc_cpu;
  441.  
  442.     proc_index = (*index_ptr)++;
  443.     pp = activeProcessInfo [proc_index];
  444.     proc_cpu = pp->p_info.system_time.tv_sec + pp->p_info.user_time.tv_sec;
  445.  
  446.     /* format this entry */
  447.  
  448.     sprintf (fmt,
  449.          Proc_format,
  450.          pp->p_info.process_id,
  451.          (*get_userid) (pp->p_info.user_id),
  452.          pp->p_info.priority,
  453.          pp->p_info.nice_value,
  454.          pp->p_info.cpu_usage,
  455.          format_k(pagetok (pp->p_info.resident_process_size)),
  456.          procStateAbbrevs[pp->p_info.state],
  457.          format_time(proc_cpu),
  458.          100.0 * pp->fraction_cpu,
  459.          pp->p_info.cmd);
  460.     
  461.     return(fmt);
  462. }
  463.  
  464. /*=== END of m_dgux.c =====================================================*/
  465.