sys-proctable 0.7.5 → 0.7.6

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,5 +1,21 @@
1
+ == 0.7.6 - 11-Jul-2007
2
+ * Fixed the starttime for Linux. Thanks go to Yaroslav Dmitriev for the spot.
3
+ * Fixed a bug in the MS Windows version within a private method that parsed
4
+ an MS specific date format. This was caused by a backwards incompatible
5
+ change in the Time.parse method in Ruby 1.8.6. See ruby-core: 11245 ff.
6
+ * Fixed the gemspec (I hope). Please let me know if you have problems.
7
+ * Added a Rakefile. Building, testing and installing should now be handled via
8
+ Rake tasks. The install.rb file has been removed - that code is now
9
+ integrated in the Rakefile.
10
+ * Minor directory layout changes and cleanup (mostly for the extconf.rb file).
11
+ * Side note - it seems that the code for OS X *does* work, at least on 10.4.10.
12
+ I can only conclude that previous reports about it failing were related to
13
+ bugs in OS X or were really just build issues. Apologies (and thanks, again)
14
+ to David Felstead for the code. However, see the README for more information
15
+ specific to OS X, as there are shortcomings.
16
+
1
17
  == 0.7.5 - 23-Nov-2006
2
- * Fixed int/long issues for Linux. Thanks go to Matt Lightner for the spot.
18
+ * Fixed int/long issues for Linux. Thanks go to Matt Lightner for the spot.
3
19
  * Minor documentation fixes and changes to the extconf.rb file.
4
20
 
5
21
  == 0.7.4 - 20-Nov-2006
data/MANIFEST CHANGED
@@ -1,7 +1,7 @@
1
1
  CHANGES
2
2
  INSTALL
3
3
  MANIFEST
4
- install.rb
4
+ Rakefile
5
5
  sys-proctable.gemspec
6
6
 
7
7
  doc/freebsd.txt
data/README CHANGED
@@ -13,17 +13,11 @@
13
13
  * FreeBSD (/proc or kvm)
14
14
  * Solaris
15
15
  * HP-UX
16
+ * OS X
16
17
 
17
18
  = Installation
18
- === UNIX
19
- cd ext; ruby extconf.rb
20
- make
21
- cd ..; ruby test/ts_all.rb (optional)
22
- make install
23
-
24
- === MS Windows
25
- ruby test/tc_windows.rb (optional)
26
- ruby install.rb
19
+ * rake test (optional)
20
+ * rake install
27
21
 
28
22
  = Synopsis
29
23
  require 'sys/proctable'
@@ -53,7 +47,7 @@
53
47
 
54
48
  = Notes
55
49
  Windows users may pass a host name as a second argument to get process
56
- information from a different host. This relies on the WMI service running.
50
+ information from a different host. This relies on the WMI service running.
57
51
 
58
52
  If you're building C source code, the ts_all.rb file is autogenerated for
59
53
  you.
@@ -61,56 +55,71 @@
61
55
  = Known Issues
62
56
  === BSD
63
57
  If you're building on FreeBSD, a standard /proc filesystem read approach is
64
- used if mounted. Otherwise, a kvm interface is used. There are more fields
58
+ used if mounted. Otherwise, a kvm interface is used. There are more fields
65
59
  available with the kvm interface, but keep in mind that you need to be a
66
- member of the kvm group (or root) to use this. You can tweak the
67
- extconf.rb file manually if you want to force the issue.
60
+ member of the kvm group (or root) to use this. You can tweak the extconf.rb
61
+ file manually if you want to force the issue.
68
62
 
69
- Not all fields are available on FreeBSD 5.x (yet). OpenBSD and NetBSD are
63
+ Not all fields are available on FreeBSD 5.x (yet). OpenBSD and NetBSD are
70
64
  not yet supported.
71
65
 
72
- Research has indicated that the kvm approach is less favored than a sysctl
73
- approach. I will try to add this interface in the 0.8.0 release.
74
-
75
66
  === Solaris
