Advertisement
n8r0n

Modified Darwin for Getting Process Information

Jul 21st, 2012
642
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 34.03 KB | None | 0 0
  1. /*-
  2.  * This code relies heavily on the Darwin "ps" command, which is available
  3.  * from Apple in the adv_cmds portion of the Darwin distribution. The portions
  4.  * of this code which were included from that source are:
  5.  *
  6.  * Copyright (c) 1990, 1993, 1994
  7.  *  The Regents of the University of California.  All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *  This product includes software developed by the University of
  20.  *  California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  *
  37.  * The portions of this code which were necessary to tie into the Perl
  38.  * Proc::ProcessTable module are:
  39.  *
  40.  * Copyright (c) 2003, 2004 by Thomas R. Wyant, III
  41.  *
  42.  * and may be reused under the same terms as Perl itself.
  43.  */
  44.  
  45. #include "darwin.h"
  46.  
  47. // iOS doesn't have <mach/shared_memory_server.h>, so we copy some #defines from here:
  48. // http://code.google.com/p/iphone-gcc/source/browse/trunk/include/mach/shared_memory_server.h?spec=svn8&r=8
  49. #define SHARED_LIBRARY_SERVER_SUPPORTED
  50. #define GLOBAL_SHARED_TEXT_SEGMENT      0x90000000
  51. #define GLOBAL_SHARED_DATA_SEGMENT      0xA0000000
  52. #define GLOBAL_SHARED_SEGMENT_MASK      0xF0000000
  53.  
  54. #define SHARED_TEXT_REGION_SIZE         0x10000000
  55. #define SHARED_DATA_REGION_SIZE         0x10000000
  56. #define SHARED_ALTERNATE_LOAD_BASE      0x09000000
  57.  
  58. // we force the TESTING and DEBUGGING #defines to be active:
  59. #define TESTING 1
  60. #define DEBUGGING 1
  61.  
  62. // mach_error() not available on iOS, so just make it a no-op
  63. #define mach_error(x, y)
  64.  
  65. /*
  66.  * static void getproclline (KINFO *k, char ** command_name, int *cmdlen, int eflg);
  67.  */
  68. static void getproclline (KINFO *k, char ** command_name, int *cmdlen,
  69.                           int eflg, int show_args);
  70. static int get_task_info (KINFO *ki);
  71.  
  72. int mempages = 0;
  73.  
  74. #ifdef TESTING
  75.  
  76. //void OS_get_table (void);
  77. //char *OS_initialize (void);
  78. //
  79. //int main (int argc, char **argv) {
  80. //    OS_initialize ();
  81. //    OS_get_table ();
  82. //    exit (0);
  83. //}
  84.  
  85. #endif
  86.  
  87.  
  88. char* OS_initialize(void) {
  89.    
  90.     size_t oldlen;
  91.     int mib[2];
  92.    
  93.     oldlen = sizeof(mempages);
  94.     mib[0] = CTL_HW;
  95.     mib[1] = HW_PHYSMEM;
  96.    
  97.     sysctl(mib, 2, &mempages, &oldlen, NULL, 0);
  98.    
  99.     return NULL;
  100. }
  101.  
  102. /* The appropriate FREE_BUFFERS definition for OS_get_table */
  103.  
  104. #define FREE_BUFFERS \
  105. {   if (kprocbuf != NULL) free (kprocbuf); \
  106. }
  107.  
  108. int OS_get_table(char* buffer, size_t buffSize) {
  109.     int bufferIndex = 0;
  110.    
  111.     size_t bufSize = 0;
  112.     char *command_name;
  113.     int cmdlen;
  114.     int i;
  115.     struct kinfo_proc *kp;
  116.     struct kinfo_proc *kprocbuf = NULL;
  117.     int local_error=0;
  118.     int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
  119.     int nentries;
  120.     size_t orig_bufSize = 0;
  121.     char pctcpu[6];
  122.     char pctmem[6];
  123.     int retry_count = 0;
  124.     int state;
  125.    
  126.     if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) {
  127.         DIE_HORRIBLY ("Failure calling sysctl")
  128.     }
  129.    
  130.     if ((kprocbuf= kp = (struct kinfo_proc *)malloc(bufSize)) == NULL) {
  131.         DIE_HORRIBLY ("Memory allocation failure")
  132.     }
  133.     retry_count = 0;
  134.     orig_bufSize = bufSize;
  135.     for(retry_count=0; ; retry_count++) {
  136.         /* retry for transient errors due to load in the system */
  137.         local_error = 0;
  138.         bufSize = orig_bufSize;
  139.         if ((local_error = sysctl(mib, 4, kp, &bufSize, NULL, 0)) < 0) {
  140.             if (retry_count < 1000) {
  141.                 /* 1 sec back off */
  142.                 sleep(1);
  143.                 continue;
  144.             }
  145.             DIE_HORRIBLY ("Failure calling sysctl")
  146.         } else if (local_error == 0) {
  147.             break;
  148.         }
  149.         /* 1 sec back off */
  150.         sleep(1);
  151.     }
  152.    
  153.     /* This has to be after the second sysctl since the bufSize
  154.      may have changed.  */
  155.     nentries = bufSize/ sizeof(struct kinfo_proc);
  156.    
  157.     /* the loop was stolen from ps - but it backs through the data.
  158.      * We're going through forward, which means we need to play
  159.      * slightly different games.
  160.      */
  161.    
  162. #if 1
  163.     kp += nentries - 1;
  164.     for (i = 1; i <= nentries; i++, --kp) {
  165. #else
  166.         for (i = nentries; --i >= 0; ++kp) {
  167. #endif
  168.             struct extern_proc *p;
  169.             struct eproc *e;
  170.             KINFO kinfo;
  171.             KINFO *ki = &kinfo;
  172.             memset(ki, 0, sizeof(*ki));
  173. #ifdef TESTING
  174.             char *ttname = NULL;
  175. #endif /* def TESTING */
  176.            
  177.             time_value_t total_time, system_time, user_time;
  178.            
  179.             ki->ki_p = kp;
  180.            
  181.             get_task_info(ki);
  182.            
  183.             p = KI_PROC (ki);
  184.             e = KI_EPROC (ki);
  185.             state = p->p_stat == SZOMB ? SZOMB : ki->state;
  186.             getproclline (ki, &command_name, &cmdlen, 0, 1);
  187.            
  188.             user_time = ki->tasks_info.user_time;
  189.             time_value_add (&user_time, &ki->times.user_time);
  190.             system_time = ki->tasks_info.system_time;
  191.             time_value_add (&system_time, &ki->times.system_time);
  192.             total_time = user_time;
  193.             time_value_add (&total_time, &system_time);
  194.            
  195. #ifndef TH_USAGE_SCALE
  196. #define TH_USAGE_SCALE  1000
  197. #endif 
  198. #define usage_to_percent(u) ((u*100)/TH_USAGE_SCALE)
  199. #define usage_to_tenths(u)  (((u*1000)/TH_USAGE_SCALE) % 10)
  200.             sprintf (pctcpu, "%d.%01d", usage_to_percent (ki->cpu_usage),
  201.                      usage_to_tenths (ki->cpu_usage));
  202.             sprintf (pctmem, "%.1f", ((float) ki->tasks_info.resident_size)
  203.                      * 100 / mempages);
  204.            
  205. #ifdef TIME_IN_MICROSECONDS
  206. #define time_value_to_ticks(x) 1000000LL * (x).seconds + (x).microseconds
  207. #else /* def TIME_IN_MICROSECONDS */
  208. #define time_value_to_ticks(x) ((long) (x).seconds * 100 + \
  209. ((long) (x).microseconds + 5000) / 10000)
  210. #endif /* def TIME_IN_MICROSECONDS */
  211.            
  212. #ifdef TESTING
  213.            
  214.             /* Since we're testing stand-alone, we'll provide a ttydev value
  215.              * for the look of the thing. We don't have to do this when live,
  216.              * since the .xs module does this automagically when it sees the
  217.              * ttynum value. This means ttydev must be passed BEFORE
  218.              * ttynum.
  219.              */
  220.            
  221.             if (e->e_tdev != NODEV) ttname = devname (e->e_tdev, S_IFCHR);
  222.             if (ttname == NULL) ttname = "";
  223.            
  224. #ifdef DEBUGGING
  225.             bufferIndex += snprintf (&buffer[bufferIndex], buffSize - bufferIndex, "\nPid: %d; i:%d; kp: %p\n", p->p_pid, i, kp);
  226. #else /* def DEBUGGING */
  227.             bufferIndex += snprintf (&buffer[bufferIndex], buffSize - bufferIndex, "\nPid: %d\n", p->p_pid);
  228. #endif /* def DEBUGGING */
  229.             //            printf ("    ppid: %d\n", e->e_ppid);
  230.             //            printf ("    pgid: %d\n", e->e_pgid);
  231.             //            printf ("     uid: %d\n", e->e_pcred.p_ruid);
  232.             //            printf ("     gid: %d\n", e->e_pcred.p_rgid);
  233.             //            printf ("    euid: %d\n", e->e_ucred.cr_uid);
  234.             //            printf ("    egid: %d\n", e->e_ucred.cr_gid);
  235.             //            printf ("    suid: %d\n", e->e_pcred.p_svuid);
  236.             //            printf ("    sgid: %d\n", e->e_pcred.p_svgid);
  237.             //            printf ("priority: %u\n", ki->curpri);
  238.             //            printf ("    size: %lu Kb\n", (u_long)ki->tasks_info.virtual_size/1024);
  239.             //            printf ("     rss: %lu Kb\n", (u_long)ki->tasks_info.resident_size/1024);
  240.             //            printf ("   flags: %#0x\n", p->p_flag);
  241.             //            printf ("    nice: %d\n", p->p_nice);
  242.             //            printf (" session: %p\n", e->e_sess);
  243. #ifdef TIME_IN_MICROSECONDS
  244.             //            printf ("    time: %lld microseconds\n", time_value_to_ticks (total_time));
  245.             //            printf ("   stime: %lld microseconds\n", time_value_to_ticks (system_time));
  246.             //            printf ("   utime: %lld microseconds\n", time_value_to_ticks (user_time));
  247. #else /* def TIME_IN_MICROSECONDS */
  248.             //            printf ("    time: %ld centiseconds\n", time_value_to_ticks (total_time));
  249.             //            printf ("   stime: %ld centiseconds\n", time_value_to_ticks (system_time));
  250.             //            printf ("   utime: %ld centiseconds\n", time_value_to_ticks (user_time));
  251. #endif /* def TIME_IN_MICROSECONDS */
  252.             //            printf ("   start: %ld\n", (unsigned long) p->p_starttime.tv_sec);
  253.             //            printf ("   wchan: %p\n", p->p_wchan);
  254.             //            printf ("  ttydev: %s\n", ttname);
  255.             //            printf ("  ttynum: %ld\n", (long) e->e_tdev);
  256.             //            printf ("    %%cpu: %s\n", pctcpu);
  257.             //            printf ("    %%mem: %s\n", pctmem);
  258.             //            printf ("   state: %d (%s)\n", state, States[state]);        
  259.             bufferIndex += snprintf (&buffer[bufferIndex], buffSize - bufferIndex, "     cmd: %s\n", cmdlen ? command_name : " (none available)");
  260.             //            printf ("   fname: %s\n", p->p_comm);
  261.            
  262. #else /* def TESTING */
  263.            
  264.             /* Send if off to Perl */
  265.             /*
  266.              bless_into_proc (Format, Fields,
  267.              p->p_pid,
  268.              e->e_ppid,
  269.              e->e_pgid,
  270.              e->e_pcred.p_ruid,
  271.              e->e_pcred.p_rgid,
  272.              e->e_ucred.cr_uid,
  273.              e->e_ucred.cr_gid,
  274.              e->e_pcred.p_svuid,
  275.              e->e_pcred.p_svgid,
  276.              ki->curpri,
  277.              ki->tasks_info.virtual_size/1024,
  278.              ki->tasks_info.resident_size/1024,
  279.              p->p_flag,
  280.              p->p_nice,
  281.              e->e_sess,
  282.              time_value_to_ticks (total_time),
  283.              time_value_to_ticks (system_time),
  284.              time_value_to_ticks (user_time),
  285.              p->p_starttime.tv_sec,
  286.              p->p_wchan,
  287.              "",        // The .xs code provides ttydev automagically //
  288.              e->e_tdev,
  289.              pctcpu,
  290.              pctmem,
  291.              States[state],
  292.              cmdlen ? command_name : "",
  293.              p->p_comm
  294.              );
  295.              */
  296. #endif /* def TESTING */
  297.            
  298.             if (command_name != NULL) free (command_name);
  299.         }
  300.        
  301.         FREE_BUFFERS
  302.         return bufferIndex;
  303.     }
  304.    
  305.     /* We're done with this definition of FREE_BUFFERS. Get rid of it in
  306.      * the hope that using it below (as a consequence of an inappropriate
  307.      * use of DIE_HORRIBLY, for example) will generate a more obvious
  308.      * error message.
  309.      */
  310.    
  311. #undef FREE_BUFFERS
  312.    
  313.    
  314.     /*
  315.      * The interface used to fetch the command arguments changed
  316.      * drastically between Jaguar (MacOS 10.2, Darwin 6.something) and
  317.      * Panther (MacOS 10.3, Darwin version unknown to me at this time).
  318.      * The corresponding module of the ps command changed likewise.
  319.      * Unfortunately, we have to either keep both interfaces around,
  320.      * or abandon Panther (stupid!), or abandon Jaguar (which I'm reluctant
  321.      * to do, since I have a not-so-sneaking sympathy for those who upgrade
  322.      * no software before its time). -- TRW
  323.      */
  324.    
  325. #ifdef KERN_PROCARGS2
  326.    
  327.     /*
  328.      * The following is pretty much verbatim from module print.c of the
  329.      * Panther version of the ps command. Specifically, it's from
  330.      * adv_cmds-63. But the calling sequence has been modified for our
  331.      * convenience. Specifically, the global variable eflg has been made
  332.      * into an argument. -- TRW
  333.      */
  334.    
  335.     /*
  336.      * Get command and arguments.
  337.      *
  338.      * If the global variable eflg is non-zero and the user has permission to view
  339.      * the process's environment, the environment is included.
  340.      */
  341.     static void
  342.     getproclline(KINFO *k, char **command_name, int *cmdlen, int eflg, int show_args)
  343.     {
  344.         int     mib[3], argmax, nargs, c = 0;
  345.         size_t      size;
  346.         char        *procargs, *sp, *np, *cp;
  347.         /*  Made into a command argument. -- TRW
  348.          *  extern int  eflg;
  349.          */
  350.        
  351.         /* Get the maximum process arguments size. */
  352.         mib[0] = CTL_KERN;
  353.         mib[1] = KERN_ARGMAX;
  354.        
  355.         size = sizeof(argmax);
  356.         if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) {
  357.             goto ERROR_A;
  358.         }
  359.        
  360.         /* Allocate space for the arguments. */
  361.         procargs = (char *)malloc(argmax);
  362.         if (procargs == NULL) {
  363.             goto ERROR_A;
  364.         }
  365.        
  366.         /*
  367.          * Make a sysctl() call to get the raw argument space of the process.
  368.          * The layout is documented in start.s, which is part of the Csu
  369.          * project.  In summary, it looks like:
  370.          *
  371.          * /---------------\ 0x00000000
  372.          * :               :
  373.          * :               :
  374.          * |---------------|
  375.          * | argc          |
  376.          * |---------------|
  377.          * | arg[0]        |
  378.          * |---------------|
  379.          * :               :
  380.          * :               :
  381.          * |---------------|
  382.          * | arg[argc - 1] |
  383.          * |---------------|
  384.          * | 0             |
  385.          * |---------------|
  386.          * | env[0]        |
  387.          * |---------------|
  388.          * :               :
  389.          * :               :
  390.          * |---------------|
  391.          * | env[n]        |
  392.          * |---------------|
  393.          * | 0             |
  394.          * |---------------| <-- Beginning of data returned by sysctl() is here.
  395.          * | argc          |
  396.          * |---------------|
  397.          * | exec_path     |
  398.          * |:::::::::::::::|
  399.          * |               |
  400.          * | String area.  |
  401.          * |               |
  402.          * |---------------| <-- Top of stack.
  403.          * :               :
  404.          * :               :
  405.          * \---------------/ 0xffffffff
  406.          */
  407.         mib[0] = CTL_KERN;
  408.         mib[1] = KERN_PROCARGS2;
  409.         mib[2] = KI_PROC(k)->p_pid;
  410.        
  411.         size = (size_t)argmax;
  412.         if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) {
  413.             goto ERROR_B;
  414.         }
  415.        
  416.         memcpy(&nargs, procargs, sizeof(nargs));
  417.         cp = procargs + sizeof(nargs);
  418.        
  419.         /* Skip the saved exec_path. */
  420.         for (; cp < &procargs[size]; cp++) {
  421.             if (*cp == '\0') {
  422.                 /* End of exec_path reached. */
  423.                 break;
  424.             }
  425.         }
  426.         if (cp == &procargs[size]) {
  427.             goto ERROR_B;
  428.         }
  429.        
  430.         /* Skip trailing '\0' characters. */
  431.         for (; cp < &procargs[size]; cp++) {
  432.             if (*cp != '\0') {
  433.                 /* Beginning of first argument reached. */
  434.                 break;
  435.             }
  436.         }
  437.         if (cp == &procargs[size]) {
  438.             goto ERROR_B;
  439.         }
  440.         /* Save where the argv[0] string starts. */
  441.         sp = cp;
  442.        
  443.         /*
  444.          * Iterate through the '\0'-terminated strings and convert '\0' to ' '
  445.          * until a string is found that has a '=' character in it (or there are
  446.          * no more strings in procargs).  There is no way to deterministically
  447.          * know where the command arguments end and the environment strings
  448.          * start, which is why the '=' character is searched for as a heuristic.
  449.          */
  450.         for (np = NULL; c < nargs && cp < &procargs[size]; cp++) {
  451.             if (*cp == '\0') {
  452.                 c++;
  453.                 if (np != NULL) {
  454.                     /* Convert previous '\0'. */
  455.                     *np = ' ';
  456.                 }
  457.                 /* Note location of current '\0'. */
  458.                 np = cp;
  459.                
  460.                 if (!show_args) {
  461.                     /*
  462.                      * Don't convert '\0' characters to ' '.
  463.                      * However, we needed to know that the
  464.                      * command name was terminated, which we
  465.                      * now know.
  466.                      */
  467.                     break;
  468.                 }
  469.             }
  470.         }
  471.        
  472.         /*
  473.          * If eflg is non-zero, continue converting '\0' characters to ' '
  474.          * characters until no more strings that look like environment settings
  475.          * follow.
  476.          */
  477.         if ( (eflg != 0) && ( (getuid() == 0) || (KI_EPROC(k)->e_pcred.p_ruid == getuid()) ) ) {
  478.             for (; cp < &procargs[size]; cp++) {
  479.                 if (*cp == '\0') {
  480.                     if (np != NULL) {
  481.                         if (&np[1] == cp) {
  482.                             /*
  483.                              * Two '\0' characters in a row.
  484.                              * This should normally only
  485.                              * happen after all the strings
  486.                              * have been seen, but in any
  487.                              * case, stop parsing.
  488.                              */
  489.                             break;
  490.                         }
  491.                         /* Convert previous '\0'. */
  492.                         *np = ' ';
  493.                     }
  494.                     /* Note location of current '\0'. */
  495.                     np = cp;
  496.                 }
  497.             }
  498.         }
  499.        
  500.         /*
  501.          * sp points to the beginning of the arguments/environment string, and
  502.          * np should point to the '\0' terminator for the string.
  503.          */
  504.         if (np == NULL || np == sp) {
  505.             /* Empty or unterminated string. */
  506.             goto ERROR_B;
  507.         }
  508.        
  509.         /* Make a copy of the string. */
  510.         *cmdlen = asprintf(command_name, "%s", sp);
  511.        
  512.         /* Clean up. */
  513.         free(procargs);
  514.         return;
  515.        
  516.     ERROR_B:
  517.         free(procargs);
  518.     ERROR_A:
  519.         *cmdlen = asprintf(command_name, "(%s)", KI_PROC(k)->p_comm);
  520.     }
  521.    
  522.    
  523. #else   /* #ifdef KERN_PROCARGS2 */
  524.    
  525.     /*
  526.      * The following code is pretty much verbatim from module print.c of
  527.      * the ps command. The version of print.c is unknown. It is identical
  528.      * to, but certainly earlier than, the version in adv_cmds-46, which
  529.      * is the most recent version that goes with Jaguar. The calling
  530.      * sequence has been modified to pass eflg as an argument (rather than
  531.      * a global variable), and to be the same as the Panther version. Also,
  532.      * some band-aid code has been inserted late in the module to cover an
  533.      * apparent bug. The Panther version of this subroutine was completely
  534.      * rewritten, and uses a different sysctl funtion. -- TRW.
  535.      */
  536.     static void getproclline (KINFO *k, char ** command_name, int *cmdlen,
  537.                               int eflg, int show_args)
  538.     /* show_args = 1, display environment; 0 = don't. */
  539.     {
  540.        
  541.         /*
  542.          *  Get command and arguments.
  543.          */
  544.         int     command_length;
  545.         char * cmdpath;
  546.         volatile int    *ip, *savedip;
  547.         volatile char   *cp;
  548.         int     nbad;
  549.         char        c;
  550.         char        *end_argc;
  551.         int         mib[4];
  552.         char *      arguments;
  553.         size_t      arguments_size = 4096;
  554.         int         len=0;
  555.         volatile unsigned int *valuep;
  556.         unsigned int value;
  557.         int blahlen=0, skiplen=0;
  558.        
  559.         /* A sysctl() is made to find out the full path that the command
  560.          was called with.
  561.          */
  562.        
  563.         *command_name = NULL;
  564.         *cmdlen = 0;
  565.        
  566.         mib[0] = CTL_KERN;
  567.         mib[1] = KERN_PROCARGS;
  568.         mib[2] = KI_PROC(k)->p_pid;
  569.         mib[3] = 0;
  570.        
  571.         arguments = (char *) malloc(arguments_size);
  572.         if (sysctl(mib, 3, arguments, &arguments_size, NULL, 0) < 0) {
  573.             goto retucomm;
  574.         }
  575.         end_argc = &arguments[arguments_size];
  576.        
  577.         ip = (int *)end_argc;
  578.         ip -= 2;        /* last arg word and .long 0 */
  579.         while (*--ip)
  580.             if (ip == (int *)arguments)
  581.                 goto retucomm;
  582.        
  583.         savedip = ip;
  584.         savedip++;
  585.         cp = (char *)savedip;
  586.         while (*--ip)
  587.             if (ip == (int *)arguments)
  588.                 goto retucomm;
  589.         ip++;
  590.        
  591.         valuep = (unsigned int *)ip;
  592.         value = *valuep;
  593.         if ((value & 0xbfff0000) == 0xbfff0000) {
  594.             ip++;ip++;
  595.             valuep = ip;
  596.             blahlen = strlen((char *) ip);
  597.             skiplen = (blahlen +3 ) /4 ;
  598.             valuep += skiplen;
  599.             cp = (char *)valuep;
  600.             while (!*cp) {
  601.                 cp++;
  602.             }
  603.             savedip = (int *) cp;
  604.         }
  605.        
  606.         nbad = 0;
  607.        
  608.         for (cp = (char *)savedip; cp < (end_argc-1); cp++) {
  609.             c = *cp & 0177;
  610.             if (c == 0)
  611.                 *cp = ' ';
  612.             else if (c < ' ' || c > 0176) {
  613.                 if (++nbad >= 5*(eflg+1)) {
  614.                     *cp++ = ' ';
  615.                     break;
  616.                 }
  617.                 *cp = '?';
  618.             }
  619.             else if (eflg == 0 && c == '=') {
  620.                 while (*--cp != ' ')
  621.                     if (cp <= (char *)ip)
  622.                         break;
  623.                 break;
  624.             }
  625.         }
  626.        
  627.         *cp = 0;
  628. #if 0
  629.         while (*--cp == ' ')
  630.             *cp = 0;
  631. #endif
  632.         cp = (char *)savedip;
  633.         command_length = end_argc - cp; /* <= MAX_COMMAND_SIZE */
  634.        
  635.         if (cp[0] == '-' || cp[0] == '?' || cp[0] <= ' ') {
  636.             /*
  637.              *  Not enough information - add short command name
  638.              */
  639.             /*
  640.              *  I have a report of this section of the code failing under
  641.              *  Panther because command_length < 0. When Jaguar hits this
  642.              *  code it typically has a largeish value of command_length
  643.              *  (200 bytes plus). Both are clearly bogus, though in the
  644.              *  case of Panther, the problem is benign. The problem is
  645.              *  that Jaguar uses a completely different sysctl call to
  646.              *  get the data, so I can't simply use that code. The
  647.              *  print.c module of the ps command from adv_cmds_43 (the
  648.              *  latest Jaguar version) is identical to the one I based
  649.              *  this code on originally. So no help there. Until I can
  650.              *  figure something better, we'll just have to rely on this
  651.              *  band-aid. A possible way to proceed, once I upgrade to
  652.              *  Panther myself, is to conditionalize on the existence of
  653.              *  KERN_PROCARGS2 to decide which version of this subroutine
  654.              *  to use. Sigh. -- TRW
  655.              */
  656. #ifdef DEBUGGING
  657.             fprintf (stdout, "Debug - getproclline found short cmd; pid %d command_length %d\n",
  658.                      KI_PROC(k)->p_pid, command_length);
  659. #endif
  660.             if (command_length > 0) {
  661.                 len = ((unsigned)command_length + MAXCOMLEN + 5);
  662.                 cmdpath = (char *)malloc(len);
  663.                 (void) strncpy(cmdpath, (const char *) cp, command_length);
  664.                 (void) strcat(cmdpath, " (");
  665.                 (void) strncat(cmdpath, KI_PROC(k)->p_comm,
  666.                                MAXCOMLEN+1);
  667.                 (void) strcat(cmdpath, ")");
  668.                 *command_name = cmdpath;
  669.                 *cmdlen = len;
  670.             }
  671.             else {
  672.                 cmdpath = (char *)malloc(2);
  673.                 strncpy (cmdpath, "", 2);
  674.                 *command_name = cmdpath;
  675.                 *cmdlen = 0;
  676.             }
  677.             free(arguments);
  678.             return;
  679.         }
  680.         else {
  681.             cmdpath = (char *)malloc((unsigned)command_length + 1);
  682.             (void) strncpy(cmdpath, (const char *) cp, command_length);
  683.             cmdpath[command_length] = '\0';
  684.             *command_name = cmdpath;
  685.             *cmdlen = command_length;
  686.             free(arguments);
  687.             return;
  688.         }
  689.        
  690.     retucomm:
  691.         len = (MAXCOMLEN + 5);
  692.         cmdpath = (char *)malloc(len);
  693.         (void) strcpy(cmdpath, " (");
  694.         (void) strncat(cmdpath, KI_PROC(k)->p_comm,
  695.                        MAXCOMLEN+1);
  696.         (void) strcat(cmdpath, ")");
  697.         *cmdlen = len;
  698.         *command_name = cmdpath;
  699.         free(arguments);
  700.         return;
  701.     }
  702.    
  703. #endif  /* #ifdef KERN_PROCARGS2 */
  704.    
  705.     static int mach_state_order (int s, long sleep_time);
  706.     static int thread_schedinfo (KINFO *ki, thread_port_t thread,
  707.                                  policy_t pol, void * buf);
  708.    
  709.     static int get_task_info (KINFO *ki)
  710.     {
  711.         kern_return_t       error;
  712.         unsigned int        info_count = TASK_BASIC_INFO_COUNT;
  713.         unsigned int        thread_info_count = THREAD_BASIC_INFO_COUNT;
  714.         pid_t               pid;
  715.         int j, err = 0;
  716.        
  717.         pid = KI_PROC(ki)->p_pid;
  718.         if (task_for_pid(mach_task_self(), pid, &ki->task) != KERN_SUCCESS) {
  719.             return(1);
  720.         }
  721.         info_count = TASK_BASIC_INFO_COUNT;
  722.         error = task_info(ki->task, TASK_BASIC_INFO, (task_info_t) &ki->tasks_info, &info_count);
  723.         if (error != KERN_SUCCESS) {
  724.             ki->invalid_tinfo=1;
  725. #ifdef DEBUG
  726.             mach_error("Error calling task_info()", error);
  727. #endif
  728.             return(1);
  729.         }
  730.         {
  731.             vm_region_basic_info_data_64_t  b_info;
  732.             vm_address_t                    address = GLOBAL_SHARED_TEXT_SEGMENT;
  733.             vm_size_t                   size;
  734.             mach_port_t                 object_name;
  735.            
  736.             //
  737.             //try to determine if this task has the split libraries
  738.             //mapped in... if so, adjust its virtual size down by
  739.             //the 2 segments that are used for split libraries
  740.             //
  741.             info_count = VM_REGION_BASIC_INFO_COUNT_64;
  742.             error = vm_region_64(ki->task, &address, &size, VM_REGION_BASIC_INFO,
  743.                                  (vm_region_info_t)&b_info, &info_count, &object_name);
  744.             if (error == KERN_SUCCESS) {
  745.                 if (b_info.reserved && size == (SHARED_TEXT_REGION_SIZE) &&
  746.                     ki->tasks_info.virtual_size > (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE))
  747.                     ki->tasks_info.virtual_size -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE);
  748.             }
  749.         }
  750.         info_count = TASK_THREAD_TIMES_INFO_COUNT;
  751.         error = task_info(ki->task, TASK_THREAD_TIMES_INFO, (task_info_t) &ki->times, &info_count);
  752.         if (error != KERN_SUCCESS) {
  753.             ki->invalid_tinfo=1;
  754. #ifdef DEBUG
  755.             mach_error("Error calling task_info()", error);
  756. #endif
  757.             return(1);
  758.         }
  759.        
  760.         switch(ki->tasks_info.policy) {
  761.                
  762.             case POLICY_TIMESHARE :
  763.                 info_count = POLICY_TIMESHARE_INFO_COUNT;
  764.                 error = task_info(ki->task, TASK_SCHED_TIMESHARE_INFO, (task_info_t) &ki->schedinfo.tshare, &info_count);
  765.                 if (error != KERN_SUCCESS) {
  766.                     ki->invalid_tinfo=1;
  767. #ifdef DEBUG
  768.                     mach_error("Error calling task_info()", error);
  769. #endif
  770.                     return(1);
  771.                 }
  772.                
  773.                 ki->curpri = ki->schedinfo.tshare.cur_priority;
  774.                 ki->basepri = ki->schedinfo.tshare.base_priority;
  775.                 break;
  776.                
  777.             case POLICY_RR :
  778.                 info_count = POLICY_RR_INFO_COUNT;
  779.                 error = task_info(ki->task, TASK_SCHED_RR_INFO, (task_info_t) &ki->schedinfo.rr, &info_count);
  780.                 if (error != KERN_SUCCESS) {
  781.                     ki->invalid_tinfo=1;
  782. #ifdef DEBUG
  783.                     mach_error("Error calling task_info()", error);
  784. #endif
  785.                     return(1);
  786.                 }
  787.                
  788.                 ki->curpri = ki->schedinfo.rr.base_priority;
  789.                 ki->basepri = ki->schedinfo.rr.base_priority;
  790.                 break;
  791.                
  792.             case POLICY_FIFO :
  793.                 info_count = POLICY_FIFO_INFO_COUNT;
  794.                 error = task_info(ki->task, TASK_SCHED_FIFO_INFO, (task_info_t) &ki->schedinfo.fifo, &info_count);
  795.                 if (error != KERN_SUCCESS) {
  796.                     ki->invalid_tinfo=1;
  797. #ifdef DEBUG
  798.                     mach_error("Error calling task_info()", error);
  799. #endif
  800.                     return(1);
  801.                 }
  802.                
  803.                 ki->curpri = ki->schedinfo.fifo.base_priority;
  804.                 ki->basepri = ki->schedinfo.fifo.base_priority;
  805.                 break;
  806.         }
  807.        
  808.         ki->invalid_tinfo=0;
  809.        
  810.         ki->cpu_usage=0;
  811.         error = task_threads(ki->task, &ki->thread_list, &ki->thread_count);
  812.         if (error != KERN_SUCCESS) {
  813.             mach_port_deallocate(mach_task_self(),ki->task);
  814. #ifdef DEBUG
  815.             mach_error("Call to task_threads() failed", error);
  816. #endif
  817.             return(1);
  818.         }
  819.         err=0;
  820.         ki->state = STATE_MAX;
  821.         //ki->curpri = 255;
  822.         //ki->basepri = 255;
  823.         ki->swapped = 1;
  824.         ki->thval = malloc(ki->thread_count * sizeof(struct thread_values));
  825.         if (ki->thval != NULL) {
  826.             for (j = 0; j < ki->thread_count; j++) {
  827.                 int tstate;
  828.                 thread_info_count = THREAD_BASIC_INFO_COUNT;
  829.                 error = thread_info(ki->thread_list[j], THREAD_BASIC_INFO,
  830.                                     (thread_info_t)&ki->thval[j].tb,
  831.                                     &thread_info_count);
  832.                 if (error != KERN_SUCCESS) {
  833. #ifdef DEBUG
  834.                     mach_error("Call to thread_info() failed", error);
  835. #endif
  836.                     err=1;
  837.                 }
  838.                 error = thread_schedinfo(ki, ki->thread_list[j],
  839.                                          ki->thval[j].tb.policy, &ki->thval[j].schedinfo);
  840.                 if (error != KERN_SUCCESS) {
  841. #ifdef DEBUG
  842.                     mach_error("Call to thread_info() failed", error);
  843. #endif
  844.                     err=1;
  845.                 }
  846.                 ki->cpu_usage += ki->thval[j].tb.cpu_usage;
  847.                 tstate = mach_state_order(ki->thval[j].tb.run_state,
  848.                                           ki->thval[j].tb.sleep_time);
  849.                 if (tstate < ki->state)
  850.                     ki->state = tstate;
  851.                 if ((ki->thval[j].tb.flags & TH_FLAGS_SWAPPED ) == 0)
  852.                     ki->swapped = 0;
  853.                 mach_port_deallocate(mach_task_self(),
  854.                                      ki->thread_list[j]);
  855.             }
  856.             free (ki->thval);
  857.             ki->thval = NULL;
  858.         }
  859.         ki->invalid_thinfo = err;
  860.         // Deallocate the list of threads.
  861.         error = vm_deallocate(mach_task_self(),
  862.                               (vm_address_t)(ki->thread_list),
  863.                               sizeof(thread_port_array_t) * ki->thread_count);
  864.         if (error != KERN_SUCCESS) {
  865. #ifdef DEBUG
  866.             mach_error("Trouble freeing thread_list", error);
  867. #endif
  868.         }
  869.        
  870.         mach_port_deallocate(mach_task_self(),ki->task);
  871.         return(0);        
  872.     }
  873.    
  874.     static int mach_state_order (int s, long sleep_time)
  875.     {      
  876.         switch (s) {
  877.             case TH_STATE_RUNNING:      return(1);
  878.             case TH_STATE_UNINTERRUPTIBLE:
  879.                 return(2);
  880.             case TH_STATE_WAITING:      return((sleep_time > 20) ? 4 : 3);
  881.             case TH_STATE_STOPPED:      return(5);
  882.             case TH_STATE_HALTED:       return(6);  
  883.             default:                    return(7);
  884.         }
  885.     }
  886.    
  887.     static int thread_schedinfo (KINFO *ki, thread_port_t thread,
  888.                                  policy_t pol, void * buf)
  889.     {
  890.         unsigned int        count;
  891.         int ret = KERN_FAILURE;
  892.        
  893.         switch (pol) {
  894.                
  895.             case POLICY_TIMESHARE:
  896.                 count = POLICY_TIMESHARE_INFO_COUNT;
  897.                 ret = thread_info(thread, THREAD_SCHED_TIMESHARE_INFO,
  898.                                   (thread_info_t)buf, &count);
  899.                 if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_timeshare_info *)buf)->cur_priority)))
  900.                     ki->curpri  = ((struct policy_timeshare_info *)buf)->cur_priority;
  901.                 break;
  902.                
  903.             case POLICY_FIFO:
  904.                 count = POLICY_FIFO_INFO_COUNT;
  905.                 ret = thread_info(thread, THREAD_SCHED_FIFO_INFO,
  906.                                   buf, &count);
  907.                 if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_fifo_info *)buf)->base_priority)))
  908.                     ki->curpri  = ((struct policy_fifo_info *)buf)->base_priority;
  909.                 break;
  910.                
  911.             case POLICY_RR:
  912.                 count = POLICY_RR_INFO_COUNT;
  913.                 ret = thread_info(thread, THREAD_SCHED_RR_INFO,
  914.                                   buf, &count);
  915.                 if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_rr_info *)buf)->base_priority)))
  916.                     ki->curpri  = ((struct policy_rr_info *)buf)->base_priority;
  917.                 break;
  918.         }
  919.         return(ret);
  920.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement