sys-proctable 0.7.3 → 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,101 @@
1
+ #############################################################################
2
+ # Installation script for sys-proctable.
3
+ #
4
+ # By running this file, it is assumed that you want a C extension, and not
5
+ # a pure Ruby version. If you want a pure Ruby version (and you're on a
6
+ # platform for which it's supported), run install.rb instead.
7
+ #############################################################################
8
+ require 'mkmf'
9
+ require 'fileutils'
10
+
11
+ c_file = nil
12
+ h_file = nil
13
+ tc_file = nil
14
+
15
+ ########################################################################
16
+ # Ruby 1.8.3 and later mandates the use of rb_pid_t over pid_t because
17
+ # some libraries define their own pid_t. So, we check for that.
18
+ ########################################################################
19
+ have_type('rb_pid_t', 'ruby.h')
20
+
21
+ ##########################################################################
22
+ # Determine appropriate source files based on platform. Also, check for
23
+ # certain header files and/or libraries on some platforms.
24
+ #
25
+ # On FreeBSD a different source file is used if the /proc filesystem is
26
+ # not found (kvm is used instead). For OpenBSD or NetBSD, the kvm
27
+ # interface is always used for now.
28
+ ##########################################################################
29
+ case RUBY_PLATFORM
30
+ when /hpux/i
31
+ c_file = 'hpux/hpux.c'
32
+ h_file = 'hpux/hpux.h'
33
+ tc_file = 'tc_hpux'
34
+ when /freebsd/i
35
+ if File.exists?('/proc') && Dir['/proc/*'].length > 0
36
+ c_file = 'freebsd/freebsd.c'
37
+ h_file = 'freebsd/freebsd.h'
38
+ tc_file = 'tc_freebsd'
39
+ else
40
+ have_library('kvm')
41
+ have_struct_member('struct kinfo_proc', 'kp_proc', 'sys/user.h')
42
+ have_struct_member('struct kinfo_proc', 'kp_eproc', 'sys/user.h')
43
+ c_file = 'bsd/bsd.c'
44
+ tc_file = 'tc_kvm_bsd.rb'
45
+ end
46
+ when /openbsd|netbsd/
47
+ have_library('kvm')
48
+ c_file = 'bsd/bsd.c'
49
+ tc_file = 'tc_kvm_bsd.rb'
50
+ when /solaris|sunos/i
51
+ c_file = 'sunos/sunos.c'
52
+ h_file = 'sunos/sunos.h'
53
+ tc_file = 'tc_sunos'
54
+ have_header('procfs.h') # false means Solaris 2.5.x
55
+ when /linux/i
56
+ c_file = 'linux/linux.c'
57
+ h_file = 'linux/linux.h'
58
+ tc_file = 'tc_linux'
59
+ when /darwin/i
60
+ c_file = 'darwin/darwin.c'
61
+ tc_file = 'tc_darwin'
62
+ when /windows|win32|cygwin|mingw|dos/i
63
+ msg = 'Use the install_pure_ruby.rb script to install on MS Windows'
64
+ STDERR.puts msg
65
+ exit
66
+ else
67
+ puts 'This platform not currently supported. Exiting...'
68
+ exit
69
+ end
70
+
71
+ #####################################################################
72
+ # Move the 'windows.rb' file under 'lib/sys/' to '.orig' to prevent
73
+ # mkmf from installing it during the 'make install' phase.
74
+ #####################################################################
75
+ if File.exists?('../lib/sys/windows.rb')
76
+ File.rename('../lib/sys/windows.rb', '../lib/sys/windows.orig')
77
+ end
78
+
79
+ ###################
80
+ # build ts_all.rb
81
+ ###################
82
+ test_file = '../test/ts_all.rb'
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"'
87
+ fh.puts "require 'tc_all'"
88
+ fh.puts "require '#{tc_file}'"
89
+ fh.puts "require 'tc_top'"
90
+ }
91
+
92
+ ########################################################################
93
+ # Copy or link files to current directory for create_makefile to work.
94
+ ########################################################################
95
+ File.delete('proctable.c') rescue nil
96
+ File.delete(File.basename(h_file)) rescue nil
97
+
98
+ File.symlink(c_file, 'proctable.c')
99
+ File.symlink(h_file, File.basename(h_file)) if h_file
100
+
101
+ create_makefile('sys/proctable')
@@ -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