ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/process_stats.c
Revision: 1.83
Committed: Sun Oct 3 18:35:58 2010 UTC (13 years, 7 months ago) by tdb
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.82: +164 -2 lines
Log Message:
Add support for AIX 5.x - 9.x.

Many thanks to Jens Rehsack <rehsack@googlemail.com> for providing the
patch for this work. Thanks!

File Contents

# User Rev Content
1 tdb 1.17 /*
2 tdb 1.57 * i-scream libstatgrab
3 tdb 1.8 * http://www.i-scream.org
4 tdb 1.17 * Copyright (C) 2000-2004 i-scream
5 pajs 1.1 *
6 tdb 1.17 * This library is free software; you can redistribute it and/or
7     * modify it under the terms of the GNU Lesser General Public
8     * License as published by the Free Software Foundation; either
9     * version 2.1 of the License, or (at your option) any later version.
10 pajs 1.1 *
11 tdb 1.17 * This library is distributed in the hope that it will be useful,
12 pajs 1.1 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 tdb 1.17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14     * Lesser General Public License for more details.
15 pajs 1.1 *
16 tdb 1.17 * You should have received a copy of the GNU Lesser General Public
17     * License along with this library; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19     * 02111-1307 USA
20 tdb 1.18 *
21 tdb 1.83 * $Id: process_stats.c,v 1.82 2006/10/09 14:47:58 tdb Exp $
22 pajs 1.1 */
23    
24     #ifdef HAVE_CONFIG_H
25     #include "config.h"
26     #endif
27    
28 pajs 1.6 #include "statgrab.h"
29 ats 1.48 #include "tools.h"
30     #include "vector.h"
31 tdb 1.83 #if defined(SOLARIS) || defined(LINUX) || defined(AIX)
32 pajs 1.1 #include <stdio.h>
33     #include <stdlib.h>
34 pajs 1.5 #include <sys/types.h>
35     #include <dirent.h>
36 ats 1.80 #endif
37 pajs 1.5 #include <string.h>
38 pajs 1.1
39     #ifdef SOLARIS
40     #include <procfs.h>
41     #include <limits.h>
42 pajs 1.5 #define PROC_LOCATION "/proc"
43     #define MAX_FILE_LENGTH PATH_MAX
44     #endif
45     #ifdef LINUX
46 ats 1.16 #include <limits.h>
47 pajs 1.25 #include <unistd.h>
48     #include <sys/stat.h>
49     #include <fcntl.h>
50 pajs 1.1 #define PROC_LOCATION "/proc"
51     #define MAX_FILE_LENGTH PATH_MAX
52     #endif
53 ats 1.13 #ifdef ALLBSD
54 tdb 1.71 #include <errno.h>
55 tdb 1.19 #include <stdlib.h>
56 pajs 1.6 #include <sys/param.h>
57     #include <sys/sysctl.h>
58 tdb 1.22 #if defined(FREEBSD) || defined(DFBSD)
59     #include <sys/user.h>
60     #else
61 tdb 1.19 #include <sys/proc.h>
62 ats 1.13 #endif
63 tdb 1.29 #include <string.h>
64     #include <paths.h>
65     #include <fcntl.h>
66     #include <limits.h>
67 tdb 1.41 #if (defined(FREEBSD) && !defined(FREEBSD5)) || defined(DFBSD)
68 tdb 1.29 #include <kvm.h>
69 pajs 1.6 #endif
70 tdb 1.41 #include <unistd.h>
71 tdb 1.55 #ifdef NETBSD2
72     #include <sys/lwp.h>
73     #endif
74 tdb 1.41 #endif
75 tdb 1.76 #ifdef HPUX
76     #include <sys/param.h>
77     #include <sys/pstat.h>
78     #include <unistd.h>
79 ats 1.77 #define PROCESS_BATCH 30
80 tdb 1.76 #endif
81 tdb 1.81 #ifdef WIN32
82     #include <windows.h>
83     #include <psapi.h>
84     #endif
85 tdb 1.83 #ifdef AIX
86     #include <unistd.h>
87     #include <errno.h>
88     #include <time.h>
89     #include <procinfo.h>
90     #include <sys/time.h>
91     extern int getprocs64(struct procentry64 *, int, struct fdsinfo64 *, int, pid_t *, int);
92     extern int getargs(struct procentry64 *, int, char *, int);
93     #endif
94 pajs 1.1
95 ats 1.52 static void proc_state_init(sg_process_stats *s) {
96 ats 1.48 s->process_name = NULL;
97     s->proctitle = NULL;
98     }
99    
100 ats 1.52 static void proc_state_destroy(sg_process_stats *s) {
101 ats 1.48 free(s->process_name);
102     free(s->proctitle);
103     }
104    
105 ats 1.52 sg_process_stats *sg_get_process_stats(int *entries){
106     VECTOR_DECLARE_STATIC(proc_state, sg_process_stats, 64,
107 tdb 1.63 proc_state_init, proc_state_destroy);
108 ats 1.48 int proc_state_size = 0;
109 ats 1.52 sg_process_stats *proc_state_ptr;
110 tdb 1.76 #ifdef HPUX
111 ats 1.77 struct pst_status pstat_procinfo[PROCESS_BATCH];
112 tdb 1.76 long procidx = 0;
113 ats 1.77 long long pagesize;
114     int num, i;
115 tdb 1.76 #endif
116 tdb 1.83 #ifdef AIX
117     struct procentry64 *procs = NULL;
118     long long pagesize;
119     int fetched = 0;
120     pid_t index = 0;
121     unsigned proc_idx;
122     time_t utime, stime;
123     int ncpus;
124     struct timeval now_tval;
125     double now_time;
126     char cmndline[ARG_MAX];
127     char comm[ARG_MAX];
128     struct procentry64 curproc_for_getargs;
129     #define PROCS_TO_FETCH 1000
130     #endif
131 tdb 1.26 #ifdef ALLBSD
132 tdb 1.37 int mib[4];
133 tdb 1.26 size_t size;
134     struct kinfo_proc *kp_stats;
135 tdb 1.41 int procs, i;
136 tdb 1.45 char *proctitle;
137 tdb 1.41 #if (defined(FREEBSD) && !defined(FREEBSD5)) || defined(DFBSD)
138 tdb 1.42 kvm_t *kvmd;
139 tdb 1.50 char **args, **argsp;
140     int argslen = 0;
141 tdb 1.41 #else
142 tdb 1.37 long buflen;
143 tdb 1.71 char *p, *proctitletmp;
144 tdb 1.37 #endif
145 tdb 1.55 #ifdef NETBSD2
146     int lwps;
147     struct kinfo_lwp *kl_stats;
148     #endif
149 tdb 1.26 #endif
150 pajs 1.24 #if defined(SOLARIS) || defined(LINUX)
151 tdb 1.63 DIR *proc_dir;
152     struct dirent *dir_entry;
153     char filename[MAX_FILE_LENGTH];
154     FILE *f;
155 pajs 1.24 #ifdef SOLARIS
156 pajs 1.5 psinfo_t process_info;
157 pajs 1.24 #endif
158 pajs 1.25 #ifdef LINUX
159     char s;
160     /* If someone has a executable of 4k filename length, they deserve to get it truncated :) */
161     char ps_name[4096];
162     char *ptr;
163 ats 1.48 VECTOR_DECLARE_STATIC(psargs, char, 128, NULL, NULL);
164 pajs 1.58 unsigned long stime, utime, starttime;
165 pajs 1.25 int x;
166     int fn;
167 ats 1.48 int len;
168     int rc;
169 pajs 1.58 time_t uptime;
170 tdb 1.82 long tickspersec;
171 pajs 1.58 #endif
172    
173     #ifdef LINUX
174     if ((f=fopen("/proc/uptime", "r")) == NULL) {
175 ats 1.74 sg_set_error_with_errno(SG_ERROR_OPEN, "/proc/uptime");
176 pajs 1.58 return NULL;
177     }
178     if((fscanf(f,"%lu %*d",&uptime)) != 1){
179 tdb 1.65 sg_set_error(SG_ERROR_PARSE, NULL);
180 pajs 1.58 return NULL;
181     }
182     fclose(f);
183 pajs 1.25 #endif
184 pajs 1.1
185 tdb 1.63 if((proc_dir=opendir(PROC_LOCATION))==NULL){
186 ats 1.74 sg_set_error_with_errno(SG_ERROR_OPENDIR, PROC_LOCATION);
187 tdb 1.63 return NULL;
188     }
189 pajs 1.23
190 tdb 1.63 while((dir_entry=readdir(proc_dir))!=NULL){
191     if(atoi(dir_entry->d_name) == 0) continue;
192 pajs 1.23
193 pajs 1.24 #ifdef SOLARIS
194 tdb 1.63 snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/psinfo", dir_entry->d_name);
195 pajs 1.24 #endif
196 pajs 1.25 #ifdef LINUX
197     snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/stat", dir_entry->d_name);
198     #endif
199 tdb 1.63 if((f=fopen(filename, "r"))==NULL){
200     /* Open failed.. Process since vanished, or the path was too long.
201     * Ah well, move onwards to the next one */
202     continue;
203     }
204 pajs 1.24 #ifdef SOLARIS
205 tdb 1.63 fread(&process_info, sizeof(psinfo_t), 1, f);
206 pajs 1.64 fclose(f);
207 pajs 1.25 #endif
208 pajs 1.1
209 ats 1.48 if (VECTOR_RESIZE(proc_state, proc_state_size + 1) < 0) {
210 ats 1.52 return NULL;
211 ats 1.48 }
212 pajs 1.23 proc_state_ptr = proc_state+proc_state_size;
213 ats 1.48
214 pajs 1.25 #ifdef SOLARIS
215 pajs 1.23 proc_state_ptr->pid = process_info.pr_pid;
216     proc_state_ptr->parent = process_info.pr_ppid;
217     proc_state_ptr->pgid = process_info.pr_pgid;
218     proc_state_ptr->uid = process_info.pr_uid;
219     proc_state_ptr->euid = process_info.pr_euid;
220     proc_state_ptr->gid = process_info.pr_gid;
221     proc_state_ptr->egid = process_info.pr_egid;
222     proc_state_ptr->proc_size = (process_info.pr_size) * 1024;
223     proc_state_ptr->proc_resident = (process_info.pr_rssize) * 1024;
224     proc_state_ptr->time_spent = process_info.pr_time.tv_sec;
225     proc_state_ptr->cpu_percent = (process_info.pr_pctcpu * 100.0) / 0x8000;
226 pajs 1.64 proc_state_ptr->nice = (int)process_info.pr_lwp.pr_nice - 20;
227 ats 1.60 if (sg_update_string(&proc_state_ptr->process_name,
228 tdb 1.63 process_info.pr_fname) < 0) {
229 ats 1.60 return NULL;
230     }
231     if (sg_update_string(&proc_state_ptr->proctitle,
232 tdb 1.63 process_info.pr_psargs) < 0) {
233 ats 1.60 return NULL;
234     }
235 pajs 1.24
236 ats 1.75 switch (process_info.pr_lwp.pr_state) {
237     case 1:
238     proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING;
239     break;
240     case 2:
241     case 5:
242     proc_state_ptr->state = SG_PROCESS_STATE_RUNNING;
243     break;
244     case 3:
245     proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE;
246     break;
247     case 4:
248     proc_state_ptr->state = SG_PROCESS_STATE_STOPPED;
249     break;
250     }
251 pajs 1.25 #endif
252     #ifdef LINUX
253 pajs 1.58 x = fscanf(f, "%d %4096s %c %d %d %*d %*d %*d %*u %*u %*u %*u %*u %lu %lu %*d %*d %*d %d %*d %*d %lu %llu %llu %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %*d\n", &(proc_state_ptr->pid), ps_name, &s, &(proc_state_ptr->parent), &(proc_state_ptr->pgid), &utime, &stime, &(proc_state_ptr->nice), &starttime, &(proc_state_ptr->proc_size), &(proc_state_ptr->proc_resident));
254     /* +3 becuase man page says "Resident Set Size: number of pages the process has in real memory, minus 3 for administrative purposes." */
255     proc_state_ptr->proc_resident = (proc_state_ptr->proc_resident + 3) * getpagesize();
256 ats 1.75 switch (s) {
257     case 'S':
258     proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING;
259     break;
260     case 'R':
261     proc_state_ptr->state = SG_PROCESS_STATE_RUNNING;
262     break;
263     case 'Z':
264     proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE;
265     break;
266     case 'T':
267     case 'D':
268     proc_state_ptr->state = SG_PROCESS_STATE_STOPPED;
269     break;
270     }
271 pajs 1.25
272     /* pa_name[0] should = '(' */
273     ptr = strchr(&ps_name[1], ')');
274     if(ptr !=NULL) *ptr='\0';
275 ats 1.48
276 ats 1.52 if (sg_update_string(&proc_state_ptr->process_name,
277 tdb 1.63 &ps_name[1]) < 0) {
278 ats 1.52 return NULL;
279 ats 1.48 }
280 pajs 1.25
281 pajs 1.58 /* cpu */
282     proc_state_ptr->cpu_percent = (100.0 * (utime + stime)) / ((uptime * 100.0) - starttime);
283 tdb 1.82 tickspersec = sysconf (_SC_CLK_TCK);
284     if (tickspersec < 0) {
285     proc_state_ptr->time_spent = 0;
286     }
287     else {
288     proc_state_ptr->time_spent = (utime + stime) / tickspersec;
289     }
290 pajs 1.25
291 tdb 1.63 fclose(f);
292 pajs 1.62
293     /* uid / gid */
294     snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/status", dir_entry->d_name);
295 tdb 1.63 if ((f=fopen(filename, "r")) == NULL) {
296     /* Open failed.. Process since vanished, or the path was too long.
297     * Ah well, move onwards to the next one */
298     continue;
299     }
300 pajs 1.62
301     if((ptr=sg_f_read_line(f, "Uid:"))==NULL){
302     fclose(f);
303     continue;
304     }
305     sscanf(ptr, "Uid:\t%d\t%d\t%*d\t%*d\n", &(proc_state_ptr->uid), &(proc_state_ptr->euid));
306    
307     if((ptr=sg_f_read_line(f, "Gid:"))==NULL){
308 tdb 1.63 fclose(f);
309     continue;
310     }
311     sscanf(ptr, "Gid:\t%d\t%d\t%*d\t%*d\n", &(proc_state_ptr->gid), &(proc_state_ptr->egid));
312 pajs 1.62
313     fclose(f);
314 ats 1.48
315 pajs 1.25 /* proctitle */
316     snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/cmdline", dir_entry->d_name);
317    
318 tdb 1.63 if((fn=open(filename, O_RDONLY)) == -1){
319     /* Open failed.. Process since vanished, or the path was too long.
320     * Ah well, move onwards to the next one */
321     continue;
322     }
323 ats 1.48
324     #define READ_BLOCK_SIZE 128
325     len = 0;
326     do {
327 ats 1.53 if (VECTOR_RESIZE(psargs, len + READ_BLOCK_SIZE) < 0) {
328 ats 1.52 return NULL;
329 ats 1.48 }
330     rc = read(fn, psargs + len, READ_BLOCK_SIZE);
331     if (rc > 0) {
332     len += rc;
333     }
334     } while (rc == READ_BLOCK_SIZE);
335     close(fn);
336    
337     if (rc == -1) {
338     /* Read failed; move on. */
339     continue;
340 pajs 1.25 }
341    
342 ats 1.48 /* Turn \0s into spaces within the command line. */
343 pajs 1.25 ptr = psargs;
344 ats 1.48 for(x = 0; x < len; x++) {
345 pajs 1.25 if (*ptr == '\0') *ptr = ' ';
346     ptr++;
347     }
348    
349 ats 1.53 if (len == 0) {
350     /* We want psargs to be NULL. */
351     if (VECTOR_RESIZE(psargs, 0) < 0) {
352     return NULL;
353     }
354     } else {
355     /* Not empty, so append a \0. */
356     if (VECTOR_RESIZE(psargs, len + 1) < 0) {
357     return NULL;
358     }
359     psargs[len] = '\0';
360     }
361    
362     if (sg_update_string(&proc_state_ptr->proctitle, psargs) < 0) {
363 ats 1.52 return NULL;
364 ats 1.48 }
365 pajs 1.24 #endif
366 pajs 1.23
367     proc_state_size++;
368 tdb 1.63 }
369     closedir(proc_dir);
370 tdb 1.26 #endif
371    
372     #ifdef ALLBSD
373 tdb 1.36 mib[0] = CTL_KERN;
374     mib[1] = KERN_PROC;
375     mib[2] = KERN_PROC_ALL;
376    
377     if(sysctl(mib, 3, NULL, &size, NULL, 0) < 0) {
378 ats 1.74 sg_set_error_with_errno(SG_ERROR_SYSCTL,
379     "CTL_KERN.KERN_PROC.KERN_PROC_ALL");
380 ats 1.52 return NULL;
381 tdb 1.36 }
382    
383     procs = size / sizeof(struct kinfo_proc);
384    
385 ats 1.61 kp_stats = sg_malloc(size);
386 tdb 1.36 if(kp_stats == NULL) {
387 ats 1.52 return NULL;
388 tdb 1.36 }
389 ats 1.54 memset(kp_stats, 0, size);
390 tdb 1.36
391     if(sysctl(mib, 3, kp_stats, &size, NULL, 0) < 0) {
392 ats 1.74 sg_set_error_with_errno(SG_ERROR_SYSCTL,
393     "CTL_KERN.KERN_PROC.KERN_PROC_ALL");
394 tdb 1.36 free(kp_stats);
395 ats 1.52 return NULL;
396 tdb 1.36 }
397 tdb 1.33
398 tdb 1.37 #if (defined(FREEBSD) && !defined(FREEBSD5)) || defined(DFBSD)
399 ats 1.52 kvmd = sg_get_kvm2();
400 tdb 1.33 #endif
401 tdb 1.26
402     for (i = 0; i < procs; i++) {
403 ats 1.48 const char *name;
404 ats 1.54
405 tdb 1.55 #ifdef FREEBSD5
406 ats 1.54 if (kp_stats[i].ki_stat == 0) {
407 tdb 1.55 #else
408     if (kp_stats[i].kp_proc.p_stat == 0) {
409     #endif
410 ats 1.54 /* FreeBSD 5 deliberately overallocates the array that
411     * the sysctl returns, so we'll get a few junk
412     * processes on the end that we have to ignore. (Search
413     * for "overestimate by 5 procs" in
414     * src/sys/kern/kern_proc.c for more details.) */
415     continue;
416     }
417 ats 1.48
418     if (VECTOR_RESIZE(proc_state, proc_state_size + 1) < 0) {
419 ats 1.52 return NULL;
420 tdb 1.29 }
421 tdb 1.26 proc_state_ptr = proc_state+proc_state_size;
422 tdb 1.30
423     #ifdef FREEBSD5
424 ats 1.48 name = kp_stats[i].ki_comm;
425 tdb 1.35 #elif defined(DFBSD)
426 ats 1.48 name = kp_stats[i].kp_thread.td_comm;
427 tdb 1.30 #else
428 ats 1.48 name = kp_stats[i].kp_proc.p_comm;
429 tdb 1.30 #endif
430 ats 1.53 if (sg_update_string(&proc_state_ptr->process_name, name) < 0) {
431 ats 1.52 return NULL;
432 ats 1.48 }
433 tdb 1.29
434 tdb 1.37 #if defined(FREEBSD5) || defined(NETBSD) || defined(OPENBSD)
435    
436     #ifdef FREEBSD5
437     mib[2] = KERN_PROC_ARGS;
438     mib[3] = kp_stats[i].ki_pid;
439     #else
440     mib[1] = KERN_PROC_ARGS;
441     mib[2] = kp_stats[i].kp_proc.p_pid;
442     mib[3] = KERN_PROC_ARGV;
443     #endif
444    
445 ats 1.48 free(proc_state_ptr->proctitle);
446 tdb 1.71 proc_state_ptr->proctitle = NULL;
447    
448     /* Starting size - we'll double this straight away */
449     #define PROCTITLE_START_SIZE 64
450     buflen = PROCTITLE_START_SIZE;
451     size = buflen;
452     proctitle = NULL;
453    
454     do {
455 tdb 1.79 if((long) size >= buflen) {
456 tdb 1.71 buflen *= 2;
457     size = buflen;
458     proctitletmp = sg_realloc(proctitle, buflen);
459     if(proctitletmp == NULL) {
460     free(proctitle);
461     proctitle = NULL;
462     proc_state_ptr->proctitle = NULL;
463     size = 0;
464     break;
465     }
466     proctitle = proctitletmp;
467     bzero(proctitle, buflen);
468     }
469    
470     if(sysctl(mib, 4, proctitle, &size, NULL, 0) < 0) {
471     free(proctitle);
472     proctitle = NULL;
473     proc_state_ptr->proctitle = NULL;
474     size = 0;
475     break;
476     }
477 tdb 1.79 } while((long) size >= buflen);
478 tdb 1.71
479     if(size > 0) {
480 ats 1.61 proc_state_ptr->proctitle = sg_malloc(size+1);
481 tdb 1.37 if(proc_state_ptr->proctitle == NULL) {
482 ats 1.52 return NULL;
483 tdb 1.29 }
484 tdb 1.37 p = proctitle;
485 ats 1.72 #ifdef OPENBSD
486     /* On OpenBSD, this value has the argv pointers (which
487     * are terminated by a NULL) at the front, so we have
488     * to skip over them to get to the strings. */
489     while (*(char ***)p != NULL) {
490     p += sizeof(char **);
491     }
492     p += sizeof(char **);
493     #endif
494 ats 1.49 proc_state_ptr->proctitle[0] = '\0';
495 tdb 1.37 do {
496 ats 1.52 sg_strlcat(proc_state_ptr->proctitle, p, size+1);
497     sg_strlcat(proc_state_ptr->proctitle, " ", size+1);
498 tdb 1.37 p += strlen(p) + 1;
499     } while (p < proctitle + size);
500     free(proctitle);
501 tdb 1.71 proctitle = NULL;
502 tdb 1.45 /* remove trailing space */
503     proc_state_ptr->proctitle[strlen(proc_state_ptr->proctitle)-1] = '\0';
504 tdb 1.37 }
505     else {
506 tdb 1.71 if(proctitle != NULL) {
507     free(proctitle);
508     proctitle = NULL;
509     }
510 tdb 1.37 proc_state_ptr->proctitle = NULL;
511     }
512     #else
513 ats 1.48 free(proc_state_ptr->proctitle);
514 tdb 1.71 proc_state_ptr->proctitle = NULL;
515 tdb 1.37 if(kvmd != NULL) {
516     args = kvm_getargv(kvmd, &(kp_stats[i]), 0);
517     if(args != NULL) {
518 tdb 1.50 argsp = args;
519     while(*argsp != NULL) {
520 tdb 1.51 argslen += strlen(*argsp) + 1;
521     argsp++;
522 tdb 1.50 }
523 ats 1.61 proctitle = sg_malloc(argslen + 1);
524 tdb 1.50 proctitle[0] = '\0';
525 tdb 1.37 if(proctitle == NULL) {
526 ats 1.52 return NULL;
527 tdb 1.37 }
528     while(*args != NULL) {
529 ats 1.52 sg_strlcat(proctitle, *args, argslen + 1);
530     sg_strlcat(proctitle, " ", argslen + 1);
531 tdb 1.37 args++;
532 tdb 1.29 }
533 tdb 1.37 /* remove trailing space */
534 tdb 1.45 proctitle[strlen(proctitle)-1] = '\0';
535 tdb 1.37 proc_state_ptr->proctitle = proctitle;
536     }
537     else {
538     proc_state_ptr->proctitle = NULL;
539 tdb 1.29 }
540     }
541     else {
542 tdb 1.37 proc_state_ptr->proctitle = NULL;
543 tdb 1.29 }
544 tdb 1.37 #endif
545 tdb 1.26
546 tdb 1.30 #ifdef FREEBSD5
547 tdb 1.26 proc_state_ptr->pid = kp_stats[i].ki_pid;
548     proc_state_ptr->parent = kp_stats[i].ki_ppid;
549     proc_state_ptr->pgid = kp_stats[i].ki_pgid;
550 tdb 1.30 #else
551     proc_state_ptr->pid = kp_stats[i].kp_proc.p_pid;
552     proc_state_ptr->parent = kp_stats[i].kp_eproc.e_ppid;
553     proc_state_ptr->pgid = kp_stats[i].kp_eproc.e_pgid;
554     #endif
555 tdb 1.26
556 tdb 1.30 #ifdef FREEBSD5
557 tdb 1.26 proc_state_ptr->uid = kp_stats[i].ki_ruid;
558     proc_state_ptr->euid = kp_stats[i].ki_uid;
559     proc_state_ptr->gid = kp_stats[i].ki_rgid;
560     proc_state_ptr->egid = kp_stats[i].ki_svgid;
561 tdb 1.35 #elif defined(DFBSD)
562     proc_state_ptr->uid = kp_stats[i].kp_eproc.e_ucred.cr_ruid;
563     proc_state_ptr->euid = kp_stats[i].kp_eproc.e_ucred.cr_svuid;
564     proc_state_ptr->gid = kp_stats[i].kp_eproc.e_ucred.cr_rgid;
565     proc_state_ptr->egid = kp_stats[i].kp_eproc.e_ucred.cr_svgid;
566 tdb 1.30 #else
567     proc_state_ptr->uid = kp_stats[i].kp_eproc.e_pcred.p_ruid;
568     proc_state_ptr->euid = kp_stats[i].kp_eproc.e_pcred.p_svuid;
569     proc_state_ptr->gid = kp_stats[i].kp_eproc.e_pcred.p_rgid;
570     proc_state_ptr->egid = kp_stats[i].kp_eproc.e_pcred.p_svgid;
571     #endif
572 tdb 1.26
573 tdb 1.30 #ifdef FREEBSD5
574 tdb 1.26 proc_state_ptr->proc_size = kp_stats[i].ki_size;
575     /* This is in pages */
576 tdb 1.30 proc_state_ptr->proc_resident =
577     kp_stats[i].ki_rssize * getpagesize();
578 tdb 1.28 /* This is in microseconds */
579 tdb 1.26 proc_state_ptr->time_spent = kp_stats[i].ki_runtime / 1000000;
580 tdb 1.30 proc_state_ptr->cpu_percent =
581     ((double)kp_stats[i].ki_pctcpu / FSCALE) * 100.0;
582 tdb 1.26 proc_state_ptr->nice = kp_stats[i].ki_nice;
583 tdb 1.30 #else
584     proc_state_ptr->proc_size =
585     kp_stats[i].kp_eproc.e_vm.vm_map.size;
586     /* This is in pages */
587     proc_state_ptr->proc_resident =
588     kp_stats[i].kp_eproc.e_vm.vm_rssize * getpagesize();
589 tdb 1.34 #if defined(NETBSD) || defined(OPENBSD)
590 tdb 1.33 proc_state_ptr->time_spent =
591     kp_stats[i].kp_proc.p_rtime.tv_sec;
592 tdb 1.35 #elif defined(DFBSD)
593     proc_state_ptr->time_spent =
594     ( kp_stats[i].kp_thread.td_uticks +
595     kp_stats[i].kp_thread.td_sticks +
596     kp_stats[i].kp_thread.td_iticks ) / 1000000;
597 tdb 1.33 #else
598 tdb 1.36 /* This is in microseconds */
599 tdb 1.30 proc_state_ptr->time_spent =
600     kp_stats[i].kp_proc.p_runtime / 1000000;
601 tdb 1.33 #endif
602 tdb 1.30 proc_state_ptr->cpu_percent =
603     ((double)kp_stats[i].kp_proc.p_pctcpu / FSCALE) * 100.0;
604     proc_state_ptr->nice = kp_stats[i].kp_proc.p_nice;
605     #endif
606 tdb 1.26
607 tdb 1.55 #ifdef NETBSD2
608     {
609     size_t size;
610     int mib[5];
611    
612     mib[0] = CTL_KERN;
613     mib[1] = KERN_LWP;
614     mib[2] = kp_stats[i].kp_proc.p_pid;
615     mib[3] = sizeof(struct kinfo_lwp);
616     mib[4] = 0;
617    
618     if(sysctl(mib, 5, NULL, &size, NULL, 0) < 0) {
619 ats 1.74 sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_KERN.KERN_LWP.pid.structsize.0");
620 tdb 1.55 return NULL;
621     }
622    
623     lwps = size / sizeof(struct kinfo_lwp);
624     mib[4] = lwps;
625    
626 ats 1.61 kl_stats = sg_malloc(size);
627 tdb 1.55 if(kl_stats == NULL) {
628     return NULL;
629     }
630    
631     if(sysctl(mib, 5, kl_stats, &size, NULL, 0) < 0) {
632 ats 1.74 sg_set_error_with_errno(SG_ERROR_SYSCTL, "CTL_KERN.KERN_LWP.pid.structsize.buffersize");
633 tdb 1.55 return NULL;
634     }
635     }
636    
637     switch(kp_stats[i].kp_proc.p_stat) {
638     case SIDL:
639     proc_state_ptr->state = SG_PROCESS_STATE_RUNNING;
640     break;
641     case SACTIVE:
642     {
643     int i;
644    
645     for(i = 0; i < lwps; i++) {
646     switch(kl_stats[i].l_stat) {
647     case LSONPROC:
648     case LSRUN:
649     proc_state_ptr->state = SG_PROCESS_STATE_RUNNING;
650     goto end;
651     case LSSLEEP:
652     proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING;
653     goto end;
654     case LSSTOP:
655     case LSSUSPENDED:
656     proc_state_ptr->state = SG_PROCESS_STATE_STOPPED;
657     goto end;
658     }
659     proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN;
660     }
661     end: ;
662     }
663     break;
664     case SSTOP:
665     proc_state_ptr->state = SG_PROCESS_STATE_STOPPED;
666     break;
667     case SZOMB:
668     proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE;
669     break;
670     default:
671     proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN;
672     break;
673     }
674 tdb 1.73
675     free(kl_stats);
676 tdb 1.55 #else
677 tdb 1.30 #ifdef FREEBSD5
678 tdb 1.26 switch (kp_stats[i].ki_stat) {
679 tdb 1.30 #else
680     switch (kp_stats[i].kp_proc.p_stat) {
681     #endif
682 tdb 1.26 case SIDL:
683     case SRUN:
684     #ifdef SONPROC
685     case SONPROC: /* NetBSD */
686     #endif
687 ats 1.52 proc_state_ptr->state = SG_PROCESS_STATE_RUNNING;
688 tdb 1.26 break;
689     case SSLEEP:
690     #ifdef SWAIT
691     case SWAIT: /* FreeBSD 5 */
692     #endif
693     #ifdef SLOCK
694     case SLOCK: /* FreeBSD 5 */
695     #endif
696 ats 1.52 proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING;
697 tdb 1.26 break;
698     case SSTOP:
699 ats 1.52 proc_state_ptr->state = SG_PROCESS_STATE_STOPPED;
700 tdb 1.26 break;
701     case SZOMB:
702     #ifdef SDEAD
703     case SDEAD: /* OpenBSD & NetBSD */
704     #endif
705 ats 1.52 proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE;
706 tdb 1.31 break;
707     default:
708 ats 1.52 proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN;
709 tdb 1.26 break;
710     }
711 tdb 1.55 #endif
712 tdb 1.26 proc_state_size++;
713     }
714    
715     free(kp_stats);
716 tdb 1.76 #endif
717    
718     #ifdef HPUX
719 ats 1.77 if ((pagesize = sysconf(_SC_PAGESIZE)) == -1) {
720 tdb 1.76 sg_set_error_with_errno(SG_ERROR_SYSCONF, "_SC_PAGESIZE");
721     return NULL;
722     }
723    
724 ats 1.78 while (1) {
725 ats 1.77 num = pstat_getproc(pstat_procinfo, sizeof pstat_procinfo[0],
726     PROCESS_BATCH, procidx);
727 ats 1.78 if (num == -1) {
728     sg_set_error_with_errno(SG_ERROR_PSTAT,
729     "pstat_getproc");
730     return NULL;
731     } else if (num == 0) {
732     break;
733     }
734 tdb 1.76
735 ats 1.77 for (i = 0; i < num; i++) {
736     struct pst_status *pi = &pstat_procinfo[i];
737 tdb 1.76
738 ats 1.77 if (VECTOR_RESIZE(proc_state, proc_state_size + 1) < 0) {
739     return NULL;
740     }
741     proc_state_ptr = proc_state+proc_state_size;
742    
743     proc_state_ptr->pid = pi->pst_pid;
744     proc_state_ptr->parent = pi->pst_ppid;
745     proc_state_ptr->pgid = pi->pst_pgrp;
746     proc_state_ptr->uid = pi->pst_uid;
747     proc_state_ptr->euid = pi->pst_euid;
748     proc_state_ptr->gid = pi->pst_gid;
749     proc_state_ptr->egid = pi->pst_egid;
750     proc_state_ptr->proc_size = (pi->pst_dsize + pi->pst_tsize + pi->pst_ssize) * pagesize;
751     proc_state_ptr->proc_resident = pi->pst_rssize * pagesize;
752     proc_state_ptr->time_spent = pi->pst_time;
753     proc_state_ptr->cpu_percent = (pi->pst_pctcpu * 100.0) / 0x8000;
754     proc_state_ptr->nice = pi->pst_nice;
755    
756     if (sg_update_string(&proc_state_ptr->process_name,
757     pi->pst_ucomm) < 0) {
758     return NULL;
759     }
760     if (sg_update_string(&proc_state_ptr->proctitle,
761     pi->pst_cmd) < 0) {
762     return NULL;
763     }
764    
765     switch (pi->pst_stat) {
766     case PS_SLEEP:
767     proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING;
768     break;
769     case PS_RUN:
770     proc_state_ptr->state = SG_PROCESS_STATE_RUNNING;
771     break;
772     case PS_STOP:
773     proc_state_ptr->state = SG_PROCESS_STATE_STOPPED;
774     break;
775     case PS_ZOMBIE:
776     proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE;
777     break;
778     case PS_IDLE:
779     case PS_OTHER:
780     proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN;
781     break;
782     }
783    
784     proc_state_size++;
785 tdb 1.76 }
786 ats 1.78 procidx = pstat_procinfo[num - 1].pst_idx + 1;
787     }
788 tdb 1.47 #endif
789    
790 tdb 1.83 #ifdef AIX
791     #define TVALU_TO_SEC(x) ((x).tv_sec + ((double)((x).tv_usec) / 1000000.0))
792     #define TVALN_TO_SEC(x) ((x).tv_sec + ((double)((x).tv_usec) / 1000000000.0))
793     ncpus = sysconf(_SC_NPROCESSORS_ONLN);
794     if( -1 == ncpus ) {
795     ncpus = 1; /* sysconf error - assume 1 */
796     }
797    
798     if ((pagesize = sysconf(_SC_PAGESIZE)) == -1) {
799     sg_set_error_with_errno(SG_ERROR_SYSCONF, "_SC_PAGESIZE");
800     return NULL;
801     }
802    
803     proc_idx = 0;
804     procs = /* (struct procentry64 *) */ malloc(sizeof(*procs) * PROCS_TO_FETCH);
805     if(NULL == procs) {
806     sg_set_error_with_errno(SG_ERROR_MALLOC, "sg_get_process_stats");
807     return 0;
808     }
809    
810     gettimeofday(&now_tval, 0);
811     now_time = TVALU_TO_SEC(now_tval);
812    
813     /* keep on grabbing chunks of processes until getprocs returns a smaller
814     block than we asked for */
815     do {
816     int i;
817     fetched = getprocs64(procs, sizeof(*procs), NULL, 0, &index, PROCS_TO_FETCH);
818     if (VECTOR_RESIZE(proc_state, proc_state_size + fetched) < 0) {
819     sg_set_error_with_errno(SG_ERROR_MALLOC, "sg_get_process_stats");
820     free(procs);
821     return NULL;
822     }
823     for( i = 0; i < fetched; ++i ) {
824     struct procentry64 *pi = procs+i;
825     int zombie = 0;
826    
827     proc_state_ptr = proc_state + proc_idx;
828    
829     zombie = 0;
830    
831     /* set a descriptive name for the process state */
832     switch( pi->pi_state ) {
833     case SSLEEP:
834     proc_state_ptr->state = SG_PROCESS_STATE_SLEEPING;
835     break;
836     case SRUN:
837     proc_state_ptr->state = SG_PROCESS_STATE_RUNNING;
838     break;
839     case SZOMB:
840     proc_state_ptr->state = SG_PROCESS_STATE_ZOMBIE;
841     zombie = 1;
842     break;
843     case SSTOP:
844     proc_state_ptr->state = SG_PROCESS_STATE_STOPPED;
845     break;
846     case SACTIVE:
847     proc_state_ptr->state = SG_PROCESS_STATE_RUNNING;
848     break;
849     case SIDL:
850     default:
851     proc_state_ptr->state = SG_PROCESS_STATE_UNKNOWN;
852     break;
853     }
854    
855     if( zombie ) {
856     utime = pi->pi_utime;
857     stime = pi->pi_stime;
858     } else {
859     utime = TVALN_TO_SEC(pi->pi_ru.ru_utime) + TVALN_TO_SEC(pi->pi_cru.ru_utime);
860     stime = TVALN_TO_SEC(pi->pi_ru.ru_stime) + TVALN_TO_SEC(pi->pi_cru.ru_stime);
861     }
862    
863     proc_state_ptr->pid = pi->pi_pid;
864     proc_state_ptr->parent = pi->pi_ppid;
865     proc_state_ptr->pgid = pi->pi_pgrp;
866     proc_state_ptr->uid = pi->pi_cred.crx_ruid;
867     proc_state_ptr->euid = pi->pi_cred.crx_uid;
868     proc_state_ptr->gid = pi->pi_cred.crx_rgid;
869     proc_state_ptr->egid = pi->pi_cred.crx_gid;
870     proc_state_ptr->proc_size = pi->pi_size;
871     proc_state_ptr->proc_resident = pi->pi_drss + pi->pi_trss; /* XXX might be wrong, see P::PT */
872     proc_state_ptr->time_spent = utime + stime;
873     proc_state_ptr->cpu_percent = (((double)(utime + stime) * 100) / ( now_time - pi->pi_start )) / ncpus;
874     proc_state_ptr->nice = pi->pi_nice;
875    
876     /* determine comm & cmndline */
877     if( (pi->pi_flags & SKPROC) == SKPROC ) {
878     if( pi->pi_pid == 0 ) {
879     snprintf(comm, ARG_MAX, "kproc (swapper)");
880     snprintf(cmndline, ARG_MAX, "kproc (swapper)");
881     } else {
882     snprintf(comm, ARG_MAX, "kproc (%s)", pi->pi_comm);
883     snprintf(cmndline, ARG_MAX, "kproc (%s)", pi->pi_comm);
884     }
885     } else {
886     snprintf(comm, ARG_MAX, "%s", pi->pi_comm);
887     curproc_for_getargs.pi_pid = pi->pi_pid;
888     if( getargs(&curproc_for_getargs, sizeof(curproc_for_getargs), cmndline, ARG_MAX) < 0 ) {
889     snprintf(cmndline, ARG_MAX, "%s", pi->pi_comm);
890     } else {
891     int done = 0;
892     /* replace NUL characters in command line with spaces */
893     char *c = cmndline;
894     while( ! done ) {
895     if( *c == '\0' ) {
896     if( *(c+1) == '\0' ) {
897     done = 1;
898     } else {
899     *c++ = ' ';
900     }
901     } else {
902     ++c;
903     }
904     }
905     }
906     }
907    
908    
909     if (sg_update_string(&proc_state_ptr->process_name, comm) < 0) {
910     free(procs);
911     return NULL;
912     }
913     if (sg_update_string(&proc_state_ptr->proctitle, cmndline) < 0) {
914     free(procs);
915     return NULL;
916     }
917    
918     proc_idx++;
919     }
920     } while( fetched >= PROCS_TO_FETCH );
921    
922     proc_state_size = proc_idx;
923    
924     free(procs);
925     #endif
926    
927    
928 tdb 1.47 #ifdef CYGWIN
929 tdb 1.65 sg_set_error(SG_ERROR_UNSUPPORTED, "Cygwin");
930 ats 1.52 return NULL;
931 tdb 1.26 #endif
932 tdb 1.81 #ifdef WIN32
933     /* FIXME The data needed for this is probably do able with the
934     * "performance registry". Although using this appears to be a black
935     * art and closely guarded secret.
936     * This is not directly used in ihost, so not considered a priority */
937     sg_set_error(SG_ERROR_UNSUPPORTED, "Win32");
938     return NULL;
939     #endif
940 tdb 1.26
941 ats 1.52 *entries = proc_state_size;
942     return proc_state;
943 tdb 1.27 }
944    
945 ats 1.52 sg_process_count *sg_get_process_count() {
946     static sg_process_count process_stat;
947 tdb 1.81 #ifndef WIN32
948 ats 1.52 sg_process_stats *ps;
949 tdb 1.27 int ps_size, x;
950 tdb 1.81 #else
951     DWORD aProcesses[1024];
952     DWORD cbNeeded;
953     #endif
954 tdb 1.27
955 tdb 1.30 process_stat.sleeping = 0;
956     process_stat.running = 0;
957     process_stat.zombie = 0;
958     process_stat.stopped = 0;
959     process_stat.total = 0;
960 tdb 1.27
961 tdb 1.81 #ifndef WIN32
962 ats 1.52 ps = sg_get_process_stats(&ps_size);
963     if (ps == NULL) {
964 tdb 1.32 return NULL;
965     }
966 tdb 1.27
967     for(x = 0; x < ps_size; x++) {
968     switch (ps->state) {
969 ats 1.52 case SG_PROCESS_STATE_RUNNING:
970 tdb 1.27 process_stat.running++;
971     break;
972 ats 1.52 case SG_PROCESS_STATE_SLEEPING:
973 tdb 1.27 process_stat.sleeping++;
974     break;
975 ats 1.52 case SG_PROCESS_STATE_STOPPED:
976 tdb 1.27 process_stat.stopped++;
977     break;
978 ats 1.52 case SG_PROCESS_STATE_ZOMBIE:
979 tdb 1.27 process_stat.zombie++;
980 ats 1.40 break;
981     default:
982 ats 1.52 /* currently no mapping for SG_PROCESS_STATE_UNKNOWN in
983     * sg_process_count */
984 tdb 1.27 break;
985     }
986     ps++;
987     }
988    
989     process_stat.total = ps_size;
990 tdb 1.81 #else
991     if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
992     return NULL;
993     process_stat.total = cbNeeded / sizeof(DWORD);
994     #endif
995 tdb 1.27
996     return &process_stat;
997 ats 1.70 }
998    
999     int sg_process_compare_name(const void *va, const void *vb) {
1000     const sg_process_stats *a = (sg_process_stats *)va;
1001     const sg_process_stats *b = (sg_process_stats *)vb;
1002    
1003     return strcmp(a->process_name, b->process_name);
1004 pajs 1.66 }
1005    
1006 pajs 1.67 int sg_process_compare_pid(const void *va, const void *vb) {
1007 pajs 1.66 const sg_process_stats *a = (sg_process_stats *)va;
1008     const sg_process_stats *b = (sg_process_stats *)vb;
1009    
1010     if (a->pid < b->pid) {
1011     return -1;
1012     } else if (a->pid == b->pid) {
1013     return 0;
1014     } else {
1015     return 1;
1016     }
1017     }
1018    
1019 pajs 1.67 int sg_process_compare_uid(const void *va, const void *vb) {
1020 pajs 1.66 const sg_process_stats *a = (sg_process_stats *)va;
1021     const sg_process_stats *b = (sg_process_stats *)vb;
1022    
1023     if (a->uid < b->uid) {
1024     return -1;
1025     } else if (a->uid == b->uid) {
1026     return 0;
1027     } else {
1028     return 1;
1029     }
1030     }
1031    
1032 pajs 1.67 int sg_process_compare_gid(const void *va, const void *vb) {
1033 pajs 1.66 const sg_process_stats *a = (sg_process_stats *)va;
1034     const sg_process_stats *b = (sg_process_stats *)vb;
1035    
1036     if (a->gid < b->gid) {
1037     return -1;
1038     } else if (a->gid == b->gid) {
1039     return 0;
1040     } else {
1041     return 1;
1042     }
1043     }
1044    
1045 pajs 1.67 int sg_process_compare_size(const void *va, const void *vb) {
1046 pajs 1.66 const sg_process_stats *a = (sg_process_stats *)va;
1047     const sg_process_stats *b = (sg_process_stats *)vb;
1048    
1049     if (a->proc_size < b->proc_size) {
1050     return -1;
1051     } else if (a->proc_size == b->proc_size) {
1052     return 0;
1053     } else {
1054     return 1;
1055     }
1056     }
1057    
1058 pajs 1.67 int sg_process_compare_res(const void *va, const void *vb) {
1059 pajs 1.66 const sg_process_stats *a = (sg_process_stats *)va;
1060     const sg_process_stats *b = (sg_process_stats *)vb;
1061    
1062     if (a->proc_resident < b->proc_resident) {
1063     return -1;
1064     } else if (a->proc_resident == b->proc_resident) {
1065     return 0;
1066     } else {
1067     return 1;
1068     }
1069     }
1070    
1071 pajs 1.67 int sg_process_compare_cpu(const void *va, const void *vb) {
1072 pajs 1.66 const sg_process_stats *a = (sg_process_stats *)va;
1073     const sg_process_stats *b = (sg_process_stats *)vb;
1074    
1075     if (a->cpu_percent < b->cpu_percent) {
1076     return -1;
1077     } else if (a->cpu_percent == b->cpu_percent) {
1078     return 0;
1079     } else {
1080     return 1;
1081     }
1082     }
1083    
1084 pajs 1.67 int sg_process_compare_time(const void *va, const void *vb) {
1085 pajs 1.66 const sg_process_stats *a = (sg_process_stats *)va;
1086     const sg_process_stats *b = (sg_process_stats *)vb;
1087    
1088     if (a->time_spent < b->time_spent) {
1089     return -1;
1090     } else if (a->time_spent == b->time_spent) {
1091     return 0;
1092     } else {
1093     return 1;
1094     }
1095     }
1096