76
67
  The cmdline member on solaris is limited to 80 characters unless you (or
77
- your program) own the process. This is a Solaris design flaw/feature.
68
+ your program) own the process. This is a Solaris design flaw/feature.
69
+
70
+ === OS X
71
+ At the moment you do not get the full command line string. The code required
72
+ to get this information is obnoxious and I don't have any compelling desire
73
+ to add it. However, if you're willing to submit a patch I'll accept it.
74
+
75
+ You can find a good starting point with the OS X code found in Dan Urist's
76
+ Proc::ProcessTable module. You can find that module on CPAN. Point your
77
+ browser at http://search.cpan.org.
78
78
 
79
79
  === Misc
80
- If you build your library as a C extension (mandatory on all platforms
81
- except MS Windows at the moment), then the windows.rb file under 'lib/sys/'
82
- is renamed to 'windows.orig'. This is to prevent mkmf from auto-installing
83
- it during the 'make install' phase.
80
+ If you build your library as a C extension (which is what will happen if
81
+ you run the 'build', 'test', or 'install' Rake tasks), then the windows.rb
82
+ file under 'lib/sys/' is renamed to 'windows.orig'. This is necessary to
83
+ prevent mkmf from auto-installing it during the 'make install' phase.
84
+
85
+ The 'clean' Rake task will rename it back to 'windows.rb'.
84
86
 
85
87
  === Thread Safety
86
88
  I am not currently using a thread-safe version of readdir(). I am not
87
89
  especially concerned about it either. If you are trying to read information
88
90
  out of /proc from different threads at the same time there is something
89
- seriously wrong with your code logic. Using readdir_r() still won't solve
91
+ seriously wrong with your code logic. Using readdir_r() still won't solve
90
92
  all potential thread safety issues anyway.
91
93
 
92
94
  = Future Plans
93
95
  I'm considering using a pure Ruby version for Linux.
94
96
 
97
+ Research has indicated that the kvm approach is less favored than a sysctl
98
+ approach on BSD variants. I will try to add this interface in the 0.8.0
99
+ release.
100
+
95
101
  = Acknowledgements
96
102
  This package is largely based on the Perl module Proc::ProcessTable by
97
103
  Dan Urist. Many ideas, as well as large chunks of code, were taken
98
- from his work. So, a big THANK YOU goes out to Dan Urist.
104
+ from his work. So, a big THANK YOU goes out to Dan Urist.
99
105
 
100
106
  A big thanks also goes out to Mike Hall who was very helpful with ideas,
101
107
  logic and testing.
102
108
 
103
109
  Thanks also go to Sean Chittenden for providing an account on one of his
104
- FreeBSD machines. This is how the FreeBSD support was (initially) added.
110
+ FreeBSD machines. This is how the FreeBSD support was (initially) added.
105
111
 
106
112
  Thanks go to James Hranicky for providing a patch that grabs name, eid,
107
113
  euid, gid and guid info in the Linux version, along with some general
108
114
  debugging help.
109
115
 
116
+ Finally I'd like to thank all the folks who have submitted bug reports
117
+ and/or patches.
118
+
110
119
  = Help Wanted
111
- I do not have access to all platforms. There are a few other major platforms
112
- out there, namely OS X, AIX, OpenBSD, and IRIX, among others, that I would
113
- like to see ports for. There are two ways you can help - either submit code
120
+ I do not have access to all platforms. There are a few other major platforms
121
+ out there, namely AIX, OpenBSD, and IRIX, among others, that I would
122
+ like to see ports for. There are two ways you can help - either submit code
114
123
  for your particular platform or give me an account on your platform so I can
115
124
  develop on it.
116
125
 
@@ -122,7 +131,7 @@
122
131
  Ruby's
123
132
 
124
133
  = Copyright
125
- (C) 2003-2006 Daniel J. Berger
134
+ (C) 2003-2007 Daniel J. Berger
126
135
  All Rights Reserved.
127
136
 
128
137
  = Author
@@ -81,9 +81,7 @@ end
81
81
  ###################
82
82
  test_file = '../test/ts_all.rb'
