| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | #ifndef _GNU_SOURCE | 
| 2 |  |  |  |  |  |  | #define _GNU_SOURCE    /* for canonicalize_file_name */ | 
| 3 |  |  |  |  |  |  | #endif | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | #include       /* is_digit */ | 
| 6 |  |  |  |  |  |  | #include      /* opendir, readdir_r */ | 
| 7 |  |  |  |  |  |  | #include | 
| 8 |  |  |  |  |  |  | #include     /* BOOL */ | 
| 9 |  |  |  |  |  |  | #include       /* *scanf family */ | 
| 10 |  |  |  |  |  |  | #include      /* malloc family */ | 
| 11 |  |  |  |  |  |  | #include      /* strchr */ | 
| 12 |  |  |  |  |  |  | #include        /* time_t */ | 
| 13 |  |  |  |  |  |  | #include | 
| 14 |  |  |  |  |  |  | #include | 
| 15 |  |  |  |  |  |  | #include | 
| 16 |  |  |  |  |  |  | #include     /* statfs */ | 
| 17 |  |  |  |  |  |  | /* glibc only goodness */ | 
| 18 |  |  |  |  |  |  | #include     /* glibc's handy obstacks */ | 
| 19 |  |  |  |  |  |  | /* pthreads */ | 
| 20 |  |  |  |  |  |  | #include     /* pthread_once */ | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | #define obstack_chunk_alloc    malloc | 
| 23 |  |  |  |  |  |  | #define obstack_chunk_free     free | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | #include "os/Linux.h" | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | /* NOTE: Before this was actually milliseconds even though it said microseconds, now it is correct. */ | 
| 28 |  |  |  |  |  |  | #define JIFFIES_TO_MICROSECONDS(x)    (((x) * 1e6) / system_hertz) | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | /* some static values that won't change, */ | 
| 31 |  |  |  |  |  |  | static pthread_once_t globals_init = PTHREAD_ONCE_INIT; | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | static long long          boot_time; | 
| 34 |  |  |  |  |  |  | static unsigned           page_size; | 
| 35 |  |  |  |  |  |  | static unsigned long long system_memory; | 
| 36 |  |  |  |  |  |  | static unsigned           system_hertz; | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | static bool init_failed = false; | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | /* get_string() | 
| 42 |  |  |  |  |  |  | * | 
| 43 |  |  |  |  |  |  | * Access strings in read only section | 
| 44 |  |  |  |  |  |  | * | 
| 45 |  |  |  |  |  |  | * @param   elem    String we want to retrive (look at enum strings) | 
| 46 |  |  |  |  |  |  | * @return  Address of string | 
| 47 |  |  |  |  |  |  | */ | 
| 48 | 106 |  |  |  |  |  | inline static const char *get_string(int elem) | 
| 49 |  |  |  |  |  |  | { | 
| 50 | 106 |  |  |  |  |  | return strings + strings_index[elem]; | 
| 51 |  |  |  |  |  |  | } | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | /* init_static_vars() | 
| 54 |  |  |  |  |  |  | * | 
| 55 |  |  |  |  |  |  | * Called by pthread_once to initialize global variables (system settings that don't change) | 
| 56 |  |  |  |  |  |  | */ | 
| 57 | 3 |  |  |  |  |  | static void init_static_vars() | 
| 58 |  |  |  |  |  |  | { | 
| 59 |  |  |  |  |  |  | struct obstack mem_pool; | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | char *file_text, *file_off; | 
| 62 |  |  |  |  |  |  | off_t file_len; | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | unsigned long long total_memory; | 
| 65 |  |  |  |  |  |  |  | 
| 66 | 3 |  |  |  |  |  | boot_time     = -1; | 
| 67 | 3 |  |  |  |  |  | system_memory = -1; | 
| 68 |  |  |  |  |  |  |  | 
| 69 | 3 |  |  |  |  |  | page_size = getpagesize(); | 
| 70 |  |  |  |  |  |  |  | 
| 71 |  |  |  |  |  |  | /* initilize our mem stack, tempoary memory */ | 
| 72 | 3 |  |  |  |  |  | obstack_init(&mem_pool); | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | /* find hertz size, I'm hoping this is gotten from elf note AT_CLKTCK */ | 
| 75 | 3 |  |  |  |  |  | system_hertz = sysconf(_SC_CLK_TCK); | 
| 76 |  |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  | /* find boot time */ | 
| 78 |  |  |  |  |  |  | /* read /proc/stat in */ | 
| 79 | 3 | 50 |  |  |  |  | if((file_text = read_file("stat", NULL, &file_len, &mem_pool)) == NULL) { | 
| 80 | 0 |  |  |  |  |  | goto fail; | 
| 81 |  |  |  |  |  |  | } | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | /* look for the line that starts with btime | 
| 84 |  |  |  |  |  |  | * NOTE: incrementing file_off after strchr is legal because file_text will | 
| 85 |  |  |  |  |  |  | *       be null terminated, so worst case after '\n' there will be '\0' and | 
| 86 |  |  |  |  |  |  | *       strncmp will fail or sscanf won't return 1 | 
| 87 |  |  |  |  |  |  | *       Only increment on the first line */ | 
| 88 | 60 | 50 |  |  |  |  | for(file_off = file_text; file_off; file_off = strchr(file_off, '\n')) { | 
| 89 | 60 | 100 |  |  |  |  | if(file_off != file_text) { | 
| 90 | 57 |  |  |  |  |  | file_off++; | 
| 91 |  |  |  |  |  |  | } | 
| 92 |  |  |  |  |  |  |  | 
| 93 | 60 | 100 |  |  |  |  | if(strncmp(file_off, "btime", 5) == 0) { | 
| 94 | 3 | 50 |  |  |  |  | if(sscanf(file_off, "btime %lld", &boot_time) == 1) { | 
| 95 | 3 |  |  |  |  |  | break; | 
| 96 |  |  |  |  |  |  | } | 
| 97 |  |  |  |  |  |  | } | 
| 98 |  |  |  |  |  |  | } | 
| 99 |  |  |  |  |  |  |  | 
| 100 | 3 | 50 |  |  |  |  | obstack_free(&mem_pool, file_text); | 
|  |  | 50 |  |  |  |  |  | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | /* did we scrape the number of pages successfuly? */ | 
| 103 | 3 | 50 |  |  |  |  | if(boot_time == -1) { | 
| 104 | 0 |  |  |  |  |  | goto fail; | 
| 105 |  |  |  |  |  |  | } | 
| 106 |  |  |  |  |  |  |  | 
| 107 |  |  |  |  |  |  | /* find total number of system pages */ | 
| 108 |  |  |  |  |  |  | /* read /proc/meminfo */ | 
| 109 | 3 | 50 |  |  |  |  | if((file_text = read_file("meminfo", NULL, &file_len, &mem_pool)) == NULL) { | 
| 110 | 0 |  |  |  |  |  | goto fail; | 
| 111 |  |  |  |  |  |  | } | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | /* look for the line that starts with: MemTotal */ | 
| 114 | 3 | 50 |  |  |  |  | for(file_off = file_text; file_off; file_off = strchr(file_off, '\n')) { | 
| 115 | 3 | 50 |  |  |  |  | if(file_off != file_text) { | 
| 116 | 0 |  |  |  |  |  | file_off++; | 
| 117 |  |  |  |  |  |  | } | 
| 118 |  |  |  |  |  |  |  | 
| 119 | 3 | 50 |  |  |  |  | if(strncmp(file_off, "MemTotal:", 9) == 0) { | 
| 120 | 3 | 50 |  |  |  |  | if(sscanf(file_off, "MemTotal: %llu", &system_memory) == 1) { | 
| 121 | 3 |  |  |  |  |  | system_memory *= 1024; /* convert to bytes */ | 
| 122 | 3 |  |  |  |  |  | break; | 
| 123 |  |  |  |  |  |  | } | 
| 124 |  |  |  |  |  |  | } | 
| 125 |  |  |  |  |  |  | } | 
| 126 |  |  |  |  |  |  |  | 
| 127 | 3 | 50 |  |  |  |  | obstack_free(&mem_pool, file_text); | 
|  |  | 50 |  |  |  |  |  | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | /* did we scrape the number of pages successfuly? */ | 
| 130 | 3 | 50 |  |  |  |  | if(total_memory == -1) { | 
| 131 | 0 |  |  |  |  |  | goto fail; | 
| 132 |  |  |  |  |  |  | } | 
| 133 |  |  |  |  |  |  |  | 
| 134 |  |  |  |  |  |  | /* initialize system hertz value */ | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | /* cleanup */ | 
| 137 | 3 | 50 |  |  |  |  | obstack_free(&mem_pool, NULL); | 
|  |  | 0 |  |  |  |  |  | 
| 138 | 3 |  |  |  |  |  | return; | 
| 139 |  |  |  |  |  |  |  | 
| 140 |  |  |  |  |  |  | /* mark failure and cleanup allocated resources */ | 
| 141 |  |  |  |  |  |  | fail: | 
| 142 | 0 | 0 |  |  |  |  | obstack_free(&mem_pool, NULL); | 
|  |  | 0 |  |  |  |  |  | 
| 143 | 0 |  |  |  |  |  | init_failed = true; | 
| 144 |  |  |  |  |  |  | } | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | /* OS_initialize() | 
| 147 |  |  |  |  |  |  | * | 
| 148 |  |  |  |  |  |  | * Called by XS parts whenever Proc::ProcessTable::new is called | 
| 149 |  |  |  |  |  |  | * | 
| 150 |  |  |  |  |  |  | * NOTE: There's a const char* -> char* conversion that's evil, but can't fix | 
| 151 |  |  |  |  |  |  | * this without breaking the Proc::ProcessTable XS API. | 
| 152 |  |  |  |  |  |  | */ | 
| 153 | 3 |  |  |  |  |  | char *OS_initialize() | 
| 154 |  |  |  |  |  |  | { | 
| 155 |  |  |  |  |  |  | struct statfs sfs; | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  | /* did we already try to initilize before and fail, if pthrad_once only | 
| 158 |  |  |  |  |  |  | * let us flag a failure from the init function; behavor of longjmp is | 
| 159 |  |  |  |  |  |  | * undefined, so that avaue is out out of the question */ | 
| 160 | 3 | 50 |  |  |  |  | if(init_failed) { | 
| 161 | 0 |  |  |  |  |  | return (char *)get_string(STR_ERR_INIT); | 
| 162 |  |  |  |  |  |  | } | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | /* check if /proc is mounted, let this go before initializing globals (below), | 
| 165 |  |  |  |  |  |  | * since the missing /proc message might me helpful */ | 
| 166 | 3 | 50 |  |  |  |  | if(statfs("/proc", &sfs) == -1) { | 
| 167 | 0 |  |  |  |  |  | return (char *)get_string(STR_ERR_PROC_STATFS); | 
| 168 |  |  |  |  |  |  | } | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | /* one time initialization of some values that won't change */ | 
| 171 | 3 |  |  |  |  |  | pthread_once(&globals_init, init_static_vars); | 
| 172 |  |  |  |  |  |  |  | 
| 173 | 3 |  |  |  |  |  | return NULL; | 
| 174 |  |  |  |  |  |  | } | 
| 175 |  |  |  |  |  |  |  | 
| 176 | 583 |  |  |  |  |  | inline static void field_enable(char *format_str, enum field field) | 
| 177 |  |  |  |  |  |  | { | 
| 178 | 583 |  |  |  |  |  | format_str[field] = tolower(format_str[field]); | 
| 179 | 583 |  |  |  |  |  | } | 
| 180 |  |  |  |  |  |  |  | 
| 181 | 212 |  |  |  |  |  | inline static void field_enable_range(char *format_str, enum field field1, | 
| 182 |  |  |  |  |  |  | enum field field2) | 
| 183 |  |  |  |  |  |  | { | 
| 184 |  |  |  |  |  |  | int i; | 
| 185 |  |  |  |  |  |  |  | 
| 186 | 1696 | 100 |  |  |  |  | for(i = field1; i <= field2; i++) { | 
| 187 | 1484 |  |  |  |  |  | format_str[i] = tolower(format_str[i]); | 
| 188 |  |  |  |  |  |  | } | 
| 189 | 212 |  |  |  |  |  | } | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | /* proc_pid_file() | 
| 192 |  |  |  |  |  |  | * | 
| 193 |  |  |  |  |  |  | * Build a path to the pid directory in proc '/proc/${pid}' with an optional | 
| 194 |  |  |  |  |  |  | * relative path at the end. Put the resultant path on top of the obstack. | 
| 195 |  |  |  |  |  |  | * | 
| 196 |  |  |  |  |  |  | * @return  Address of the create path string. | 
| 197 |  |  |  |  |  |  | */ | 
| 198 | 430 |  |  |  |  |  | inline static char *proc_pid_file(const char *pid, const char *file, | 
| 199 |  |  |  |  |  |  | struct obstack *mem_pool) | 
| 200 |  |  |  |  |  |  | { | 
| 201 |  |  |  |  |  |  | /* path to dir */ | 
| 202 | 430 |  |  |  |  |  | obstack_printf(mem_pool, "/proc/%s", pid); | 
| 203 |  |  |  |  |  |  |  | 
| 204 |  |  |  |  |  |  | /* additional path (not just the dir) */ | 
| 205 | 430 | 100 |  |  |  |  | if(file) { | 
| 206 | 371 |  |  |  |  |  | obstack_printf(mem_pool, "/%s", file); | 
| 207 |  |  |  |  |  |  | } | 
| 208 |  |  |  |  |  |  |  | 
| 209 | 430 | 50 |  |  |  |  | obstack_1grow(mem_pool, '\0'); | 
| 210 |  |  |  |  |  |  |  | 
| 211 | 430 | 50 |  |  |  |  | return (char *)obstack_finish(mem_pool); | 
|  |  | 50 |  |  |  |  |  | 
| 212 |  |  |  |  |  |  | } | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | /* read_file() | 
| 215 |  |  |  |  |  |  | * | 
| 216 |  |  |  |  |  |  | * Reads the contents of a file using an obstack for memory. It can read files like | 
| 217 |  |  |  |  |  |  | * /proc/stat or /proc/${pid}/stat. | 
| 218 |  |  |  |  |  |  | * | 
| 219 |  |  |  |  |  |  | * @param   path        String representing the part following /proc (usualy this is | 
| 220 |  |  |  |  |  |  | *                      the process pid number) | 
| 221 |  |  |  |  |  |  | * @param   extra_path  Path to the file to read in (relative to /proc/${path}/) | 
| 222 |  |  |  |  |  |  | * @param   len         Pointer to the value where the length will be saved | 
| 223 |  |  |  |  |  |  | * | 
| 224 |  |  |  |  |  |  | * @return  Pointer to a null terminate string allocated on the obstack, or | 
| 225 |  |  |  |  |  |  | *          NULL when it fails (doesn't clean up the obstack). | 
| 226 |  |  |  |  |  |  | */ | 
| 227 | 271 |  |  |  |  |  | static char *read_file(const char *path, const char *extra_path, | 
| 228 |  |  |  |  |  |  | off_t *len, struct obstack *mem_pool) | 
| 229 |  |  |  |  |  |  | { | 
| 230 | 271 |  |  |  |  |  | int   fd, result = -1; | 
| 231 |  |  |  |  |  |  | char *text, *file, *start; | 
| 232 |  |  |  |  |  |  |  | 
| 233 |  |  |  |  |  |  | /* build the filename in our tempoary storage */ | 
| 234 | 271 |  |  |  |  |  | file = proc_pid_file(path, extra_path, mem_pool); | 
| 235 |  |  |  |  |  |  |  | 
| 236 | 271 |  |  |  |  |  | fd = open(file, O_RDONLY); | 
| 237 |  |  |  |  |  |  |  | 
| 238 |  |  |  |  |  |  | /* free tmp memory we allocated for the file contents, this way we are not | 
| 239 |  |  |  |  |  |  | * poluting the obstack and the only thing left on it is the file */ | 
| 240 | 271 | 50 |  |  |  |  | obstack_free(mem_pool, file); | 
|  |  | 50 |  |  |  |  |  | 
| 241 |  |  |  |  |  |  |  | 
| 242 | 271 | 50 |  |  |  |  | if(fd == -1) { | 
| 243 | 0 |  |  |  |  |  | return NULL; | 
| 244 |  |  |  |  |  |  | } | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | /* read file into our buffer */ | 
| 247 | 883 | 100 |  |  |  |  | for(*len = 0; result; *len += result) { | 
| 248 | 612 | 100 |  |  |  |  | obstack_blank(mem_pool, 1024); | 
| 249 | 612 |  |  |  |  |  | start = obstack_base(mem_pool) + *len; | 
| 250 |  |  |  |  |  |  |  | 
| 251 | 612 | 50 |  |  |  |  | if((result = read(fd, start, 1024)) == -1) { | 
| 252 | 0 | 0 |  |  |  |  | obstack_free(mem_pool, obstack_finish(mem_pool)); | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 253 | 0 |  |  |  |  |  | close(fd); | 
| 254 | 0 |  |  |  |  |  | return NULL; | 
| 255 |  |  |  |  |  |  | } | 
| 256 |  |  |  |  |  |  | } | 
| 257 |  |  |  |  |  |  |  | 
| 258 | 271 |  |  |  |  |  | start  = obstack_base(mem_pool) + *len; | 
| 259 | 271 |  |  |  |  |  | *start = '\0'; | 
| 260 |  |  |  |  |  |  |  | 
| 261 |  |  |  |  |  |  | /* finalize our text buffer */ | 
| 262 | 271 | 50 |  |  |  |  | text = obstack_finish(mem_pool); | 
|  |  | 50 |  |  |  |  |  | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | /* not bothering checking return value, because it's possible that the | 
| 265 |  |  |  |  |  |  | * process went away */ | 
| 266 | 271 |  |  |  |  |  | close(fd); | 
| 267 |  |  |  |  |  |  |  | 
| 268 | 271 |  |  |  |  |  | return text; | 
| 269 |  |  |  |  |  |  | } | 
| 270 |  |  |  |  |  |  |  | 
| 271 |  |  |  |  |  |  | /* get_user_info() | 
| 272 |  |  |  |  |  |  | * | 
| 273 |  |  |  |  |  |  | * Find the user/group id of the process | 
| 274 |  |  |  |  |  |  | * | 
| 275 |  |  |  |  |  |  | * @param   pid         String representing the pid | 
| 276 |  |  |  |  |  |  | * @param   prs         Data structure where to put the scraped values | 
| 277 |  |  |  |  |  |  | * @param   mem_pool    Obstack to use for temory storage | 
| 278 |  |  |  |  |  |  | */ | 
| 279 | 53 |  |  |  |  |  | static void get_user_info(char *pid, char *format_str, struct procstat *prs, | 
| 280 |  |  |  |  |  |  | struct obstack *mem_pool) | 
| 281 |  |  |  |  |  |  | { | 
| 282 |  |  |  |  |  |  | char *      path_pid; | 
| 283 |  |  |  |  |  |  | struct stat stat_pid; | 
| 284 |  |  |  |  |  |  | int         result; | 
| 285 |  |  |  |  |  |  |  | 
| 286 |  |  |  |  |  |  | /* (temp) /proc/${pid} */ | 
| 287 | 53 |  |  |  |  |  | path_pid = proc_pid_file(pid, NULL, mem_pool); | 
| 288 |  |  |  |  |  |  |  | 
| 289 | 53 |  |  |  |  |  | result = stat(path_pid, &stat_pid); | 
| 290 |  |  |  |  |  |  |  | 
| 291 | 53 | 50 |  |  |  |  | obstack_free(mem_pool, path_pid); | 
|  |  | 50 |  |  |  |  |  | 
| 292 |  |  |  |  |  |  |  | 
| 293 | 53 | 50 |  |  |  |  | if(result == -1) { | 
| 294 | 0 |  |  |  |  |  | return; | 
| 295 |  |  |  |  |  |  | } | 
| 296 |  |  |  |  |  |  |  | 
| 297 | 53 |  |  |  |  |  | prs->uid = stat_pid.st_uid; | 
| 298 | 53 |  |  |  |  |  | prs->gid = stat_pid.st_gid; | 
| 299 |  |  |  |  |  |  |  | 
| 300 | 53 |  |  |  |  |  | field_enable(format_str, F_UID); | 
| 301 | 53 |  |  |  |  |  | field_enable(format_str, F_GID); | 
| 302 |  |  |  |  |  |  | } | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | /* get_proc_stat() | 
| 305 |  |  |  |  |  |  | * | 
| 306 |  |  |  |  |  |  | * Reads a processes stat file in the proc filesystem '/proc/${pid}/stat' and | 
| 307 |  |  |  |  |  |  | * fills the procstat structure with the values. | 
| 308 |  |  |  |  |  |  | * | 
| 309 |  |  |  |  |  |  | * @param   pid         String representing the pid | 
| 310 |  |  |  |  |  |  | * @param   prs         Data structure where to put the scraped values | 
| 311 |  |  |  |  |  |  | * @param   mem_pool    Obstack to use for temory storage | 
| 312 |  |  |  |  |  |  | */ | 
| 313 | 53 |  |  |  |  |  | static bool get_proc_stat(char *pid, char *format_str, struct procstat *prs, | 
| 314 |  |  |  |  |  |  | struct obstack *mem_pool) | 
| 315 |  |  |  |  |  |  | { | 
| 316 |  |  |  |  |  |  | char *stat_text, *stat_cont, *close_paren, *open_paren; | 
| 317 |  |  |  |  |  |  | int   result; | 
| 318 |  |  |  |  |  |  | off_t stat_len; | 
| 319 |  |  |  |  |  |  | long  dummy_l; | 
| 320 |  |  |  |  |  |  | int   dummy_i; | 
| 321 |  |  |  |  |  |  |  | 
| 322 | 53 |  |  |  |  |  | bool read_ok = true; | 
| 323 |  |  |  |  |  |  |  | 
| 324 | 53 | 50 |  |  |  |  | if((stat_text = read_file(pid, "stat", &stat_len, mem_pool)) == NULL) { | 
| 325 | 0 |  |  |  |  |  | return false; | 
| 326 |  |  |  |  |  |  | } | 
| 327 |  |  |  |  |  |  |  | 
| 328 | 53 | 50 |  |  |  |  | if(sscanf(stat_text, "%d (", &prs->pid) != 1) { | 
| 329 | 0 |  |  |  |  |  | goto done; | 
| 330 |  |  |  |  |  |  | } | 
| 331 |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  | /* replace the first ')' with a '\0', the contents look like this: | 
| 333 |  |  |  |  |  |  | *    pid (program_name) state ... | 
| 334 |  |  |  |  |  |  | * if we don't find ')' then it's incorrectly formated */ | 
| 335 | 53 | 50 |  |  |  |  | if((close_paren = strrchr(stat_text, ')')) == NULL) { | 
| 336 | 0 |  |  |  |  |  | read_ok = false; | 
| 337 | 0 |  |  |  |  |  | goto done; | 
| 338 |  |  |  |  |  |  | } | 
| 339 | 53 |  |  |  |  |  | *close_paren = '\0'; | 
| 340 |  |  |  |  |  |  |  | 
| 341 | 53 | 50 |  |  |  |  | if((open_paren = strchr(stat_text, '(')) == NULL) { | 
| 342 | 0 |  |  |  |  |  | read_ok = false; | 
| 343 | 0 |  |  |  |  |  | goto done; | 
| 344 |  |  |  |  |  |  | } | 
| 345 |  |  |  |  |  |  |  | 
| 346 |  |  |  |  |  |  |  | 
| 347 | 53 |  |  |  |  |  | int comm_esize = sizeof(prs->comm) - 1; | 
| 348 | 53 |  |  |  |  |  | int comm_len   = close_paren - open_paren - 1; | 
| 349 |  |  |  |  |  |  |  | 
| 350 | 53 | 50 |  |  |  |  | if(comm_len > comm_esize) { | 
| 351 | 0 |  |  |  |  |  | comm_len = comm_esize; | 
| 352 |  |  |  |  |  |  | } | 
| 353 | 53 | 50 |  |  |  |  | if(comm_len > 0) { | 
| 354 | 53 |  |  |  |  |  | strncpy(prs->comm, open_paren + 1, comm_esize); | 
| 355 | 53 |  |  |  |  |  | prs->comm[comm_esize] = '\0'; | 
| 356 |  |  |  |  |  |  | } | 
| 357 |  |  |  |  |  |  |  | 
| 358 |  |  |  |  |  |  |  | 
| 359 |  |  |  |  |  |  | /* address at which we pickup again, after the ')' | 
| 360 |  |  |  |  |  |  | * NOTE: we don't bother checking bounds since strchr didn't return NULL | 
| 361 |  |  |  |  |  |  | * thus the NULL terminator will be at least close_paren+1, which is ok */ | 
| 362 | 53 |  |  |  |  |  | stat_cont = close_paren + 1; | 
| 363 |  |  |  |  |  |  |  | 
| 364 |  |  |  |  |  |  | /* scrape the remaining values */ | 
| 365 | 53 |  |  |  |  |  | result = sscanf(stat_cont, | 
| 366 |  |  |  |  |  |  | " %c"                        /*  state */ | 
| 367 |  |  |  |  |  |  | " %d"                        /*  ppid */ | 
| 368 |  |  |  |  |  |  | " %d"                        /*  pgrp */ | 
| 369 |  |  |  |  |  |  | " %d"                        /*  sid */ | 
| 370 |  |  |  |  |  |  | " %d"                        /*  tty */ | 
| 371 |  |  |  |  |  |  | " %d"                        /*  tty_pgid (dummy) */ | 
| 372 |  |  |  |  |  |  | " %u"                        /*  flags */ | 
| 373 |  |  |  |  |  |  | " %lu"                       /* minflt */ | 
| 374 |  |  |  |  |  |  | " %lu"                       /* cminflt */ | 
| 375 |  |  |  |  |  |  | " %lu"                       /* majflt */ | 
| 376 |  |  |  |  |  |  | " %lu"                       /* cmajflt */ | 
| 377 |  |  |  |  |  |  | " %llu"                      /* utime */ | 
| 378 |  |  |  |  |  |  | " %llu"                      /* stime */ | 
| 379 |  |  |  |  |  |  | " %llu"                      /* cutime */ | 
| 380 |  |  |  |  |  |  | " %lld"                      /* cstime */ | 
| 381 |  |  |  |  |  |  | " %ld"                       /* priority */ | 
| 382 |  |  |  |  |  |  | " %ld"                       /* nice (dummy) */ | 
| 383 |  |  |  |  |  |  | " %ld"                       /* num_threads (dummy) */ | 
| 384 |  |  |  |  |  |  | " %d"                        /* itrealvalue (dummy) */ | 
| 385 |  |  |  |  |  |  | " %llu"                      /* start_time */ | 
| 386 |  |  |  |  |  |  | " %lu"                       /* vsize */ | 
| 387 |  |  |  |  |  |  | " %ld"                       /* rss */ | 
| 388 |  |  |  |  |  |  | " %ld"                       /* rsslim */ | 
| 389 |  |  |  |  |  |  | " %lu"                       /* start_code (dummy) */ | 
| 390 |  |  |  |  |  |  | " %lu"                       /* end_code (dummy) */ | 
| 391 |  |  |  |  |  |  | " %lu"                       /* start_stack (dummy) */ | 
| 392 |  |  |  |  |  |  | " %lu"                       /* esp (dummy) */ | 
| 393 |  |  |  |  |  |  | " %lu"                       /* eip (dummy) */ | 
| 394 |  |  |  |  |  |  | " %lu"                       /* pending (dummy) */ | 
| 395 |  |  |  |  |  |  | " %lu"                       /* blocked (dummy) */ | 
| 396 |  |  |  |  |  |  | " %lu"                       /* sigign (dummy) */ | 
| 397 |  |  |  |  |  |  | " %lu"                       /* sigcatch (dummy) */ | 
| 398 |  |  |  |  |  |  | " %lu"                       /* wchan (obsolete) */ | 
| 399 |  |  |  |  |  |  | , | 
| 400 |  |  |  |  |  |  | &prs->state_c,               /* %c */ | 
| 401 |  |  |  |  |  |  | &prs->ppid, &prs->pgrp,      /* %d %d */ | 
| 402 |  |  |  |  |  |  | &prs->sid,                   /* %d */ | 
| 403 |  |  |  |  |  |  | &prs->tty, &dummy_i,         /* tty, tty_pgid */ | 
| 404 |  |  |  |  |  |  | &prs->flags,                 /* %u */ | 
| 405 |  |  |  |  |  |  | &prs->minflt, &prs->cminflt, | 
| 406 |  |  |  |  |  |  | &prs->majflt, &prs->cmajflt, /* %lu %lu %lu %lu */ | 
| 407 |  |  |  |  |  |  | &prs->utime, &prs->stime, | 
| 408 |  |  |  |  |  |  | &prs->cutime, &prs->cstime, | 
| 409 |  |  |  |  |  |  | &prs->priority, | 
| 410 |  |  |  |  |  |  | &dummy_l,                       /* nice */ | 
| 411 |  |  |  |  |  |  | &dummy_l,                       /* num threads */ | 
| 412 |  |  |  |  |  |  | &dummy_i,                       /* timeout obsolete */ | 
| 413 |  |  |  |  |  |  | &prs->start_time, | 
| 414 |  |  |  |  |  |  | &prs->vsize, &prs->rss, | 
| 415 |  |  |  |  |  |  | &dummy_l, | 
| 416 |  |  |  |  |  |  | &dummy_l, &dummy_l, | 
| 417 |  |  |  |  |  |  | &dummy_l, | 
| 418 |  |  |  |  |  |  | &dummy_l, &dummy_l, | 
| 419 |  |  |  |  |  |  | &dummy_l, &dummy_l, &dummy_l, &dummy_l, | 
| 420 |  |  |  |  |  |  | &prs->wchan); | 
| 421 |  |  |  |  |  |  |  | 
| 422 |  |  |  |  |  |  | /* 33 items in scanf's list... It's all or nothing baby */ | 
| 423 | 53 | 50 |  |  |  |  | if(result != 33) { | 
| 424 | 0 |  |  |  |  |  | read_ok = false; | 
| 425 | 0 |  |  |  |  |  | goto done; | 
| 426 |  |  |  |  |  |  | } | 
| 427 |  |  |  |  |  |  |  | 
| 428 |  |  |  |  |  |  | /* enable fields; F_STATE is not the range */ | 
| 429 | 53 |  |  |  |  |  | field_enable_range(format_str, F_PID, F_WCHAN); | 
| 430 |  |  |  |  |  |  |  | 
| 431 |  |  |  |  |  |  | done: | 
| 432 | 53 | 50 |  |  |  |  | obstack_free(mem_pool, stat_text); | 
|  |  | 50 |  |  |  |  |  | 
| 433 | 53 |  |  |  |  |  | return read_ok; | 
| 434 |  |  |  |  |  |  | } | 
| 435 |  |  |  |  |  |  |  | 
| 436 | 106 |  |  |  |  |  | static void eval_link(char *pid, char *link_rel, enum field field, char **ptr, | 
| 437 |  |  |  |  |  |  | char *format_str, struct obstack *mem_pool) | 
| 438 |  |  |  |  |  |  | { | 
| 439 |  |  |  |  |  |  | char *link_file, *link; | 
| 440 |  |  |  |  |  |  |  | 
| 441 |  |  |  |  |  |  | /* path to the link file like. /proc/{pid}/{link_rel} */ | 
| 442 | 106 |  |  |  |  |  | link_file = proc_pid_file(pid, link_rel, mem_pool); | 
| 443 |  |  |  |  |  |  |  | 
| 444 |  |  |  |  |  |  | /* It's okay to use canonicalize_file_name instead of readlink on linux | 
| 445 |  |  |  |  |  |  | * for the cwd symlink, since on linux the links we care about will never | 
| 446 |  |  |  |  |  |  | * be relative links (cwd, exec) | 
| 447 |  |  |  |  |  |  | * Doing this because readlink works on static buffers */ | 
| 448 |  |  |  |  |  |  | /* canonicalize_file_name is no good for musl, use realpath instead */ | 
| 449 | 106 |  |  |  |  |  | link = realpath(link_file, NULL); | 
| 450 |  |  |  |  |  |  |  | 
| 451 |  |  |  |  |  |  | /* we no longer need need the path to the link file */ | 
| 452 | 106 | 50 |  |  |  |  | obstack_free(mem_pool, link_file); | 
|  |  | 50 |  |  |  |  |  | 
| 453 |  |  |  |  |  |  |  | 
| 454 | 106 | 50 |  |  |  |  | if(link == NULL) { | 
| 455 | 0 |  |  |  |  |  | return; | 
| 456 |  |  |  |  |  |  | } | 
| 457 |  |  |  |  |  |  |  | 
| 458 |  |  |  |  |  |  | /* copy the path onto our obstack, set the value (somewhere in pts) | 
| 459 |  |  |  |  |  |  | * and free the results of canonicalize_file_name */ | 
| 460 | 106 |  |  |  |  |  | obstack_printf(mem_pool, "%s", link); | 
| 461 | 106 | 50 |  |  |  |  | obstack_1grow(mem_pool, '\0'); | 
| 462 |  |  |  |  |  |  |  | 
| 463 | 106 | 50 |  |  |  |  | *ptr = (char *)obstack_finish(mem_pool); | 
|  |  | 50 |  |  |  |  |  | 
| 464 | 106 |  |  |  |  |  | free(link); | 
| 465 |  |  |  |  |  |  |  | 
| 466 |  |  |  |  |  |  | /* enable whatever field we successfuly retrived */ | 
| 467 | 106 |  |  |  |  |  | field_enable(format_str, field); | 
| 468 |  |  |  |  |  |  | } | 
| 469 |  |  |  |  |  |  |  | 
| 470 | 53 |  |  |  |  |  | static void get_proc_cmndline(char *pid, char *format_str, struct procstat *prs, | 
| 471 |  |  |  |  |  |  | struct obstack *mem_pool) | 
| 472 |  |  |  |  |  |  | { | 
| 473 |  |  |  |  |  |  | char *cmndline_text, *cur; | 
| 474 |  |  |  |  |  |  | off_t cmndline_off; | 
| 475 |  |  |  |  |  |  |  | 
| 476 | 53 | 50 |  |  |  |  | if((cmndline_text = read_file(pid, "cmdline", &cmndline_off, mem_pool)) == NULL) { | 
| 477 | 0 |  |  |  |  |  | return; | 
| 478 |  |  |  |  |  |  | } | 
| 479 |  |  |  |  |  |  |  | 
| 480 |  |  |  |  |  |  | /* replace all '\0' with spaces (except for the last one */ | 
| 481 | 7483 | 100 |  |  |  |  | for(cur = cmndline_text; cur < cmndline_text + cmndline_off - 1; cur++) { | 
| 482 | 7430 | 100 |  |  |  |  | if(*cur == '\0') { | 
| 483 | 342 |  |  |  |  |  | *cur = ' '; | 
| 484 |  |  |  |  |  |  | } | 
| 485 |  |  |  |  |  |  | } | 
| 486 |  |  |  |  |  |  |  | 
| 487 | 53 |  |  |  |  |  | prs->cmndline = cmndline_text; | 
| 488 | 53 |  |  |  |  |  | field_enable(format_str, F_CMNDLINE); | 
| 489 |  |  |  |  |  |  | } | 
| 490 |  |  |  |  |  |  |  | 
| 491 | 53 |  |  |  |  |  | static void get_proc_cmdline(char *pid, char *format_str, struct procstat *prs, | 
| 492 |  |  |  |  |  |  | struct obstack *mem_pool) | 
| 493 |  |  |  |  |  |  | { | 
| 494 |  |  |  |  |  |  | char *cmdline_text; | 
| 495 |  |  |  |  |  |  | off_t cmdline_off; | 
| 496 |  |  |  |  |  |  |  | 
| 497 | 53 | 50 |  |  |  |  | if((cmdline_text = read_file(pid, "cmdline", &cmdline_off, mem_pool)) == NULL) { | 
| 498 | 0 |  |  |  |  |  | return; | 
| 499 |  |  |  |  |  |  | } | 
| 500 |  |  |  |  |  |  |  | 
| 501 | 53 |  |  |  |  |  | prs->cmdline     = cmdline_text; | 
| 502 | 53 |  |  |  |  |  | prs->cmdline_len = cmdline_off; | 
| 503 | 53 |  |  |  |  |  | field_enable(format_str, F_CMDLINE); | 
| 504 |  |  |  |  |  |  | } | 
| 505 |  |  |  |  |  |  |  | 
| 506 | 53 |  |  |  |  |  | static void get_proc_environ(char *pid, char *format_str, struct procstat *prs, | 
| 507 |  |  |  |  |  |  | struct obstack *mem_pool) | 
| 508 |  |  |  |  |  |  | { | 
| 509 |  |  |  |  |  |  | char *environ_text; | 
| 510 |  |  |  |  |  |  | off_t environ_off; | 
| 511 |  |  |  |  |  |  |  | 
| 512 | 53 | 50 |  |  |  |  | if((environ_text = read_file(pid, "environ", &environ_off, mem_pool)) == NULL) { | 
| 513 | 0 |  |  |  |  |  | return; | 
| 514 |  |  |  |  |  |  | } | 
| 515 |  |  |  |  |  |  |  | 
| 516 | 53 |  |  |  |  |  | prs->environ     = environ_text; | 
| 517 | 53 |  |  |  |  |  | prs->environ_len = environ_off; | 
| 518 | 53 |  |  |  |  |  | field_enable(format_str, F_ENVIRON); | 
| 519 |  |  |  |  |  |  | } | 
| 520 |  |  |  |  |  |  |  | 
| 521 | 53 |  |  |  |  |  | static void get_proc_status(char *pid, char *format_str, struct procstat *prs, | 
| 522 |  |  |  |  |  |  | struct obstack *mem_pool) | 
| 523 |  |  |  |  |  |  | { | 
| 524 |  |  |  |  |  |  | char *status_text, *loc; | 
| 525 |  |  |  |  |  |  | off_t status_len; | 
| 526 |  |  |  |  |  |  | int   dummy_i; | 
| 527 |  |  |  |  |  |  |  | 
| 528 | 53 | 50 |  |  |  |  | if((status_text = read_file(pid, "status", &status_len, mem_pool)) == NULL) { | 
| 529 | 0 |  |  |  |  |  | return; | 
| 530 |  |  |  |  |  |  | } | 
| 531 |  |  |  |  |  |  |  | 
| 532 | 53 |  |  |  |  |  | loc = status_text; | 
| 533 |  |  |  |  |  |  |  | 
| 534 |  |  |  |  |  |  | /* | 
| 535 |  |  |  |  |  |  | * get the euid, egid and so on out of /proc/$$/status | 
| 536 |  |  |  |  |  |  | * where the 2 lines in which we are interested in are: | 
| 537 |  |  |  |  |  |  | * [5] Uid:    500     500     500     500 | 
| 538 |  |  |  |  |  |  | * [6] Gid:    500     500     500     500 | 
| 539 |  |  |  |  |  |  | * added by scip | 
| 540 |  |  |  |  |  |  | */ | 
| 541 |  |  |  |  |  |  |  | 
| 542 | 530 | 50 |  |  |  |  | for(loc = status_text; loc; loc = strchr(loc, '\n')) { | 
| 543 |  |  |  |  |  |  | /* skip past the \n character */ | 
| 544 | 530 | 100 |  |  |  |  | if(loc != status_text) { | 
| 545 | 477 |  |  |  |  |  | loc++; | 
| 546 |  |  |  |  |  |  | } | 
| 547 |  |  |  |  |  |  |  | 
| 548 | 530 | 100 |  |  |  |  | if(strncmp(loc, "Uid:", 4) == 0) { | 
| 549 | 53 |  |  |  |  |  | sscanf(loc + 4, " %d %d %d %d", &dummy_i, &prs->euid, &prs->suid, &prs->fuid); | 
| 550 | 53 |  |  |  |  |  | field_enable_range(format_str, F_EUID, F_FUID); | 
| 551 | 477 | 100 |  |  |  |  | } else if(strncmp(loc, "Gid:", 4) == 0) { | 
| 552 | 53 |  |  |  |  |  | sscanf(loc + 4, " %d %d %d %d", &dummy_i, &prs->egid, &prs->sgid, &prs->fgid); | 
| 553 | 53 |  |  |  |  |  | field_enable_range(format_str, F_EGID, F_FGID); | 
| 554 | 424 | 100 |  |  |  |  | } else if(strncmp(loc, "TracerPid:", 10) == 0) { | 
| 555 | 53 |  |  |  |  |  | sscanf(loc + 10, " %d", &prs->tracer); | 
| 556 | 53 |  |  |  |  |  | field_enable(format_str, F_TRACER); | 
| 557 |  |  |  |  |  |  | } | 
| 558 |  |  |  |  |  |  |  | 
| 559 |  |  |  |  |  |  | /* short circuit condition */ | 
| 560 | 530 | 100 |  |  |  |  | if(islower(format_str[F_EUID]) && islower(format_str[F_EGID]) && islower(format_str[F_TRACER])) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 561 | 53 |  |  |  |  |  | goto done; | 
| 562 |  |  |  |  |  |  | } | 
| 563 |  |  |  |  |  |  | } | 
| 564 |  |  |  |  |  |  |  | 
| 565 |  |  |  |  |  |  | done: | 
| 566 | 53 | 50 |  |  |  |  | obstack_free(mem_pool, status_text); | 
|  |  | 50 |  |  |  |  |  | 
| 567 |  |  |  |  |  |  | } | 
| 568 |  |  |  |  |  |  |  | 
| 569 |  |  |  |  |  |  | /* fixup_stat_values() | 
| 570 |  |  |  |  |  |  | * | 
| 571 |  |  |  |  |  |  | * Correct, calculate, covert values to user expected values. | 
| 572 |  |  |  |  |  |  | * | 
| 573 |  |  |  |  |  |  | * @param   format_str  String containing field index types | 
| 574 |  |  |  |  |  |  | * @param   prs         Data structure to peform fixups on | 
| 575 |  |  |  |  |  |  | */ | 
| 576 | 53 |  |  |  |  |  | static void fixup_stat_values(char *format_str, struct procstat *prs) | 
| 577 |  |  |  |  |  |  | { | 
| 578 |  |  |  |  |  |  | /* set the state pointer to the right (const) string */ | 
| 579 | 53 |  |  |  |  |  | switch(prs->state_c) { | 
| 580 |  |  |  |  |  |  | case 'S': | 
| 581 | 48 |  |  |  |  |  | prs->state = get_string(SLEEP); | 
| 582 | 48 |  |  |  |  |  | break; | 
| 583 |  |  |  |  |  |  |  | 
| 584 |  |  |  |  |  |  | case 'W': | 
| 585 | 0 |  |  |  |  |  | prs->state = get_string(WAIT);         /*Waking state.  Could be mapped to WAKING, but would break backward compatibility */ | 
| 586 | 0 |  |  |  |  |  | break; | 
| 587 |  |  |  |  |  |  |  | 
| 588 |  |  |  |  |  |  | case 'R': | 
| 589 | 5 |  |  |  |  |  | prs->state = get_string(RUN); | 
| 590 | 5 |  |  |  |  |  | break; | 
| 591 |  |  |  |  |  |  |  | 
| 592 |  |  |  |  |  |  | case 'I': | 
| 593 | 0 |  |  |  |  |  | prs->state = get_string(IDLE); | 
| 594 | 0 |  |  |  |  |  | break; | 
| 595 |  |  |  |  |  |  |  | 
| 596 |  |  |  |  |  |  | case 'Z': | 
| 597 | 0 |  |  |  |  |  | prs->state = get_string(DEFUNCT); | 
| 598 | 0 |  |  |  |  |  | break; | 
| 599 |  |  |  |  |  |  |  | 
| 600 |  |  |  |  |  |  | case 'D': | 
| 601 | 0 |  |  |  |  |  | prs->state = get_string(UWAIT); | 
| 602 | 0 |  |  |  |  |  | break; | 
| 603 |  |  |  |  |  |  |  | 
| 604 |  |  |  |  |  |  | case 'T': | 
| 605 |  |  |  |  |  |  | case 'H':       /* GNU Hurd HALTED state */ | 
| 606 | 0 |  |  |  |  |  | prs->state = get_string(STOP); | 
| 607 | 0 |  |  |  |  |  | break; | 
| 608 |  |  |  |  |  |  |  | 
| 609 |  |  |  |  |  |  | case 'x': | 
| 610 | 0 |  |  |  |  |  | prs->state = get_string(DEAD); | 
| 611 | 0 |  |  |  |  |  | break; | 
| 612 |  |  |  |  |  |  |  | 
| 613 |  |  |  |  |  |  | case 'X': | 
| 614 | 0 |  |  |  |  |  | prs->state = get_string(DEAD); | 
| 615 | 0 |  |  |  |  |  | break; | 
| 616 |  |  |  |  |  |  |  | 
| 617 |  |  |  |  |  |  | case 'K': | 
| 618 | 0 |  |  |  |  |  | prs->state = get_string(WAKEKILL); | 
| 619 | 0 |  |  |  |  |  | break; | 
| 620 |  |  |  |  |  |  |  | 
| 621 |  |  |  |  |  |  | case 't': | 
| 622 | 0 |  |  |  |  |  | prs->state = get_string(TRACINGSTOP); | 
| 623 | 0 |  |  |  |  |  | break; | 
| 624 |  |  |  |  |  |  |  | 
| 625 |  |  |  |  |  |  | case 'P': | 
| 626 | 0 |  |  |  |  |  | prs->state = get_string(PARKED); | 
| 627 | 0 |  |  |  |  |  | break; | 
| 628 |  |  |  |  |  |  |  | 
| 629 |  |  |  |  |  |  | /* unknown state, state is already set to NULL */ | 
| 630 |  |  |  |  |  |  | default: | 
| 631 | 0 |  |  |  |  |  | ppt_warn("Ran into unknown state (hex char: %x)", (int)prs->state_c); | 
| 632 | 0 |  |  |  |  |  | goto skip_state_format; | 
| 633 |  |  |  |  |  |  | } | 
| 634 |  |  |  |  |  |  |  | 
| 635 | 53 |  |  |  |  |  | field_enable(format_str, F_STATE); | 
| 636 |  |  |  |  |  |  |  | 
| 637 |  |  |  |  |  |  | skip_state_format: | 
| 638 |  |  |  |  |  |  |  | 
| 639 | 53 |  |  |  |  |  | prs->start_time = (prs->start_time / system_hertz) + boot_time; | 
| 640 |  |  |  |  |  |  |  | 
| 641 |  |  |  |  |  |  | /* fix time */ | 
| 642 |  |  |  |  |  |  |  | 
| 643 | 53 |  |  |  |  |  | prs->stime  = JIFFIES_TO_MICROSECONDS(prs->stime); | 
| 644 | 53 |  |  |  |  |  | prs->utime  = JIFFIES_TO_MICROSECONDS(prs->utime); | 
| 645 | 53 |  |  |  |  |  | prs->cstime = JIFFIES_TO_MICROSECONDS(prs->cstime); | 
| 646 | 53 |  |  |  |  |  | prs->cutime = JIFFIES_TO_MICROSECONDS(prs->cutime); | 
| 647 |  |  |  |  |  |  |  | 
| 648 |  |  |  |  |  |  | /* derived time values */ | 
| 649 | 53 |  |  |  |  |  | prs->time  = prs->utime + prs->stime; | 
| 650 | 53 |  |  |  |  |  | prs->ctime = prs->cutime + prs->cstime; | 
| 651 |  |  |  |  |  |  |  | 
| 652 | 53 |  |  |  |  |  | field_enable_range(format_str, F_TIME, F_CTIME); | 
| 653 |  |  |  |  |  |  |  | 
| 654 |  |  |  |  |  |  | /* fix rss to be in bytes (returned from kernel in pages) */ | 
| 655 | 53 |  |  |  |  |  | prs->rss *= page_size; | 
| 656 | 53 |  |  |  |  |  | } | 
| 657 |  |  |  |  |  |  |  | 
| 658 |  |  |  |  |  |  | /* calc_prec() | 
| 659 |  |  |  |  |  |  | * | 
| 660 |  |  |  |  |  |  | * calculate the two cpu/memory precentage values | 
| 661 |  |  |  |  |  |  | */ | 
| 662 | 53 |  |  |  |  |  | static void calc_prec(char *format_str, struct procstat *prs, struct obstack *mem_pool) | 
| 663 |  |  |  |  |  |  | { | 
| 664 |  |  |  |  |  |  | int len; | 
| 665 |  |  |  |  |  |  |  | 
| 666 |  |  |  |  |  |  | /* calculate pctcpu - NOTE: This assumes the cpu time is in microsecond units! | 
| 667 |  |  |  |  |  |  | * multiplying by 1/1e6 puts all units back in seconds.  Then multiply by 100.0f to get a percentage. | 
| 668 |  |  |  |  |  |  | */ | 
| 669 |  |  |  |  |  |  |  | 
| 670 | 53 |  |  |  |  |  | float pctcpu = (100.0f * (prs->utime + prs->stime) * 1 / 1e6) / (time(NULL) - prs->start_time); | 
| 671 |  |  |  |  |  |  |  | 
| 672 | 53 |  |  |  |  |  | len = snprintf(prs->pctcpu, LENGTH_PCTCPU, "%6.2f", pctcpu); | 
| 673 | 53 | 50 |  |  |  |  | if(len >= LENGTH_PCTCPU) { | 
| 674 | 0 |  |  |  |  |  | ppt_warn("percent cpu truncated from %d, set LENGTH_PCTCPU to at least: %d)", len, len + 1); | 
| 675 |  |  |  |  |  |  | } | 
| 676 |  |  |  |  |  |  |  | 
| 677 |  |  |  |  |  |  |  | 
| 678 | 53 |  |  |  |  |  | field_enable(format_str, F_PCTCPU); | 
| 679 |  |  |  |  |  |  |  | 
| 680 |  |  |  |  |  |  | /* calculate pctmem */ | 
| 681 | 53 | 50 |  |  |  |  | if(system_memory > 0) { | 
| 682 | 53 |  |  |  |  |  | sprintf(prs->pctmem, "%3.2f", (float)prs->rss / system_memory * 100.f); | 
| 683 | 53 |  |  |  |  |  | field_enable(format_str, F_PCTMEM); | 
| 684 |  |  |  |  |  |  | } | 
| 685 | 53 |  |  |  |  |  | } | 
| 686 |  |  |  |  |  |  |  | 
| 687 |  |  |  |  |  |  | /* is_pid() | 
| 688 |  |  |  |  |  |  | * | 
| 689 |  |  |  |  |  |  | * | 
| 690 |  |  |  |  |  |  | * @return  Boolean value. | 
| 691 |  |  |  |  |  |  | */ | 
| 692 | 363 |  |  |  |  |  | inline static bool is_pid(const char *str) | 
| 693 |  |  |  |  |  |  | { | 
| 694 | 502 | 100 |  |  |  |  | for(; *str; str++) { | 
| 695 | 449 | 100 |  |  |  |  | if(!isdigit(*str)) { | 
| 696 | 310 |  |  |  |  |  | return false; | 
| 697 |  |  |  |  |  |  | } | 
| 698 |  |  |  |  |  |  | } | 
| 699 |  |  |  |  |  |  |  | 
| 700 | 53 |  |  |  |  |  | return true; | 
| 701 |  |  |  |  |  |  | } | 
| 702 |  |  |  |  |  |  |  | 
| 703 | 0 |  |  |  |  |  | inline static bool pid_exists(const char *str, struct obstack *mem_pool) | 
| 704 |  |  |  |  |  |  | { | 
| 705 | 0 |  |  |  |  |  | char *pid_dir_path = NULL; | 
| 706 |  |  |  |  |  |  | int   result; | 
| 707 |  |  |  |  |  |  |  | 
| 708 | 0 |  |  |  |  |  | obstack_printf(mem_pool, "/proc/%s", str); | 
| 709 | 0 | 0 |  |  |  |  | obstack_1grow(mem_pool, '\0'); | 
| 710 | 0 | 0 |  |  |  |  | pid_dir_path = obstack_finish(mem_pool); | 
|  |  | 0 |  |  |  |  |  | 
| 711 |  |  |  |  |  |  |  | 
| 712 |  |  |  |  |  |  | /* directory exists? */ | 
| 713 | 0 |  |  |  |  |  | result = (access(pid_dir_path, F_OK) != -1); | 
| 714 |  |  |  |  |  |  |  | 
| 715 | 0 | 0 |  |  |  |  | obstack_free(mem_pool, pid_dir_path); | 
|  |  | 0 |  |  |  |  |  | 
| 716 |  |  |  |  |  |  |  | 
| 717 | 0 |  |  |  |  |  | return result; | 
| 718 |  |  |  |  |  |  | } | 
| 719 |  |  |  |  |  |  |  | 
| 720 | 5 |  |  |  |  |  | void OS_get_table() | 
| 721 |  |  |  |  |  |  | { | 
| 722 |  |  |  |  |  |  | /* dir walker storage */ | 
| 723 |  |  |  |  |  |  | DIR *          dir; | 
| 724 |  |  |  |  |  |  | struct dirent *dir_ent, *dir_result; | 
| 725 |  |  |  |  |  |  |  | 
| 726 |  |  |  |  |  |  | /* all our storage is going to be here */ | 
| 727 |  |  |  |  |  |  | struct obstack mem_pool; | 
| 728 |  |  |  |  |  |  |  | 
| 729 |  |  |  |  |  |  | /* container for scraped process values */ | 
| 730 |  |  |  |  |  |  | struct procstat *prs; | 
| 731 |  |  |  |  |  |  |  | 
| 732 |  |  |  |  |  |  | /* string containing our local copy of format_str, elements will be | 
| 733 |  |  |  |  |  |  | * lower cased if we are able to figure them out */ | 
| 734 |  |  |  |  |  |  | char *format_str; | 
| 735 |  |  |  |  |  |  |  | 
| 736 |  |  |  |  |  |  | /* initialize a small memory pool for this function */ | 
| 737 | 5 |  |  |  |  |  | obstack_init(&mem_pool); | 
| 738 |  |  |  |  |  |  |  | 
| 739 |  |  |  |  |  |  | /* put the dirent on the obstack, since it's rather large */ | 
| 740 | 5 | 50 |  |  |  |  | dir_ent = obstack_alloc(&mem_pool, sizeof(struct dirent)); | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 741 |  |  |  |  |  |  |  | 
| 742 | 5 | 50 |  |  |  |  | if((dir = opendir("/proc")) == NULL) { | 
| 743 | 0 |  |  |  |  |  | return; | 
| 744 |  |  |  |  |  |  | } | 
| 745 |  |  |  |  |  |  |  | 
| 746 |  |  |  |  |  |  | /* Iterate through all the process entries (numeric) under /proc */ | 
| 747 | 368 | 50 |  |  |  |  | while(readdir_r(dir, dir_ent, &dir_result) == 0 && dir_result) { | 
|  |  | 100 |  |  |  |  |  | 
| 748 |  |  |  |  |  |  | /* Only look at this file if it's a proc id; that is, all numbers */ | 
| 749 | 363 | 100 |  |  |  |  | if(!is_pid(dir_result->d_name)) { | 
| 750 | 310 |  |  |  |  |  | continue; | 
| 751 |  |  |  |  |  |  | } | 
| 752 |  |  |  |  |  |  |  | 
| 753 |  |  |  |  |  |  | /* allocate container for storing process values */ | 
| 754 | 53 | 50 |  |  |  |  | prs = obstack_alloc(&mem_pool, sizeof(struct procstat)); | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 755 | 53 |  |  |  |  |  | bzero(prs, sizeof(struct procstat)); | 
| 756 |  |  |  |  |  |  |  | 
| 757 |  |  |  |  |  |  | /* initialize the format string */ | 
| 758 | 53 |  |  |  |  |  | obstack_printf(&mem_pool, "%s", get_string(STR_DEFAULT_FORMAT)); | 
| 759 | 53 | 50 |  |  |  |  | obstack_1grow(&mem_pool, '\0'); | 
| 760 | 53 | 50 |  |  |  |  | format_str = (char *)obstack_finish(&mem_pool); | 
|  |  | 50 |  |  |  |  |  | 
| 761 |  |  |  |  |  |  |  | 
| 762 |  |  |  |  |  |  | /* get process' uid/guid */ | 
| 763 | 53 |  |  |  |  |  | get_user_info(dir_result->d_name, format_str, prs, &mem_pool); | 
| 764 |  |  |  |  |  |  |  | 
| 765 |  |  |  |  |  |  | /* scrape /proc/${pid}/stat */ | 
| 766 | 53 | 50 |  |  |  |  | if(get_proc_stat(dir_result->d_name, format_str, prs, &mem_pool) == false) { | 
| 767 |  |  |  |  |  |  | /* did the pid directory go away mid flight? */ | 
| 768 | 0 | 0 |  |  |  |  | if(pid_exists(dir_result->d_name, &mem_pool) == false) { | 
| 769 | 0 |  |  |  |  |  | continue; | 
| 770 |  |  |  |  |  |  | } | 
| 771 |  |  |  |  |  |  | } | 
| 772 |  |  |  |  |  |  |  | 
| 773 |  |  |  |  |  |  | /* correct values (times) found in /proc/${pid}/stat */ | 
| 774 | 53 |  |  |  |  |  | fixup_stat_values(format_str, prs); | 
| 775 |  |  |  |  |  |  |  | 
| 776 |  |  |  |  |  |  | /* get process' cmndline */ | 
| 777 | 53 |  |  |  |  |  | get_proc_cmndline(dir_result->d_name, format_str, prs, &mem_pool); | 
| 778 |  |  |  |  |  |  |  | 
| 779 |  |  |  |  |  |  | /* get process' cmdline */ | 
| 780 | 53 |  |  |  |  |  | get_proc_cmdline(dir_result->d_name, format_str, prs, &mem_pool); | 
| 781 |  |  |  |  |  |  |  | 
| 782 |  |  |  |  |  |  | /* get process' environ */ | 
| 783 | 53 |  |  |  |  |  | get_proc_environ(dir_result->d_name, format_str, prs, &mem_pool); | 
| 784 |  |  |  |  |  |  |  | 
| 785 |  |  |  |  |  |  | /* get process' cwd & exec values from the symblink */ | 
| 786 | 53 |  |  |  |  |  | eval_link(dir_result->d_name, "cwd", F_CWD, &prs->cwd, format_str, | 
| 787 |  |  |  |  |  |  | &mem_pool); | 
| 788 | 53 |  |  |  |  |  | eval_link(dir_result->d_name, "exe", F_EXEC, &prs->exec, format_str, | 
| 789 |  |  |  |  |  |  | &mem_pool); | 
| 790 |  |  |  |  |  |  |  | 
| 791 |  |  |  |  |  |  | /* scrape from /proc/{$pid}/status */ | 
| 792 | 53 |  |  |  |  |  | get_proc_status(dir_result->d_name, format_str, prs, &mem_pool); | 
| 793 |  |  |  |  |  |  |  | 
| 794 |  |  |  |  |  |  | /* calculate precent cpu & mem values */ | 
| 795 | 53 |  |  |  |  |  | calc_prec(format_str, prs, &mem_pool); | 
| 796 |  |  |  |  |  |  |  | 
| 797 |  |  |  |  |  |  | /* Go ahead and bless into a perl object */ | 
| 798 |  |  |  |  |  |  | /* Linux.h defines const char* const* Fiels, but we cast it away, as bless_into_proc only understands char** */ | 
| 799 | 53 |  |  |  |  |  | bless_into_proc(format_str, (char **)field_names, | 
| 800 |  |  |  |  |  |  | prs->uid, | 
| 801 |  |  |  |  |  |  | prs->gid, | 
| 802 |  |  |  |  |  |  | prs->pid, | 
| 803 | 53 |  |  |  |  |  | prs->comm, | 
| 804 |  |  |  |  |  |  | prs->ppid, | 
| 805 |  |  |  |  |  |  | prs->pgrp, | 
| 806 |  |  |  |  |  |  | prs->sid, | 
| 807 |  |  |  |  |  |  | prs->tty, | 
| 808 |  |  |  |  |  |  | prs->flags, | 
| 809 |  |  |  |  |  |  | prs->minflt, | 
| 810 |  |  |  |  |  |  | prs->cminflt, | 
| 811 |  |  |  |  |  |  | prs->majflt, | 
| 812 |  |  |  |  |  |  | prs->cmajflt, | 
| 813 |  |  |  |  |  |  | prs->utime, | 
| 814 |  |  |  |  |  |  | prs->stime, | 
| 815 |  |  |  |  |  |  | prs->cutime, | 
| 816 |  |  |  |  |  |  | prs->cstime, | 
| 817 |  |  |  |  |  |  | prs->priority, | 
| 818 |  |  |  |  |  |  | prs->start_time, | 
| 819 |  |  |  |  |  |  | prs->vsize, | 
| 820 |  |  |  |  |  |  | prs->rss, | 
| 821 |  |  |  |  |  |  | prs->wchan, | 
| 822 |  |  |  |  |  |  | prs->time, | 
| 823 |  |  |  |  |  |  | prs->ctime, | 
| 824 |  |  |  |  |  |  | prs->state, | 
| 825 |  |  |  |  |  |  | prs->euid, | 
| 826 |  |  |  |  |  |  | prs->suid, | 
| 827 |  |  |  |  |  |  | prs->fuid, | 
| 828 |  |  |  |  |  |  | prs->egid, | 
| 829 |  |  |  |  |  |  | prs->sgid, | 
| 830 |  |  |  |  |  |  | prs->fgid, | 
| 831 | 53 |  |  |  |  |  | prs->pctcpu, | 
| 832 | 53 |  |  |  |  |  | prs->pctmem, | 
| 833 |  |  |  |  |  |  | prs->cmndline, | 
| 834 |  |  |  |  |  |  | prs->exec, | 
| 835 |  |  |  |  |  |  | prs->cwd, | 
| 836 |  |  |  |  |  |  | prs->cmdline, | 
| 837 |  |  |  |  |  |  | prs->cmdline_len, | 
| 838 |  |  |  |  |  |  | prs->environ, | 
| 839 |  |  |  |  |  |  | prs->environ_len, | 
| 840 |  |  |  |  |  |  | prs->tracer | 
| 841 |  |  |  |  |  |  | ); | 
| 842 |  |  |  |  |  |  |  | 
| 843 |  |  |  |  |  |  | /* we want a new prs, for the next itteration */ | 
| 844 | 53 | 100 |  |  |  |  | obstack_free(&mem_pool, prs); | 
|  |  | 50 |  |  |  |  |  | 
| 845 |  |  |  |  |  |  | } | 
| 846 |  |  |  |  |  |  |  | 
| 847 | 5 |  |  |  |  |  | closedir(dir); | 
| 848 |  |  |  |  |  |  |  | 
| 849 |  |  |  |  |  |  | /* free all our tempoary memory */ | 
| 850 | 5 | 50 |  |  |  |  | obstack_free(&mem_pool, NULL); | 
|  |  | 0 |  |  |  |  |  | 
| 851 |  |  |  |  |  |  | } |