sys-proctable 0.7.6-i586-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/linux/linux.c ADDED
@@ -0,0 +1,320 @@
1
+ /***************************************************************
2
+ * linux.c (proctable.c)
3
+ *
4
+ * Linux specific code for the Ruby ps extension. Some code
5
+ * has been copied directly from Dan Urist's Proc::ProcessTable
6
+ * Perl module.
7
+ *
8
+ * Author: Daniel J. Berger
9
+ **************************************************************/
10
+ #include "ruby.h"
11
+ #include "linux.h"
12
+ #include "version.h"
13
+
14
+ #ifdef __cplusplus
15
+ extern "C"
16
+ {
17
+ #endif
18
+
19
+ VALUE sProc, cProcError;
20
+
21
+ /*
22
+ * Converts a proc_info struct into a Ruby struct.
23
+ */
24
+ static VALUE proctable_get_process(struct proc_info *p, VALUE env_hash) {
25
+ return rb_struct_new(sProc,
26
+ rb_str_new2(p->cmdline),
27
+ rb_str_new2(p->cwd),
28
+ rb_str_new2(p->exe),
29
+ INT2FIX(p->pid),
30
+ rb_str_new2(p->name),
31
+ INT2FIX(p->uid),
32
+ INT2FIX(p->euid),
33
+ INT2FIX(p->gid),
34
+ INT2FIX(p->egid),
35
+ rb_str_new2(p->comm),
36
+ rb_str_new(p->state,1),
37
+ INT2FIX(p->ppid),
38
+ INT2FIX(p->pgrp),
39
+ INT2FIX(p->session),
40
+ INT2FIX(p->tty_num),
41
+ INT2FIX(p->tpgid),
42
+ ULONG2NUM(p->flags),
43
+ ULONG2NUM(p->minflt),
44
+ ULONG2NUM(p->cminflt),
45
+ ULONG2NUM(p->majflt),
46
+ ULONG2NUM(p->cmajflt),
47
+ ULONG2NUM(p->utime),
48
+ ULONG2NUM(p->stime),
49
+ LONG2FIX(p->cutime),
50
+ LONG2FIX(p->cstime),
51
+ LONG2FIX(p->priority),
52
+ LONG2FIX(p->nice),
53
+ LONG2FIX(p->itrealvalue),
54
+ ULONG2NUM(boot_time() + (p->starttime / CLK_TCK)),
55
+ ULONG2NUM(p->vsize),
56
+ LONG2FIX(p->rss),
57
+ ULONG2NUM(p->rlim),
58
+ ULONG2NUM(p->startcode),
59
+ ULONG2NUM(p->endcode),
60
+ ULONG2NUM(p->startstack),
61
+ ULONG2NUM(p->kstkesp),
62
+ ULONG2NUM(p->kstkeip),
63
+ ULONG2NUM(p->signal),
64
+ ULONG2NUM(p->blocked),
65
+ ULONG2NUM(p->sigignore),
66
+ ULONG2NUM(p->sigcatch),
67
+ ULONG2NUM(p->wchan),
68
+ ULONG2NUM(p->nswap),
69
+ ULONG2NUM(p->cnswap),
70
+ INT2FIX(p->exit_signal),
71
+ INT2FIX(p->processor),
72
+ env_hash
73
+ );
74
+ }
75
+
76
+ /*
77
+ * call-seq:
78
+ * ProcTable.ps(pid=nil)
79
+ * ProcTable.ps(pid=nil){ |ps| ... }
80
+ *
81
+ * In block form, yields a ProcTableStruct for each process entry that you
82
+ * have rights to. This method returns an array of ProcTableStruct's in
83
+ * non-block form.
84
+ *
85
+ * If a +pid+ is provided, then only a single ProcTableStruct is yielded or
86
+ * returned, or nil if no process information is found for that +pid+.
87
+ */
88
+ static VALUE proctable_ps(int argc, VALUE *argv, VALUE klass){
89
+ DIR* dir_ptr;
90
+ FILE* file_ptr;
91
+ struct dirent* dirent_ptr;
92
+ struct proc_info p;
93
+ char pathbuf[NAME_MAX];
94
+ int temp, num_scanned;
95
+ int pid = -1;
96
+
97
+ VALUE v_pid = Qnil;
98
+ VALUE v_array = Qnil;
99
+ VALUE v_pstruct = Qnil;
100
+ VALUE v_env = rb_hash_new();
101
+
102
+ rb_scan_args(argc, argv, "01", &v_pid);
103
+
104
+ if((dir_ptr = opendir("/proc")) == NULL)
105
+ rb_raise(cProcError, "/proc filesystem unreadable");
106
+
107
+ if(!NIL_P(v_pid))
108
+ pid = NUM2INT(v_pid);
109
+
110
+ if(!rb_block_given_p())
111
+ v_array = rb_ary_new();
112
+
113
+ /* Iterate through all the (numeric) process entries uner /proc */
114
+ while((dirent_ptr = readdir(dir_ptr)) != NULL){
115
+
116
+ /* Only look at this file if it's a proc id; that is, all numbers */
117
+ if( strtok(dirent_ptr->d_name, "0123456789") != NULL )
118
+ continue;
119
+
120
+ if(!NIL_P(v_pid)){
121
+ if(atoi(dirent_ptr->d_name) != pid){
122
+ continue;
123
+ }
124
+ }
125
+
126
+ /* Get the /proc/PID/cmdline info */
127
+ sprintf(pathbuf, "%s%s%s", "/proc/", dirent_ptr->d_name, "/cmdline");
128
+ if( (file_ptr = fopen(pathbuf, "r")) != NULL ){
129
+ size_t got;
130
+ if((got = fread(p.cmdline, sizeof(char), ARG_MAX, file_ptr)) > 0 ){
131
+ size_t i;
132
+
133
+ /* Replace \0 characters with spaces */
134
+ for(i = 0; i < got; i++){
135
+ if(p.cmdline[i] == '\0'){
136
+ p.cmdline[i] = ' ';
137
+ }
138
+ }
139
+
140
+ p.cmdline[got] = '\0';
141
+ trimr(p.cmdline); /* Trim trailing whitespace */
142
+ }
143
+ fclose(file_ptr);
144
+ }
145
+
146
+ /* Get the /proc/PID/exe info (which is a link) */
147
+ sprintf(pathbuf, "%s%s%s", "/proc/", dirent_ptr->d_name, "/exe");
148
+ memset(p.exe, 0, sizeof(p.exe));
149
+
150
+ if(readlink(pathbuf, p.exe, sizeof(p.exe)) == -1){ /* Ignore */ }
151
+
152
+ /* Get the /proc/PID/cwd info (which is a link) */
153
+ sprintf(pathbuf, "%s%s%s", "/proc/", dirent_ptr->d_name, "/cwd");
154
+ memset(p.cwd, 0, sizeof(p.cwd));
155
+
156
+ if(readlink(pathbuf, p.cwd, sizeof(p.cwd)) == -1){ /* Ignore */ }
157
+
158
+ /* Get name, uid, euid, gid and gid info out of /proc/PID/status */
159
+ sprintf(pathbuf, "%s%s%s", "/proc/", dirent_ptr->d_name, "/status");
160
+
161
+ if((file_ptr = fopen(pathbuf,"r")) != NULL ){
162
+ char line[ARG_MAX];
163
+ char dummy[ARG_MAX];
164
+
165
+ while(fgets(line, ARG_MAX - 1, file_ptr) != NULL){
166
+ if(!strncmp("Name", line, strlen("Name"))) {
167
+ sscanf(line, "%s %s", dummy, p.name);
168
+ }
169
+ else if(!strncmp("Uid", line, strlen("Uid"))){
170
+ sscanf(line, "%s %d %d", dummy, &p.uid, &p.euid);
171
+ }
172
+ else if (!strncmp("Gid", line, strlen("Gid"))) {
173
+ sscanf(line, "%s %d %d", dummy, &p.gid, &p.egid);
174
+ }
175
+ }
176
+ fclose(file_ptr);
177
+ }
178
+
179
+ /* Get the /proc/PID/stat info */
180
+ sprintf(pathbuf,"%s%s%s","/proc/",dirent_ptr->d_name,"/stat");
181
+ if((file_ptr = fopen(pathbuf,"r")) != NULL){
182
+ num_scanned = fscanf(file_ptr,
183
+ "%d %s %s %d %d\
184
+ %d %d %d %lu %lu\
185
+ %lu %lu %lu %lu %lu\
186
+ %ld %ld %ld %ld %d\
187
+ %ld %lu %lu %ld %lu\
188
+ %lu %lu %lu %lu %lu\
189
+ %lu %lu %lu %lu %lu\
190
+ %lu %lu %d %d",
191
+ &p.pid, p.comm, p.state, &p.ppid, &p.pgrp,
192
+ &p.session, &p.tty_num, &p.tpgid, &p.flags, &p.minflt,
193
+ &p.cminflt, &p.majflt, &p.cmajflt, &p.utime, &p.stime,
194
+ &p.cutime, &p.cstime, &p.priority, &p.nice, &temp,
195
+ &p.itrealvalue,&p.starttime, &p.vsize, &p.rss, &p.rlim,
196
+ &p.startcode, &p.endcode, &p.startstack, &p.kstkesp, &p.kstkeip,
197
+ &p.signal, &p.blocked, &p.sigignore, &p.sigcatch, &p.wchan,
198
+ &p.nswap, &p.cnswap, &p.exit_signal,&p.processor
199
+ );
200
+
201
+ fclose(file_ptr);
202
+
203
+ if(num_scanned < 39)
204
+ rb_sys_fail("fscanf");
205
+ }
206
+
207
+ /* Get rid of the parens in the comm field */
208
+ strcpy(p.comm, strtok(p.comm,"()"));
209
+
210
+ /**********************************************************************
211
+ * Get the environ string out or /proc/PID/environ and make a hash
212
+ * out of it
213
+ **********************************************************************/
214
+ sprintf(pathbuf, "%s%s%s", "/proc/", dirent_ptr->d_name, "/environ");
215
+ if((file_ptr = fopen( pathbuf, "r" )) != NULL){
216
+
217
+ int count;
218
+ char env_buf[ARG_MAX];
219
+ char key[MAX_ENV_NAME];
220
+ char *next_var, *value;
221
+
222
+ /* Get char count */
223
+ count = fread(env_buf, sizeof(char), ARG_MAX, file_ptr);
224
+ next_var = env_buf;
225
+
226
+ while(next_var < env_buf + count){
227
+ value = strchr(next_var,'=');
228
+ /***************************************************************
229
+ * It's possible some environ files contain data that's not in
230
+ * the KEY=value format. For such cases, we'll just set the
231
+ * string as the key, and set the corresponding value to nil.
232
+ ***************************************************************/
233
+ if(NULL == value){
234
+ rb_hash_aset(v_env, rb_str_new2(next_var), Qnil);
235
+ break;
236
+ }
237
+ strncpy(key, next_var, value - next_var);
238
+ key[value-next_var] = '\0';
239
+
240
+ ++value;
241
+ rb_hash_aset(v_env, rb_str_new2(key), rb_str_new2(value));
242
+ next_var += strlen(next_var) + 1;
243
+ }
244
+
245
+ fclose(file_ptr);
246
+ }
247
+
248
+ /* If cmdline is empty, use comm instead */
249
+ if(0 == strlen(p.cmdline))
250
+ strcpy(p.cmdline, p.comm);
251
+
252
+ v_pstruct = proctable_get_process(&p, v_env);
253
+
254
+ if(rb_block_given_p())
255
+ rb_yield(v_pstruct);
256
+ else
257
+ rb_ary_push(v_array, v_pstruct);
258
+ }
259
+
260
+ closedir(dir_ptr);
261
+
262
+ /* If a process ID was provided and found, return a single struct */
263
+ if(!NIL_P(v_pid))
264
+ return v_pstruct;
265
+
266
+ return v_array; /* nil if block was provided */
267
+ }
268
+
269
+ /*
270
+ * call-seq:
271
+ * ProcTable.fields
272
+ *
273
+ * Returns an array of fields that each ProcTableStruct will contain. This
274
+ * may be useful if you want to know in advance what fields are available
275
+ * without having to perform at least one read of the /proc table.
276
+ */
277
+ static VALUE proctable_fields(VALUE klass){
278
+ unsigned int i;
279
+ VALUE rbFarray = rb_ary_new();
280
+
281
+ for(i = 0; i < sizeof(fields)/sizeof(fields[0]); i++)
282
+ rb_ary_push(rbFarray,rb_str_new2(fields[i]));
283
+
284
+ return rbFarray;
285
+ }
286
+
287
+ /*
288
+ * A Ruby interface for gathering process table information.
289
+ */
290
+ void Init_proctable()
291
+ {
292
+ VALUE mSys, cProcTable;
293
+
294
+ /* Modules and Classes */
295
+ mSys = rb_define_module("Sys");
296
+ cProcTable = rb_define_class_under(mSys, "ProcTable", rb_cObject);
297
+ cProcError = rb_define_class_under(mSys, "ProcTableError",rb_eStandardError);
298
+
299
+ /* Class Methods */
300
+ rb_define_singleton_method(cProcTable, "fields", proctable_fields, 0);
301
+ rb_define_singleton_method(cProcTable, "ps", proctable_ps, -1);
302
+
303
+ /* Constants */
304
+ rb_define_const(cProcTable,"VERSION",rb_str_new2(SYS_PROCTABLE_VERSION));
305
+
306
+ /* Structs */
307
+ sProc = rb_struct_define("ProcTableStruct","cmdline","cwd","exe","pid",
308
+ "name", "uid", "euid", "gid", "egid", "comm","state","ppid",
309
+ "pgrp","session","tty_num","tpgid","flags","minflt","cminflt","majflt",
310
+ "cmajflt","utime","stime","cutime","cstime","priority","nice",
311
+ "itrealvalue","starttime","vsize","rss","rlim","startcode","endcode",
312
+ "startstack","kstkesp","kstkeip","signal","blocked","sigignore",
313
+ "sigcatch","wchan","nswap","cnswap","exit_signal","processor","environ",
314
+ NULL
315
+ );
316
+ }
317
+
318
+ #ifdef __cplusplus
319
+ }
320
+ #endif
data/ext/linux/linux.h ADDED
@@ -0,0 +1,158 @@
1
+ /************************************************************************
2
+ * linux.h
3
+ *
4
+ * Linux specific information, including struct layout.
5
+ ************************************************************************/
6
+ #include <dirent.h>
7
+ #include <linux/limits.h>
8
+ #include <unistd.h>
9
+ #include <string.h>
10
+ #include <ctype.h>
11
+
12
+ #ifndef CLK_TCK
13
+ #define CLK_TCK sysconf(_SC_CLK_TCK)
14
+ #endif
15
+
16
+ #define MAX_ENV_NAME 128
17
+ #define BTIME_BUF 1024
18
+
19
+ /****************************************************************************
20
+ * Note that the 20th field (between nice and itrealvalue) is not included
21
+ * in our struct. It is a simple placeholder that was hardcoded for a
22
+ * removed field. See the proc man page for more details.
23
+ *
24
+ * Also note that the environ attribute is not part of this struct, mostly
25
+ * because I wouldn't know what type to set it to. It *is* part of the ruby
26
+ * struct, however.
27
+ ****************************************************************************/
28
+ struct proc_info{
29
+ char cmdline[ARG_MAX];
30
+ char cwd[ARG_MAX];
31
+ char exe[ARG_MAX];
32
+ int pid;
33
+ char name[ARG_MAX];
34
+ int uid;
35
+ int euid;
36
+ int gid;
37
+ int egid;
38
+ char comm[ARG_MAX];
39
+ char state[1];
40
+ int ppid;
41
+ int pgrp;
42
+ int session;
43
+ int tty_num;
44
+ int tpgid;
45
+ unsigned long flags;
46
+ unsigned long minflt;
47
+ unsigned long cminflt;
48
+ unsigned long majflt;
49
+ unsigned long cmajflt;
50
+ unsigned long utime;
51
+ unsigned long stime;
52
+ long cutime;
53
+ long cstime;
54
+ long priority;
55
+ long nice;
56
+ long itrealvalue;
57
+ unsigned long starttime;
58
+ unsigned long vsize;
59
+ long rss;
60
+ unsigned long rlim;
61
+ unsigned long startcode;
62
+ unsigned long endcode;
63
+ unsigned long startstack;
64
+ unsigned long kstkesp;
65
+ unsigned long kstkeip;
66
+ unsigned long signal;
67
+ unsigned long blocked;
68
+ unsigned long sigignore;
69
+ unsigned long sigcatch;
70
+ unsigned long wchan;
71
+ unsigned long nswap;
72
+ unsigned long cnswap;
73
+ int exit_signal;
74
+ int processor;
75
+ };
76
+
77
+ /*****************************************************************************
78
+ * This array's only purpose is for the 'fields()' class method. If there's
79
+ * a way to report fields out of our defined struct (sProc), please tell me
80
+ * how!
81
+ *****************************************************************************/
82
+ char *fields[] = {
83
+ "cmdline",
84
+ "cwd",
85
+ "exe",
86
+ "pid",
87
+ "name",
88
+ "uid",
89
+ "euid",
90
+ "gid",
91
+ "egid",
92
+ "comm",
93
+ "state",
94
+ "ppid",
95
+ "pgrp",
96
+ "session",
97
+ "tty_num",
98
+ "tpgid",
99
+ "flags",
100
+ "minflt",
101
+ "cminflt",
102
+ "majflt",
103
+ "cmajflt",
104
+ "utime",
105
+ "stime",
106
+ "cutime",
107
+ "cstime",
108
+ "priority",
109
+ "nice",
110
+ "itrealvalue",
111
+ "starttime",
112
+ "vsize",
113
+ "rss",
114
+ "rlim",
115
+ "startcode",
116
+ "endcode",
117
+ "startstack",
118
+ "kstkesp",
119
+ "kstkeip",
120
+ "signal",
121
+ "blocked",
122
+ "sigignore",
123
+ "sigcatch",
124
+ "wchan",
125
+ "nswap",
126
+ "cnswap",
127
+ "exit_signal",
128
+ "processor",
129
+ "environ"
130
+ };
131
+
132
+ /* Helper function to remove trailing whitespace. Use for cmdline info */
133
+ void trimr(char* s){
134
+ char* p = s + strlen(s);
135
+ while(--p >= s && isspace(*p))
136
+ ;
137
+
138
+ *++p = 0;
139
+ }
140
+
141
+ /* Helper function to get the boot time */
142
+ unsigned long boot_time(){
143
+ FILE* fp;
144
+ char buf[BTIME_BUF];
145
+ unsigned long btime = 0;
146
+
147
+ if((fp = fopen( "/proc/stat", "r" )) != NULL){
148
+ while(!feof(fp)){
149
+ if(fscanf(fp,"btime %ld", &btime) == 1)
150
+ break;
151
+ if(fgets(buf, BTIME_BUF, fp) == NULL)
152
+ break;
153
+ }
154
+ fclose(fp);
155
+ }
156
+
157
+ return btime;
158
+ }