83
83
  File.open(test_file, 'w'){ |fh|
84
- fh.puts '$LOAD_PATH.unshift Dir.pwd'
85
- fh.puts '$LOAD_PATH.unshift Dir.pwd + "/lib"'
86
- fh.puts '$LOAD_PATH.unshift Dir.pwd + "/ext"'
84
+ fh.puts "require 'tc_all'"
87
85
  fh.puts "require '#{tc_file}'"
88
86
  fh.puts "require 'tc_top'"
89
87
  }
@@ -0,0 +1,374 @@
1
+ /**************************************************************************
2
+ * sunos.c (proctable.c)
3
+ *
4
+ * Solaris 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
+ * The portion of code that grabs data out of /proc/xxx/as is based
9
+ * on a post by Roger Faulkner on comp.unix.questions.
10
+ **************************************************************************/
11
+ #include "ruby.h"
12
+ #include "sunos.h"
13
+ #include "version.h"
14
+
15
+ #ifdef __cplusplus
16
+ extern "C"
17
+ {
18
+ #endif
19
+
20
+ VALUE sProcStruct, cProcError;
21
+
22
+ /*
23
+ * Private method that converts a psinfo struct into a Ruby struct.
24
+ */
25
+ #ifdef HAVE_PROCFS_H
26
+ static VALUE proctable_getprocstruct(struct psinfo *p, VALUE v_cmd_array)
27
+ #else
28
+ static VALUE proctable_getprocstruct(struct prpsinfo *p, VALUE v_cmd_array)
29
+ #endif
30
+ {
31
+ char state[STATE_MAX];
32
+ char comm[COMM_MAX];
33
+ prusage_t pbuf;
34
+ VALUE cmdline;
35
+ VALUE rbTTY = Qnil;
36
+
37
+ /*
38
+ * If we were unable to get the full command line, resort to the limited
39
+ * pr_psargs struct member.
40
+ */
41
+ if(RARRAY(v_cmd_array)->len == 0)
42
+ cmdline = rb_str_new2(p->pr_psargs);
43
+ else
44
+ cmdline = rb_ary_join(v_cmd_array,rb_str_new2(" "));
45
+
46
+ if(PRNODEV != p->pr_ttydev)
47
+ rbTTY = UINT2NUM(p->pr_ttydev);
48
+ else
49
+ rbTTY = INT2NUM(-1);
50
+
51
+ #ifndef HAVE_PROCFS_H
52
+ char wchan[WCHAN_MAX];
53
+ sprintf(wchan, "%x", (unsigned int)p->pr_wchan);
54
+ #endif
55
+
56
+ #ifdef HAVE_PROCFS_H
57
+ switch(p->pr_lwp.pr_state)
58
+ #else
59
+ switch(p->pr_state)
60
+ #endif
61
+ {
62
+ case SSLEEP:
63
+ strcpy(state, SLEEP);
64
+ break;
65
+ case SRUN:
66
+ strcpy(state, RUN);
67
+ break;
68
+ case SZOMB:
69
+ strcpy(state, ZOMBIE);
70
+ break;
71
+ case SSTOP:
72
+ strcpy(state, STOP);
73
+ break;
74
+ case SIDL:
75
+ strcpy(state, IDLE);
76
+ break;
77
+ case SONPROC:
78
+ strcpy(state, ONPROC);
79
+ break;
80
+ }
81
+
82
+ strcpy(comm, p->pr_fname);
83
+
84
+ getprusage(p->pr_pid,&pbuf); /* Get the process usage info */
85
+
86
+ return rb_struct_new(sProcStruct,
87
+ INT2FIX(p->pr_flag),
88
+ #ifdef HAVE_PROCFS_H
89
+ INT2FIX(p->pr_nlwp),
90
+ #endif
91
+ UINT2NUM(p->pr_pid),
92
+ UINT2NUM(p->pr_ppid),
93
+ #ifdef HAVE_PROCFS_H
94
+ UINT2NUM(p->pr_pgid),
95
+ #else
96
+ UINT2NUM(p->pr_pgrp),
97
+ #endif
98
+ UINT2NUM(p->pr_sid),
99
+ UINT2NUM(p->pr_uid),
100
+ UINT2NUM(p->pr_euid),
101
+ UINT2NUM(p->pr_gid),
102
+ UINT2NUM(p->pr_egid),
103
+ #ifdef HAVE_PROCFS_H
104
+ INT2FIX(p->pr_lwp.pr_pri),
105
+ INT2FIX(p->pr_lwp.pr_nice),
106
+ #else
107
+ INT2FIX(p->pr_pri),
108
+ INT2FIX(p->pr_nice),
109
+ #endif
110
+ rbTTY,
111
+ INT2FIX(p->pr_time.tv_sec),
112
+ INT2FIX(p->pr_ctime.tv_sec),
113
+ #ifdef HAVE_PROCFS_H
114
+ INT2FIX(p->pr_size * 1024),
115
+ INT2FIX(p->pr_rssize * 1024),
116
+ UINT2NUM(p->pr_lwp.pr_wchan),
117
+ #else
118
+ INT2FIX(p->pr_bysize),
119
+ INT2FIX(p->pr_rssize),
120
+ rb_str_new2(wchan),
121
+ #endif
122
+ rb_float_new(((double)p->pr_pctcpu)/0x8000*100),
123
+ rb_float_new(((double)p->pr_pctmem)/0x8000*100),
124
+ rb_str_new2(state),
125
+ rb_str_new2(p->pr_fname),
126
+ cmdline,
127
+ rb_time_new(p->pr_start.tv_sec,0),
128
+ #ifdef HAVE_PROCFS_H
129
+ INT2NUM(p->pr_lwp.pr_onpro),
130
+ #endif
131
+ rb_str_new2(comm),
132
+ INT2FIX(p->pr_argc),
133
+ v_cmd_array,
134
+ LONG2FIX(pbuf.pr_lwpid),
135
+ INT2FIX(pbuf.pr_count),
136
+ LONG2FIX(pbuf.pr_tstamp.tv_sec),
137
+ LONG2FIX(pbuf.pr_create.tv_sec),
138
+ LONG2FIX(pbuf.pr_term.tv_sec),
139
+ LONG2FIX(pbuf.pr_rtime.tv_sec),
140
+ LONG2FIX(pbuf.pr_utime.tv_sec),
141
+ LONG2FIX(pbuf.pr_stime.tv_sec),
142
+ LONG2FIX(pbuf.pr_ttime.tv_sec),
143
+ LONG2FIX(pbuf.pr_tftime.tv_sec),
144
+ LONG2FIX(pbuf.pr_dftime.tv_sec),
145
+ LONG2FIX(pbuf.pr_kftime.tv_sec),
146
+ LONG2FIX(pbuf.pr_ltime.tv_sec),
147
+ LONG2FIX(pbuf.pr_slptime.tv_sec),
148
+ LONG2FIX(pbuf.pr_wtime.tv_sec),
149
+ LONG2FIX(pbuf.pr_stoptime.tv_sec),
150
+ ULONG2NUM(pbuf.pr_minf),
151
+ ULONG2NUM(pbuf.pr_majf),
152
+ ULONG2NUM(pbuf.pr_nswap),
153
+ ULONG2NUM(pbuf.pr_inblk),
154
+ ULONG2NUM(pbuf.pr_oublk),
155
+ ULONG2NUM(pbuf.pr_msnd),
156
+ ULONG2NUM(pbuf.pr_mrcv),
157
+ ULONG2NUM(pbuf.pr_sigs),
158
+ ULONG2NUM(pbuf.pr_vctx),
159
+ ULONG2NUM(pbuf.pr_ictx),
160
+ ULONG2NUM(pbuf.pr_sysc),
161
+ ULONG2NUM(pbuf.pr_ioch)
162
+ );
163
+ }
164
+
165
+ /*
166
+ * call-seq:
167
+ * ProcTable.ps(pid=nil)
168
+ * ProcTable.ps(pid=nil){ |ps| ... }
169
+ *
170
+ * In block form, yields a ProcTableStruct for each process entry that you
171
+ * have rights to. This method returns an array of ProcTableStruct's in
172
+ * non-block form.
173
+ *
174
+ * If a +pid+ is provided, then only a single ProcTableStruct is yielded or
175
+ * returned, or nil if no process information is found for that +pid+.
176
+ */
177
+ static VALUE proctable_ps(int argc, VALUE *argv, VALUE klass)
178
+ {
179
+ DIR *procdir;
180
+ struct dirent *procdirp;
181
+ int psdata;
182
+ char pathbuf[PATH_MAX];
183
+
184
+ char* arg;
185
+ uintptr_t addr_args;
186
+ uintptr_t* arg_vec;
187
+ size_t arg_len;
188
+ int fd, arg_count, i, pid;
189
+
190
+ VALUE v_pid;
191
+ VALUE v_ps_struct = Qnil;
192
+ VALUE v_array = Qnil;
193
+ VALUE v_cmd_array = rb_ary_new();
194
+
195
+ #ifdef HAVE_PROCFS_H
196
+ struct psinfo p;
197
+ char as_file[MAXPATHLEN];
198
+ #else
199
+ struct prpsinfo p;
200
+ #endif
201
+
202
+ rb_scan_args(argc, argv, "01", &v_pid);
203
+
204
+ if(!rb_block_given_p())
205
+ v_array = rb_ary_new();
206
+
207
+ if( (procdir = opendir( "/proc" )) == NULL )
208
+ rb_raise(cProcError,"/proc filesystem unreadable");
209
+
210
+ while( (procdirp = readdir(procdir)) != NULL )
211
+ {
212
+ /* Only look at this file if it's a proc id; that is, all numbers */
213
+ if(strtok(procdirp->d_name, "0123456789") != NULL ){ continue; }
214
+
215
+ /* If a pid is provided, only return info on that pid */
216
+ if(!NIL_P(v_pid)){
217
+ pid = NUM2INT(v_pid);
218
+ if(atoi(procdirp->d_name) != pid)
219
+ continue;
220
+ }
221
+
222
+ /* Construct path of the form /proc/proc_number */
223
+ strcpy(pathbuf, "/proc/");
224
+ strcpy(as_file, "/proc/");
225
+ strcat(pathbuf, procdirp->d_name);
226
+ strcat(as_file, procdirp->d_name);
227
+
228
+ #ifdef HAVE_PROCFS_H
229
+ strcat(pathbuf, "/psinfo"); /* Solaris 2.6+ has process info here */
230
+ strcat(as_file, "/as");
231
+ #endif
232
+
233
+ if( (psdata = open( pathbuf, O_RDONLY )) == -1 )
234
+ continue;
235
+
236
+ #ifdef HAVE_PROCFS_H
237
+ read(psdata, (void *) &p, sizeof(struct psinfo));
238
+ #else
239
+ if(ioctl(psdata, PIOCPSINFO, &p) == -1)
240
+ continue;
241
+ #endif
242
+
243
+ #ifdef HAVE_PROCFS_H
244
+ /*
245
+ * For those processes where it is possible to read /proc/xxx/as
246
+ * get the entire command line string.
247
+ */
248
+ addr_args = p.pr_argv;
249
+ arg_count = p.pr_argc;
250
+
251
+ if((fd = open(as_file, O_RDONLY)) < 0){
252
+ /* Do nothing - you can only get info on processes you rights to */
253
+ }
254
+ else
255
+ {
256
+ arg_vec = malloc(arg_count * sizeof(uintptr_t));
257
+
258
+ /* We need this here to pick up args properly on 2.8+ */
259
+ #ifdef PR_MODEL_NATIVE
260
+ if(p.pr_dmodel == PR_MODEL_NATIVE){
261
+ (void)pread(fd, arg_vec, arg_count * sizeof (uintptr_t), addr_args);
262
+ }
263
+ else{
264
+ caddr32_t *arg_vec32 = (caddr32_t *)arg_vec;
265
+ (void)pread(fd, arg_vec32, arg_count * sizeof (caddr32_t), addr_args);
266
+ for (i = arg_count - 1; i >= 0; --i)
267
+ {
268
+ arg_vec[i] = arg_vec32[i];
269
+ }
270
+ }
271
+ #else
272
+ /* Need a better patch for 2.6 here */
273
+ (void)pread(fd, arg_vec, arg_count * sizeof (uintptr_t), addr_args);
274
+ #endif
275
+
276
+ arg_len = 16;
277
+ arg = malloc(arg_len+1);
278
+ for(i = 0; i < arg_count; i++) {
279
+
280
+ if(pread(fd, arg, arg_len, arg_vec[i]) < 0)
281
+ continue;
282
+
283
+ arg[arg_len] = '\0';
284
+ if(strlen(arg) == arg_len){
285
+ arg_len *= 2;
286
+ arg = realloc(arg, arg_len + 1);
287
+ i--;
288
+ continue;
289
+ }
290
+ rb_ary_push(v_cmd_array, rb_str_new2(arg));
291
+ }
292
+ free(arg);
293
+ free(arg_vec);
294
+ }
295
+ close(fd);
296
+ #endif
297
+
298
+ close(psdata);
299
+ v_ps_struct = proctable_getprocstruct(&p, v_cmd_array);
300
+
301
+ if(rb_block_given_p()){
302
+ rb_yield(v_ps_struct);
303
+ }
304
+ else{
305
+ rb_ary_push(v_array, v_ps_struct);
306
+ }
307
+ rb_ary_clear(v_cmd_array);
308
+ }
309
+ closedir(procdir);
310
+
311
+ /* If a process ID was provided and found, return a single struct */
312
+ if(!NIL_P(v_pid))
313
+ return v_ps_struct;
314
+
315
+ return v_array; /* nil if block was provided */
316
+ }
317
+
318
+ /*
319
+ * call-seq:
320
+ * ProcTable.fields
321
+ *
322
+ * Returns an array of fields that each ProcTableStruct will contain. This
323
+ * may be useful if you want to know in advance what fields are available
324
+ * without having to perform at least one read of the /proc table.
325
+ */
326
+ static VALUE proctable_fields(VALUE klass){
327
+ uint_t i;
328
+ VALUE rbFarray = rb_ary_new();
329
+
330
+ for(i = 0; i < (sizeof(fields) / sizeof(fields[0])); i++)
331
+ rb_ary_push(rbFarray, rb_str_new2(fields[i]));
332
+
333
+ return rbFarray;
334
+ }
335
+
336
+ /*
337
+ * A Ruby interface for gathering process table information.
338
+ */
339
+ void Init_proctable(){
340
+ VALUE mSys, cProcTable;
341
+
342
+ /* Modules and Classes */
343
+ mSys = rb_define_module("Sys");
344
+ cProcTable = rb_define_class_under(mSys, "ProcTable", rb_cObject);
345
+ cProcError = rb_define_class_under(mSys, "ProcTableError", rb_eStandardError);
346
+
347
+ /* Class methods */
348
+ rb_define_singleton_method(cProcTable, "fields", proctable_fields, 0);
349
+ rb_define_singleton_method(cProcTable, "ps", proctable_ps, -1);
350
+
351
+ /* Constants */
352
+ rb_define_const(cProcTable, "VERSION", rb_str_new2(SYS_PROCTABLE_VERSION));
353
+
354
+ /* Structs */
355
+ sProcStruct = rb_struct_define("ProcTableStruct","flag",
356
+ #ifdef HAVE_PROCFS_H
357
+ "nlwp",
358
+ #endif
359
+ "pid","ppid","pgid","sid","uid","euid","gid","egid","priority","nice",
360
+ "ttydev","time","ctime","size","rss","wchan","pctcpu","pctmem","state",
361
+ "fname","cmdline","start",
362
+ #ifdef HAVE_PROCFS_H
363
+ "processor",
364
+ #endif
365
+ "comm","num_args","cmd_args","lwpid","count","tstamp","create","term",
366
+ "rtime","utime","stime","ttime","tftime","dftime","kftime","ltime",
367
+ "slptime","wtime","stoptime","minf","majf","nswap","inblk","oublk",
368
+ "msnd","mrcv","sigs","vctx","ictx","sysc","ioch",NULL
369
+ );
370
+ }
371
+
372
+ #ifdef __cplusplus
373
+ }
374
+ #endif