ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/libstatgrab/src/libstatgrab/process_stats.c
Revision: 1.29
Committed: Sat Apr 3 20:33:45 2004 UTC (20 years, 1 month ago) by tdb
Content type: text/plain
Branch: MAIN
Changes since 1.28: +49 -19 lines
Log Message:
Got the command line args. Now using kvm to get information, although
fortunately this doesn't need any special privileges. Switched to using
kvm to get the process listing too.

When no command line arguments available doing something similar to ps and
putting the command name in brackets.

File Contents

# User Rev Content
1 tdb 1.17 /*
2 pajs 1.1 * i-scream central monitoring system
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.29 * $Id: process_stats.c,v 1.28 2004/04/03 16:57:32 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     #if defined(SOLARIS) || defined(LINUX)
30 pajs 1.1 #include <stdio.h>
31     #include <stdlib.h>
32 pajs 1.5 #include <sys/types.h>
33     #include <dirent.h>
34     #include <string.h>
35 pajs 1.6 #endif
36 pajs 1.1
37     #ifdef SOLARIS
38     #include <procfs.h>
39     #include <limits.h>
40 pajs 1.5 #define PROC_LOCATION "/proc"
41     #define MAX_FILE_LENGTH PATH_MAX
42     #endif
43     #ifdef LINUX
44 ats 1.16 #include <limits.h>
45 pajs 1.25 #include <unistd.h>
46     #include <sys/stat.h>
47     #include <fcntl.h>
48 pajs 1.1 #define PROC_LOCATION "/proc"
49     #define MAX_FILE_LENGTH PATH_MAX
50     #endif
51 ats 1.13 #ifdef ALLBSD
52 tdb 1.19 #include <stdlib.h>
53 pajs 1.6 #include <sys/param.h>
54     #include <sys/sysctl.h>
55 tdb 1.22 #if defined(FREEBSD) || defined(DFBSD)
56     #include <sys/user.h>
57     #else
58 tdb 1.19 #include <sys/proc.h>
59 ats 1.13 #endif
60 tdb 1.29 #include <string.h>
61     #include <paths.h>
62     #include <fcntl.h>
63     #include <limits.h>
64     #include <kvm.h>
65 pajs 1.6 #endif
66 pajs 1.1
67 pajs 1.23 int get_proc_snapshot(proc_state_t **ps){
68     proc_state_t *proc_state = NULL;
69     proc_state_t *proc_state_ptr;
70     int proc_state_size = 0;
71 tdb 1.26 #ifdef ALLBSD
72     int mib[3];
73     size_t size;
74     struct kinfo_proc *kp_stats;
75 tdb 1.29 int procs, i, alloc;
76     static kvm_t *kvmd;
77     char **args;
78     char *proctitle;
79 tdb 1.26 #endif
80 pajs 1.24 #if defined(SOLARIS) || defined(LINUX)
81 pajs 1.23 DIR *proc_dir;
82     struct dirent *dir_entry;
83     char filename[MAX_FILE_LENGTH];
84     FILE *f;
85 pajs 1.24 #ifdef SOLARIS
86 pajs 1.5 psinfo_t process_info;
87 pajs 1.24 #endif
88 pajs 1.25 #ifdef LINUX
89     char s;
90     /* If someone has a executable of 4k filename length, they deserve to get it truncated :) */
91     char ps_name[4096];
92     char *ptr;
93     static char *psargs = NULL;
94     static int psarg_size = 0;
95     unsigned long stime, utime;
96     int x;
97     int fn;
98     int toread;
99     ssize_t size;
100     int t_read;
101     #endif
102 pajs 1.1
103 pajs 1.23 if((proc_dir=opendir(PROC_LOCATION))==NULL){
104 pajs 1.25 return -1;
105 pajs 1.23 }
106    
107     while((dir_entry=readdir(proc_dir))!=NULL){
108     if(atoi(dir_entry->d_name) == 0) continue;
109    
110 pajs 1.24 #ifdef SOLARIS
111 pajs 1.23 snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/psinfo", dir_entry->d_name);
112 pajs 1.24 #endif
113 pajs 1.25 #ifdef LINUX
114     snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/stat", dir_entry->d_name);
115     #endif
116 pajs 1.23 if((f=fopen(filename, "r"))==NULL){
117     /* Open failed.. Process since vanished, or the path was too long.
118     * Ah well, move onwards to the next one */
119     continue;
120     }
121 pajs 1.24 #ifdef SOLARIS
122 pajs 1.23 fread(&process_info, sizeof(psinfo_t), 1, f);
123 pajs 1.25 #endif
124 pajs 1.1
125 pajs 1.23 proc_state = realloc(proc_state, (1+proc_state_size)*sizeof(proc_state_t));
126     proc_state_ptr = proc_state+proc_state_size;
127 pajs 1.25 #ifdef SOLARIS
128 pajs 1.23 proc_state_ptr->pid = process_info.pr_pid;
129     proc_state_ptr->parent = process_info.pr_ppid;
130     proc_state_ptr->pgid = process_info.pr_pgid;
131     proc_state_ptr->uid = process_info.pr_uid;
132     proc_state_ptr->euid = process_info.pr_euid;
133     proc_state_ptr->gid = process_info.pr_gid;
134     proc_state_ptr->egid = process_info.pr_egid;
135     proc_state_ptr->proc_size = (process_info.pr_size) * 1024;
136     proc_state_ptr->proc_resident = (process_info.pr_rssize) * 1024;
137     proc_state_ptr->time_spent = process_info.pr_time.tv_sec;
138     proc_state_ptr->cpu_percent = (process_info.pr_pctcpu * 100.0) / 0x8000;
139     proc_state_ptr->process_name = strdup(process_info.pr_fname);
140     proc_state_ptr->proctitle = strdup(process_info.pr_psargs);
141 pajs 1.24
142     if(process_info.pr_lwp.pr_state==1) proc_state_ptr->state = SLEEPING;
143     if(process_info.pr_lwp.pr_state==2) proc_state_ptr->state = RUNNING;
144     if(process_info.pr_lwp.pr_state==3) proc_state_ptr->state = ZOMBIE;
145     if(process_info.pr_lwp.pr_state==4) proc_state_ptr->state = STOPPED;
146     if(process_info.pr_lwp.pr_state==6) proc_state_ptr->state = RUNNING;
147 pajs 1.25 #endif
148     #ifdef LINUX
149     x = fscanf(f, "%d %4096s %c %d %d %*d %*d %*d %*lu %*lu %*lu %*lu %*lu %lu %lu %*ld %*ld %*ld %d %*ld %*ld %*lu %llu %llu %*lu %*lu %*lu %*lu %*lu %*lu %*lu %*lu %*lu %*lu %*lu %*lu %*lu %*d %*d\n", &(proc_state_ptr->pid), ps_name, &s, &(proc_state_ptr->parent), &(proc_state_ptr->pgid), &utime, &stime, &(proc_state_ptr->nice), &(proc_state_ptr->proc_size), &(proc_state_ptr->proc_resident));
150     proc_state_ptr->proc_resident = proc_state_ptr->proc_resident * getpagesize();
151     if(s == 'S') proc_state_ptr->state = SLEEPING;
152     if(s == 'R') proc_state_ptr->state = RUNNING;
153     if(s == 'Z') proc_state_ptr->state = ZOMBIE;
154     if(s == 'T') proc_state_ptr->state = STOPPED;
155     if(s == 'D') proc_state_ptr->state = STOPPED;
156    
157     /* pa_name[0] should = '(' */
158     ptr = strchr(&ps_name[1], ')');
159     if(ptr !=NULL) *ptr='\0';
160     proc_state_ptr->process_name = strdup(&ps_name[1]);
161    
162     /* Need to do cpu */
163    
164    
165     /* proctitle */
166     snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/cmdline", dir_entry->d_name);
167    
168     if((fn=open(filename, O_RDONLY)) == -1){
169     /* Open failed.. Process since vanished, or the path was too long.
170     * Ah well, move onwards to the next one */
171     continue;
172     }
173     #define PSARG_START_SIZE 128
174     if(psargs == NULL){
175     psargs = malloc(PSARG_START_SIZE);
176     psarg_size = PSARG_START_SIZE;
177     }
178     ptr = psargs;
179     t_read = 0;
180     toread = psarg_size;
181     while((size = read(fn, ptr, toread)) == toread){
182     psargs = realloc(psargs, (psarg_size + PSARG_START_SIZE));
183     ptr = psargs+psarg_size;
184     t_read = psarg_size;
185     psarg_size+=PSARG_START_SIZE;
186     toread = PSARG_START_SIZE;
187     }
188     if(size != -1) t_read+=size;
189    
190     ptr = psargs;
191     for(x=0; x<t_read; x++){
192     if (*ptr == '\0') *ptr = ' ';
193     ptr++;
194     }
195     /* for safety sake */
196     psargs[t_read] = '\0';
197    
198     proc_state_ptr->proctitle = strdup(psargs);
199    
200 pajs 1.24 #endif
201 pajs 1.23
202     proc_state_size++;
203 pajs 1.1
204 pajs 1.23 fclose(f);
205     }
206     closedir(proc_dir);
207 tdb 1.26 #endif
208    
209     #ifdef ALLBSD
210 tdb 1.29 kvmd = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, NULL, O_RDONLY, NULL);
211 tdb 1.26
212 tdb 1.29 if(kvmd == NULL) return NULL;
213 tdb 1.26
214 tdb 1.29 kp_stats = kvm_getprocs(kvmd, KERN_PROC_ALL, 0, &procs);
215 tdb 1.26
216 tdb 1.29 if (kp_stats == NULL || procs < 0) {
217 tdb 1.26 return NULL;
218     }
219    
220     for (i = 0; i < procs; i++) {
221 tdb 1.29 /* replace with something more sensible */
222 tdb 1.26 proc_state = realloc(proc_state, (1+proc_state_size)*sizeof(proc_state_t));
223 tdb 1.29 if(proc_state == NULL ) {
224     return NULL;
225     }
226 tdb 1.26 proc_state_ptr = proc_state+proc_state_size;
227    
228     proc_state_ptr->process_name = strdup(kp_stats[i].ki_comm);
229 tdb 1.29
230     args = kvm_getargv(kvmd, &(kp_stats[i]), 0);
231     if(args != NULL) {
232     alloc = 1;
233     proctitle = malloc(alloc);
234     if(proctitle == NULL) {
235     return NULL;
236     }
237     while(*args != NULL) {
238     if(strlen(proctitle) + strlen(*args) >= alloc) {
239     alloc = (alloc + strlen(*args)) << 1;
240     proctitle = realloc(proctitle, alloc);
241     if(proctitle == NULL) {
242     return NULL;
243     }
244     }
245     strncat(proctitle, *args, strlen(*args));
246     strncat(proctitle, " ", 1);
247     args++;
248     }
249     /* remove trailing space */
250     proctitle[strlen(proctitle)-1] = NULL;
251     proc_state_ptr->proctitle = proctitle;
252     }
253     else {
254     proc_state_ptr->proctitle = malloc(strlen(kp_stats[i].ki_comm)+4);
255     if(proc_state_ptr->proctitle == NULL) {
256     return NULL;
257     }
258     sprintf(proc_state_ptr->proctitle, " (%s)", kp_stats[i].ki_comm);
259     }
260 tdb 1.26
261     proc_state_ptr->pid = kp_stats[i].ki_pid;
262     proc_state_ptr->parent = kp_stats[i].ki_ppid;
263     proc_state_ptr->pgid = kp_stats[i].ki_pgid;
264    
265     proc_state_ptr->uid = kp_stats[i].ki_ruid;
266     proc_state_ptr->euid = kp_stats[i].ki_uid;
267     proc_state_ptr->gid = kp_stats[i].ki_rgid;
268     proc_state_ptr->egid = kp_stats[i].ki_svgid;
269    
270     proc_state_ptr->proc_size = kp_stats[i].ki_size;
271     /* This is in pages */
272     proc_state_ptr->proc_resident = kp_stats[i].ki_rssize * getpagesize();
273 tdb 1.28 /* This is in microseconds */
274 tdb 1.26 proc_state_ptr->time_spent = kp_stats[i].ki_runtime / 1000000;
275 tdb 1.28 proc_state_ptr->cpu_percent = ((double) kp_stats[i].ki_pctcpu / FSCALE) * 100.0;
276 tdb 1.26 proc_state_ptr->nice = kp_stats[i].ki_nice;
277    
278     switch (kp_stats[i].ki_stat) {
279     case SIDL:
280     case SRUN:
281     #ifdef SONPROC
282     case SONPROC: /* NetBSD */
283     #endif
284     proc_state_ptr->state = RUNNING;
285     break;
286     case SSLEEP:
287     #ifdef SWAIT
288     case SWAIT: /* FreeBSD 5 */
289     #endif
290     #ifdef SLOCK
291     case SLOCK: /* FreeBSD 5 */
292     #endif
293     proc_state_ptr->state = SLEEPING;
294     break;
295     case SSTOP:
296     proc_state_ptr->state = STOPPED;
297     break;
298     case SZOMB:
299     #ifdef SDEAD
300     case SDEAD: /* OpenBSD & NetBSD */
301     #endif
302     proc_state_ptr->state = ZOMBIE;
303     break;
304     }
305     proc_state_size++;
306     }
307    
308     free(kp_stats);
309     #endif
310    
311 pajs 1.23 *ps = proc_state;
312     return proc_state_size;
313 tdb 1.27 }
314    
315     process_stat_t *get_process_stats() {
316     static process_stat_t process_stat;
317     proc_state_t *ps;
318     int ps_size, x;
319    
320     process_stat.sleeping=0;
321     process_stat.running=0;
322     process_stat.zombie=0;
323     process_stat.stopped=0;
324     process_stat.total=0;
325    
326     ps_size = get_proc_snapshot(&ps);
327    
328     for(x = 0; x < ps_size; x++) {
329     switch (ps->state) {
330     case RUNNING:
331     process_stat.running++;
332     break;
333     case SLEEPING:
334     process_stat.sleeping++;
335     break;
336     case STOPPED:
337     process_stat.stopped++;
338     break;
339     case ZOMBIE:
340     process_stat.zombie++;
341     break;
342     }
343     ps++;
344     }
345    
346     process_stat.total = ps_size;
347    
348     return &process_stat;
349 pajs 1.23 }