sys-proctable 0.7.3 → 0.7.4

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.
@@ -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