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

# Content
1 /*
2 * i-scream central monitoring system
3 * http://www.i-scream.org
4 * Copyright (C) 2000-2004 i-scream
5 *
6 * 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 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * 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 *
21 * $Id: process_stats.c,v 1.28 2004/04/03 16:57:32 tdb Exp $
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "statgrab.h"
29 #if defined(SOLARIS) || defined(LINUX)
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <dirent.h>
34 #include <string.h>
35 #endif
36
37 #ifdef SOLARIS
38 #include <procfs.h>
39 #include <limits.h>
40 #define PROC_LOCATION "/proc"
41 #define MAX_FILE_LENGTH PATH_MAX
42 #endif
43 #ifdef LINUX
44 #include <limits.h>
45 #include <unistd.h>
46 #include <sys/stat.h>
47 #include <fcntl.h>
48 #define PROC_LOCATION "/proc"
49 #define MAX_FILE_LENGTH PATH_MAX
50 #endif
51 #ifdef ALLBSD
52 #include <stdlib.h>
53 #include <sys/param.h>
54 #include <sys/sysctl.h>
55 #if defined(FREEBSD) || defined(DFBSD)
56 #include <sys/user.h>
57 #else
58 #include <sys/proc.h>
59 #endif
60 #include <string.h>
61 #include <paths.h>
62 #include <fcntl.h>
63 #include <limits.h>
64 #include <kvm.h>
65 #endif
66
67 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 #ifdef ALLBSD
72 int mib[3];
73 size_t size;
74 struct kinfo_proc *kp_stats;
75 int procs, i, alloc;
76 static kvm_t *kvmd;
77 char **args;
78 char *proctitle;
79 #endif
80 #if defined(SOLARIS) || defined(LINUX)
81 DIR *proc_dir;
82 struct dirent *dir_entry;
83 char filename[MAX_FILE_LENGTH];
84 FILE *f;
85 #ifdef SOLARIS
86 psinfo_t process_info;
87 #endif
88 #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
103 if((proc_dir=opendir(PROC_LOCATION))==NULL){
104 return -1;
105 }
106
107 while((dir_entry=readdir(proc_dir))!=NULL){
108 if(atoi(dir_entry->d_name) == 0) continue;
109
110 #ifdef SOLARIS
111 snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/psinfo", dir_entry->d_name);
112 #endif
113 #ifdef LINUX
114 snprintf(filename, MAX_FILE_LENGTH, "/proc/%s/stat", dir_entry->d_name);
115 #endif
116 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 #ifdef SOLARIS
122 fread(&process_info, sizeof(psinfo_t), 1, f);
123 #endif
124
125 proc_state = realloc(proc_state, (1+proc_state_size)*sizeof(proc_state_t));
126 proc_state_ptr = proc_state+proc_state_size;
127 #ifdef SOLARIS
128 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
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 #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 #endif
201
202 proc_state_size++;
203
204 fclose(f);
205 }
206 closedir(proc_dir);
207 #endif
208
209 #ifdef ALLBSD
210 kvmd = kvm_openfiles(_PATH_DEVNULL, _PATH_DEVNULL, NULL, O_RDONLY, NULL);
211
212 if(kvmd == NULL) return NULL;
213
214 kp_stats = kvm_getprocs(kvmd, KERN_PROC_ALL, 0, &procs);
215
216 if (kp_stats == NULL || procs < 0) {
217 return NULL;
218 }
219
220 for (i = 0; i < procs; i++) {
221 /* replace with something more sensible */
222 proc_state = realloc(proc_state, (1+proc_state_size)*sizeof(proc_state_t));
223 if(proc_state == NULL ) {
224 return NULL;
225 }
226 proc_state_ptr = proc_state+proc_state_size;
227
228 proc_state_ptr->process_name = strdup(kp_stats[i].ki_comm);
229
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
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 /* This is in microseconds */
274 proc_state_ptr->time_spent = kp_stats[i].ki_runtime / 1000000;
275 proc_state_ptr->cpu_percent = ((double) kp_stats[i].ki_pctcpu / FSCALE) * 100.0;
276 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 *ps = proc_state;
312 return proc_state_size;
313 }
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 }