sys-proctable 0.9.9-universal-aix5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,218 @@
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+ require 'rbconfig'
5
+ include RbConfig
6
+
7
+ CLEAN.include(
8
+ '**/*.core', # Core dump files
9
+ '**/*.gem', # Gem files
10
+ '**/*.rbc', # Rubinius
11
+ '**/*.rbx', # Rubinius
12
+ '**/*.o', # C object file
13
+ '**/*.log', # Ruby extension build log
14
+ '**/Makefile', # C Makefile
15
+ '**/conftest.dSYM', # OS X build directory
16
+ "**/*.#{CONFIG['DLEXT']}" # C shared object
17
+ )
18
+
19
+ desc 'Build the sys-proctable library for C versions of sys-proctable'
20
+ task :build => [:clean] do
21
+ if RUBY_PLATFORM == 'java'
22
+ if ENV['JRUBY_OPTS']
23
+ ENV['JRUBY_OPTS'] += ' -Xcext.enabled=true'
24
+ else
25
+ ENV['JRUBY_OPTS'] = '-Xcext.enabled=true'
26
+ end
27
+ end
28
+
29
+ case CONFIG['host_os']
30
+ when /darwin/i
31
+ dir = 'ext/darwin'
32
+ ext = '.bundle'
33
+ when /hpux/i
34
+ dir = 'ext/hpux'
35
+ ext = '.sl'
36
+ end
37
+
38
+ if CONFIG['host_os'] =~ /darwin|hpux/i
39
+ Dir.chdir(dir) do
40
+ ruby 'extconf.rb'
41
+ sh 'make'
42
+ cp 'proctable' + ext, 'sys'
43
+ end
44
+ end
45
+ end
46
+
47
+ desc 'Install the sys-proctable library'
48
+ task :install => [:build] do
49
+ file = nil
50
+ dir = File.join(CONFIG['sitelibdir'], 'sys')
51
+
52
+ Dir.mkdir(dir) unless File.exists?(dir)
53
+
54
+ case CONFIG['host_os']
55
+ when /mswin|win32|msdos|cygwin|mingw|windows/i
56
+ file = 'lib/windows/sys/proctable.rb'
57
+ when /linux/i
58
+ file = 'lib/linux/sys/proctable.rb'
59
+ when /sunos|solaris/i
60
+ file = 'lib/sunos/sys/proctable.rb'
61
+ when /aix/i
62
+ file = 'lib/aix/sys/proctable.rb'
63
+ when /freebsd/i
64
+ file = 'lib/freebsd/sys/proctable.rb'
65
+ when /darwin/i
66
+ Dir.chdir('ext/darwin'){ sh 'make install' }
67
+ when /hpux/i
68
+ Dir.chdir('ext/hpux'){ sh 'make install' }
69
+ end
70
+
71
+ cp(file, dir, :verbose => true) if file
72
+ end
73
+
74
+ desc 'Uninstall the sys-proctable library'
75
+ task :uninstall do
76
+ case CONFIG['host_os']
77
+ when /darwin|hpux/i
78
+ dir = File.join(CONFIG['sitearchdir'], 'sys')
79
+ file = File.join(dir, 'proctable.' + CONFIG['DLEXT'])
80
+ else
81
+ dir = File.join(CONFIG['sitelibdir'], 'sys')
82
+ file = File.join(dir, 'proctable.rb')
83
+ end
84
+
85
+ rm(file)
86
+ end
87
+
88
+ desc 'Run the benchmark suite'
89
+ task :bench => [:build] do
90
+ sh "ruby -Ilib benchmarks/bench_ps.rb"
91
+ end
92
+
93
+ desc 'Run the example program'
94
+ task :example => [:build] do
95
+ sh 'ruby -Ilib -Iext examples/example_ps.rb'
96
+ end
97
+
98
+ desc 'Run the test suite'
99
+ Rake::TestTask.new do |t|
100
+ task :test => :build
101
+ t.libs << 'test' << '.'
102
+
103
+ case CONFIG['host_os']
104
+ when /mswin|msdos|cygwin|mingw|windows/i
105
+ t.test_files = FileList['test/test_sys_proctable_windows.rb']
106
+ t.libs << 'lib/windows'
107
+ when /linux/i
108
+ t.test_files = FileList['test/test_sys_proctable_linux.rb']
109
+ t.libs << 'lib/linux'
110
+ when /sunos|solaris/i
111
+ t.test_files = FileList['test/test_sys_proctable_sunos.rb']
112
+ t.libs << 'lib/sunos'
113
+ when /aix/i
114
+ t.test_files = FileList['test/test_sys_proctable_aix.rb']
115
+ t.libs << 'lib/aix'
116
+ when /freebsd/i
117
+ t.test_files = FileList['test/test_sys_proctable_freebsd.rb']
118
+ t.libs << 'lib/freebsd'
119
+ when /darwin/i
120
+ t.libs << 'ext/darwin'
121
+ t.test_files = FileList['test/test_sys_proctable_darwin.rb']
122
+ when /hpux/i
123
+ t.libs << 'ext/hpux'
124
+ t.test_files = FileList['test/test_sys_proctable_hpux.rb']
125
+ end
126
+ end
127
+
128
+ namespace :gem do
129
+ desc 'Create a gem for the specified OS, or your current OS by default'
130
+ task :create, [:os] => [:clean] do |_task, args|
131
+ require 'rubygems/package'
132
+
133
+ if args.is_a?(String)
134
+ os = args
135
+ else
136
+ args.with_defaults(:os => CONFIG['host_os'])
137
+ os = args[:os]
138
+ end
139
+
140
+ spec = eval(IO.read('sys-proctable.gemspec'))
141
+ spec.files += ['lib/sys-proctable.rb']
142
+
143
+ # I've had to manually futz with the spec here in some cases
144
+ # in order to get the universal platform settings I want because
145
+ # of some bugginess in Rubygems' platform.rb.
146
+ #
147
+ case os
148
+ when /freebsd/i
149
+ spec.platform = Gem::Platform.new(['universal', 'freebsd'])
150
+ spec.require_paths = ['lib', 'lib/freebsd']
151
+ spec.files += ['lib/freebsd/sys/proctable.rb']
152
+ spec.test_files << 'test/test_sys_proctable_freebsd.rb'
153
+ spec.add_dependency('ffi')
154
+ when /darwin/i
155
+ spec.platform = Gem::Platform.new(['universal', 'darwin'])
156
+ spec.files << 'ext/darwin/sys/proctable.c'
157
+ spec.extra_rdoc_files << 'ext/darwin/sys/proctable.c'
158
+ spec.test_files << 'test/test_sys_proctable_darwin.rb'
159
+ spec.extensions = ['ext/darwin/extconf.rb']
160
+ when /hpux/i
161
+ spec.platform = Gem::Platform.new(['universal', 'hpux'])
162
+ spec.files << 'ext/hpux/sys/proctable.c'
163
+ spec.extra_rdoc_files << 'ext/hpux/sys/proctable.c'
164
+ spec.test_files << 'test/test_sys_proctable_hpux.rb'
165
+ spec.extensions = ['ext/hpux/extconf.rb']
166
+ when /linux/i
167
+ spec.platform = Gem::Platform.new(['universal', 'linux'])
168
+ spec.require_paths = ['lib', 'lib/linux']
169
+ spec.files += ['lib/linux/sys/proctable.rb', 'lib/linux/sys/proctable/cgroup_entry.rb']
170
+ spec.test_files << 'test/test_sys_proctable_linux.rb'
171
+ when /sunos|solaris/i
172
+ spec.platform = Gem::Platform.new(['universal', 'solaris'])
173
+ spec.require_paths = ['lib', 'lib/sunos']
174
+ spec.files += ['lib/sunos/sys/proctable.rb']
175
+ spec.test_files << 'test/test_sys_proctable_sunos.rb'
176
+ when /aix/i
177
+ spec.platform = Gem::Platform.new(['universal', 'aix5'])
178
+ spec.require_paths = ['lib', 'lib/aix']
179
+ spec.files += ['lib/aix/sys/proctable.rb']
180
+ spec.test_files << 'test/test_sys_proctable_aix.rb'
181
+ when /mswin|win32|dos|cygwin|mingw|windows/i
182
+ spec.platform = Gem::Platform.new(['universal', 'mingw32'])
183
+ spec.require_paths = ['lib', 'lib/windows']
184
+ spec.files += ['lib/windows/sys/proctable.rb']
185
+ spec.test_files << 'test/test_sys_proctable_windows.rb'
186
+ else
187
+ raise "Unsupported platform: #{os}"
188
+ end
189
+
190
+ spec.test_files << 'test/test_sys_top.rb'
191
+
192
+ # https://github.com/rubygems/rubygems/issues/147
193
+ spec.original_platform = spec.platform
194
+
195
+ spec.signing_key = File.join(Dir.home, '.ssh', 'gem-private_key.pem')
196
+
197
+ Gem::Package.build(spec, true)
198
+ end
199
+
200
+ desc 'Create a gem for each supported OS'
201
+ task :create_all => [:clean] do
202
+ platforms = %w[aix darwin freebsd hpux linux solaris windows]
203
+ Rake::Task["clean"].execute
204
+ platforms.each{ |os|
205
+ FileUtils.mkdir_p("pkg/#{os}")
206
+ Rake::Task["gem:create"].execute(os)
207
+ Dir.glob("*.gem").each{ |gem| FileUtils.mv(gem, "pkg/#{os}") }
208
+ }
209
+ end
210
+
211
+ desc 'Install the sys-proctable library as a gem'
212
+ task :install => [:create] do
213
+ gem_name = Dir['*.gem'].first
214
+ sh "gem install -l #{gem_name}"
215
+ end
216
+ end
217
+
218
+ task :default => :test
@@ -0,0 +1,21 @@
1
+ ########################################################################
2
+ # bench_ps.rb
3
+ #
4
+ # Benchmark program to show overall speed and compare the block form
5
+ # versus the non-block form. You should run this benchmark via the
6
+ # 'rake bench' Rake task.
7
+ ########################################################################
8
+ require 'benchmark'
9
+ require 'sys/proctable'
10
+
11
+ MAX = 10
12
+
13
+ Benchmark.bm do |bench|
14
+ bench.report("Block form"){
15
+ MAX.times{ Sys::ProcTable.ps{} }
16
+ }
17
+
18
+ bench.report("Non-block form"){
19
+ MAX.times{ Sys::ProcTable.ps }
20
+ }
21
+ end
@@ -0,0 +1,47 @@
1
+ = Description
2
+ A simple 'top' interface for Ruby
3
+
4
+ = Prerequisites
5
+ Requires the "sys/proctable" package (which should be installed along
6
+ with this package).
7
+
8
+ = Synopsis
9
+ require "sys/top"
10
+
11
+ Sys::Top.top(5).each{ |ps|
12
+ p ps
13
+ }
14
+
15
+ = Constants
16
+ VERSION
17
+ Returns the version number of this package as a String.
18
+
19
+ = Class Methods
20
+ Sys::Top.top(number=10, field="pctcpu")
21
+ Returns an array of ProcTableStruct's. The size of the array (i.e. the
22
+ number of processes) that it returns is based on +number+, and sorted by
23
+ +pctcpu+. By default, the size and field values are 10 and "pctcpu",
24
+ respectively.
25
+
26
+ = Notes
27
+ Not all fields are available on all platforms. Please check your
28
+ platform specific documentation for which fields are available.
29
+
30
+ = Bugs
31
+ None that I'm aware of. Please log bug reports on the project page at
32
+ http://www.rubyforge.org/projects/sysutils
33
+
34
+ = License
35
+ Artistic 2.0
36
+
37
+ = Copyright
38
+ (C) 2004-2009 Daniel J. Berger
39
+ All Rights Reserved.
40
+
41
+ = Warranty
42
+ This package is provided "as is" and without any express or
43
+ implied warranties, including, without limitation, the implied
44
+ warranties of merchantability and fitness for a particular purpose.
45
+
46
+ = Author
47
+ Daniel J. Berger
@@ -0,0 +1,20 @@
1
+ #######################################################################
2
+ # example_ps.rb
3
+ #
4
+ # Generic test program that demonstrates the use of ProcTable.ps. You
5
+ # can run this via the 'rake example' task.
6
+ #
7
+ # Modify as you see fit
8
+ #######################################################################
9
+ require 'sys/proctable'
10
+ include Sys
11
+
12
+ puts "VERSION: " + ProcTable::VERSION
13
+ sleep 2
14
+
15
+ ProcTable.ps{ |s|
16
+ ProcTable.fields.each{ |field|
17
+ puts "#{field}: " + s.send(field).to_s
18
+ }
19
+ puts '=' * 30
20
+ }
@@ -0,0 +1,456 @@
1
+ #######################################################################
2
+ # proctable.rb
3
+ #
4
+ # A pure Ruby version of sys-proctable for AIX 5.3 or later.
5
+ ########################################################################
6
+ require 'sys/proctable/version'
7
+
8
+ # The Sys module serves as a namespace only.
9
+ module Sys
10
+
11
+ # The ProcTable class encapsulates process table information.
12
+ class ProcTable
13
+
14
+ class Error < StandardError; end
15
+
16
+ # There is no constructor
17
+ private_class_method :new
18
+
19
+ private
20
+
21
+ @fields = [
22
+ # --- psinfo_t ---
23
+ :flag, # process flags from proc struct p_flag
24
+ :flag2, # process flags from proc struct p_flag2
25
+ :nlwp, # number of threads in process
26
+ #:pad1, # reserved for future use
27
+ :uid, # real user id
28
+ :euid, # effective user id
29
+ :gid, # real group id
30
+ :egid, # effective group id
31
+ :pid, # unique process id
32
+ :ppid, # process id of parent
33
+ :pgid, # pid of process group leader
34
+ :sid, # session id
35
+ :ttydev, # controlling tty device (device #)
36
+ :s_ttydev, # controlling tty device name or '-'
37
+ :addr, # internal address of proc struct
38
+ :size, # process image size in KB (1024) units
39
+ :rssize, # resident set size in KB (1024) units
40
+ :start, # process start time, time since epoch
41
+ :time, # usr+sys cpu time for this process
42
+ :cid, # corral id
43
+ #:pad2, # reserved for future use
44
+ :argc, # initial argument count
45
+ :argv, # address of initial argument vector in user process
46
+ :envp, # address of initial environment vector in user process
47
+ :fname, # last component of exec()ed pathname
48
+ :psargs, # initial characters of arg list
49
+ #:pad, # reserved for future use
50
+
51
+ # --- lwpsinfo_t ---
52
+ :lwpid, # thread id
53
+ #:addr, # internal address of thread
54
+ :wchan, # wait addr for sleeping thread
55
+ #:flag, # thread flags
56
+ :wtype, # type of thread wait
57
+ :state, # thread state
58
+ :sname, # printable thread state character
59
+ :nice, # nice for cpu usage
60
+ :pri, # priority, high value = high priority
61
+ :policy, # scheduling policy
62
+ :clname, # printable scheduling policy string
63
+ :onpro, # processor on which thread last ran
64
+ :bindpro, # processor to which thread is bound
65
+ :ptid, # pthread id
66
+ #:pad1, # reserved for future use
67
+ #:pad, # reserved for future use
68
+
69
+ # --- prmap_t ---
70
+ :map, # array of prmap_t structures
71
+
72
+ # --- lwp ---
73
+ #:lwp # array of lwp information
74
+
75
+ # other...
76
+ :fd, # array of used file descriptors
77
+ :cmd_args, # array of command line arguments
78
+ :environ, # hash of environment associated with the process
79
+ :cmdline, # joined cmd_args if present, otherwise psargs
80
+ :cwd, # current working directory
81
+ ]
82
+
83
+ @psinfo_pack_directive = [
84
+ 'L', # pr_flag
85
+ 'L', # pr_flag2
86
+ 'L', # pr_nlwp
87
+ 'L', # pr__pad1
88
+ 'Q', # pr_uid
89
+ 'Q', # pr_euid
90
+ 'Q', # pr_gid
91
+ 'Q', # pr_egid
92
+ 'Q', # pr_pid
93
+ 'Q', # pr_ppid
94
+ 'Q', # pr_pgid
95
+ 'Q', # pr_sid
96
+ 'Q', # pr_ttydev
97
+ 'Q', # pr_addr
98
+ 'Q', # pr_size
99
+ 'Q', # pr_rssize
100
+ 'QlL', # pr_start
101
+ 'QlL', # pr_time
102
+ 'S', # pr_cid
103
+ 'S', # pr__pad2
104
+ 'L', # pr_argc
105
+ 'Q', # pr_argv
106
+ 'Q', # pr_envp
107
+ 'A16', # pr_fname[PRFNSZ]
108
+ 'A80', # pr_psargs[PRARGSZ]
109
+ 'Q8', # pr__pad[8]
110
+ # --- lwpsinfo_t --- pr_lwp
111
+ 'Q', # pr_lwpid
112
+ 'Q', # pr_addr
113
+ 'Q', # pr_wchan
114
+ 'L', # pr_flag
115
+ 'C', # pr_wtype
116
+ 'c', # pr_state
117
+ 'A', # pr_sname
118
+ 'C', # pr_nice
119
+ 'l', # pr_pri
120
+ 'L', # pr_policy
121
+ 'A8', # pr_clname
122
+ 'l', # pr_onpro
123
+ 'l', # pr_bindpro
124
+ 'L', # pr_ptid
125
+ 'L', # pr__pad1
126
+ 'Q7' # pr__pad[7]
127
+ ].join
128
+
129
+ # --- prmap_t ---
130
+ @map_fields = [
131
+ :size,
132
+ :vaddr,
133
+ :mapname,
134
+ :off,
135
+ :mflags,
136
+ :s_mflags,
137
+ :pathoff,
138
+ :alias,
139
+ :gp,
140
+ #:pad,
141
+ :path,
142
+ ]
143
+
144
+ @prmap_pack_directive = [
145
+ 'Q', # pr_size
146
+ 'Q', # pr_vaddr
147
+ 'A64', # pr_mapname[PRMAPSZ]
148
+ 'Q', # pr_off
149
+ 'L', # pr_mflags
150
+ 'L', # pr_pathoff
151
+ 'Q', # pr_alias
152
+ 'Q', # pr_gp
153
+ 'Q8', # pr__pad[8]
154
+ ].join
155
+
156
+ # prmap_t pr_mflags
157
+
158
+ PR_MFLAGS =
159
+ [
160
+ [ 0x80000000, 'main' ], # MA_MAINEXEC - main executable
161
+ [ 0x40000000, 'kernel' ], # MA_KERNTEXT - kernel text
162
+ [ 0x00000004, 'read' ], # MA_READ - readable
163
+ [ 0x00000002, 'write' ], # MA_WRITE - writable
164
+ [ 0x00000001, 'exec' ], # MA_EXEC - executable
165
+ [ 0x00000008, 'shared' ], # MA_SHARED - shared memory region
166
+ [ 0x00000010, 'heap' ], # MA_BREAK - heap -- grown by brk
167
+ [ 0x00000020, 'stack' ], # MA_STACK - stack -- grows on stack faults
168
+ ]
169
+
170
+ @devs = {}
171
+
172
+ Dir['/dev/**/*'].map do |filename|
173
+ begin
174
+ rdev = File.stat(filename).rdev
175
+ rescue
176
+ next
177
+ end
178
+
179
+ @devs[rdev] = filename[5..-1] if rdev.nonzero?
180
+ end
181
+
182
+ public
183
+
184
+ ProcTableStruct = Struct.new("ProcTableStruct", *@fields) do
185
+ alias comm fname
186
+ end
187
+
188
+ ProcTableMapStruct = Struct.new("ProcTableMapStruct", *@map_fields)
189
+
190
+ # In block form, yields a ProcTableStruct for each process entry that you
191
+ # have rights to. This method returns an array of ProcTableStruct's in
192
+ # non-block form.
193
+ #
194
+ # If a +pid+ is provided, then only a single ProcTableStruct is yielded or
195
+ # returned, or nil if no process information is found for that +pid+.
196
+ #
197
+ # Example:
198
+ #
199
+ # # Iterate over all processes
200
+ # ProcTable.ps do |proc_info|
201
+ # p proc_info
202
+ # end
203
+ #
204
+ # # Print process table information for only pid 1001
205
+ # p ProcTable.ps(1001)
206
+ #
207
+ def self.ps(pid = nil)
208
+ raise TypeError unless (pid.is_a?(Fixnum) || pid.is_a?(Bignum)) if pid
209
+
210
+ array = block_given? ? nil : []
211
+ struct = nil
212
+
213
+ Dir.foreach("/proc") do |file|
214
+ next if file =~ /\D/ # Skip non-numeric entries under /proc
215
+
216
+ # Only return information for a given pid, if provided
217
+ if pid
218
+ next unless file.to_i == pid
219
+ end
220
+
221
+ # Skip over any entries we don't have permissions to read
222
+ next unless File.readable?("/proc/#{file}/psinfo")
223
+
224
+ psinfo = IO.read("/proc/#{file}/psinfo") rescue next
225
+
226
+ psinfo_array = psinfo.unpack(@psinfo_pack_directive)
227
+
228
+ struct = ProcTableStruct.new
229
+
230
+ struct.flag = psinfo_array[0] # pr_flag
231
+ struct.flag2 = psinfo_array[1] # pr_flag2
232
+ struct.nlwp = psinfo_array[2] # pr_nlwp
233
+ # pr__pad1
234
+ struct.uid = psinfo_array[4] # pr_uid
235
+ struct.euid = psinfo_array[5] # pr_euid
236
+ struct.gid = psinfo_array[6] # pr_gid
237
+ struct.egid = psinfo_array[7] # pr_egid
238
+ struct.pid = psinfo_array[8] # pr_pid
239
+ struct.ppid = psinfo_array[9] # pr_ppid
240
+ struct.pgid = psinfo_array[10] # pr_pgid
241
+ struct.sid = psinfo_array[11] # pr_sid
242
+ struct.ttydev = psinfo_array[12] # pr_ttydev
243
+
244
+ # convert from 64-bit dev_t to 32-bit dev_t and then map the device
245
+ # number to a name
246
+ ttydev = struct.ttydev
247
+ ttydev = (((ttydev & 0x0000FFFF00000000) >> 16) | (ttydev & 0xFFFF))
248
+ struct.s_ttydev = @devs.has_key?(ttydev) ? @devs[ttydev] : '-'
249
+
250
+ struct.addr = psinfo_array[13] # pr_addr
251
+ struct.size = psinfo_array[14] * 1024 # pr_size
252
+ struct.rssize = psinfo_array[15] * 1024 # pr_rssize
253
+ struct.start = Time.at(psinfo_array[16], psinfo_array[17]) # pr_start
254
+ # skip pr_start.__pad
255
+ struct.time = psinfo_array[19] # pr_time
256
+ # skip pr_time.tv_nsec and pr_time.__pad
257
+ struct.cid = psinfo_array[22] # pr_cid
258
+ # skip pr__pad2
259
+ struct.argc = psinfo_array[24] # pr_argc
260
+ struct.argv = psinfo_array[25] # pr_argv
261
+ struct.envp = psinfo_array[26] # pr_envp
262
+ struct.fname = psinfo_array[27] # pr_fname
263
+ struct.psargs = psinfo_array[28] # pr_psargs
264
+ # skip pr__pad
265
+
266
+ ### lwpsinfo_t info
267
+
268
+ struct.lwpid = psinfo_array[37] # pr_lwpid
269
+ # skip pr_addr
270
+ struct.wchan = psinfo_array[39] # pr_wchan
271
+ # skip pr_flag
272
+ struct.wtype = psinfo_array[41] # pr_wtype
273
+ struct.state = psinfo_array[42] # pr_state
274
+ struct.sname = psinfo_array[43] # pr_sname
275
+ struct.nice = psinfo_array[44] # pr_nice
276
+ struct.pri = psinfo_array[45] # pr_pri
277
+ struct.policy = psinfo_array[46] # pr_policy
278
+ struct.clname = psinfo_array[47] # pr_clname
279
+ struct.onpro = psinfo_array[48] # pr_onpro
280
+ struct.bindpro = psinfo_array[49] # pr_bindpro
281
+ struct.ptid = psinfo_array[50] # pr_ptid
282
+ # skip pr__pad1
283
+ # skip pr__pad
284
+
285
+ # Get the full command line out of /proc/<pid>/as.
286
+ begin
287
+ File.open("/proc/#{file}/as", 'rb') do |fd|
288
+ np = fd.sysseek(struct.argv, IO::SEEK_SET)
289
+
290
+ if np != struct.argv
291
+ raise Error, "argv seek to #{struct.argv}, result #{np}", caller
292
+ end
293
+
294
+ argv = fd.sysread(4).unpack('L')[0]
295
+
296
+ np = fd.sysseek(argv, IO::SEEK_SET)
297
+
298
+ if np != argv
299
+ raise Error, "*argv seek to #{argv}, result #{np}", caller
300
+ end
301
+
302
+ argv = fd.sysread(4 * struct.argc).unpack("L#{struct.argc}")
303
+
304
+ struct.cmd_args = []
305
+
306
+ argv.each_with_index do |address, i|
307
+ np = fd.sysseek(address, IO::SEEK_SET)
308
+
309
+ if np != address
310
+ raise Error, "argv[#{i}] seek to #{address}, result #{np}",
311
+ caller
312
+ end
313
+
314
+ data = fd.sysread(512)[/^[^\0]*/] # Null strip
315
+ struct.cmd_args << data
316
+ end
317
+
318
+ # Get the environment hash associated with the process.
319
+ struct.environ = {}
320
+
321
+ # First have to go to the address given by struct.envp. That will
322
+ # give us the address of the environment pointer array.
323
+
324
+ np = fd.sysseek(struct.envp, IO::SEEK_SET)
325
+
326
+ if np != struct.envp
327
+ raise Error, "envp seek to #{struct.envp}, result #{np}", caller
328
+ end
329
+
330
+ envloc = fd.sysread(4).unpack('L')[0]
331
+ n = 0
332
+
333
+ loop do
334
+ np = fd.sysseek(envloc, IO::SEEK_SET)
335
+
336
+ if np != envloc
337
+ raise Error, "envp[#{n}] seek to #{envloc}, result #{np}",
338
+ caller
339
+ end
340
+
341
+ envp = fd.sysread(4).unpack("L")[0]
342
+ break if envp.zero?
343
+ np = fd.sysseek(envp, IO::SEEK_SET)
344
+ data = fd.sysread(1024)[/^[^\0]*/] # Null strip
345
+ key, value = data.split('=')
346
+ struct.environ[key] = value
347
+ envloc += 4
348
+ n += 1
349
+ end
350
+ end
351
+ rescue Errno::EACCES, Errno::EOVERFLOW, EOFError
352
+ # Skip this if we don't have proper permissions, if there's
353
+ # no associated environment, or if there's a largefile issue.
354
+ rescue Errno::ENOENT
355
+ next # The process has terminated. Bail out!
356
+ end
357
+
358
+ # Information from /proc/<pid>/fd. This returns an array of
359
+ # numeric file descriptors used by the process.
360
+ struct.fd = Dir["/proc/#{file}/fd/*"].map { |f| File.basename(f).to_i }
361
+
362
+ # Use the cmd_args as the cmdline if available. Otherwise use
363
+ # the psargs. This struct member is provided to provide a measure
364
+ # of consistency with the other platform implementations.
365
+ if struct.cmd_args.nil? || struct.cmd_args.empty?
366
+ struct.cmdline = struct.psargs
367
+ else
368
+ struct.cmdline = struct.cmd_args.join(' ')
369
+ end
370
+
371
+ # get current working directory from /proc/<pid>/cwd
372
+ struct.cwd = File.readlink("/proc/#{file}/cwd") rescue nil
373
+
374
+ # get virtual address map from /proc/<pid>/map
375
+ begin
376
+ struct.map = []
377
+
378
+ File.open("/proc/#{file}/map", 'rb') do |fd|
379
+ loop do
380
+ prmap_array = fd.sysread(176).unpack(@prmap_pack_directive)
381
+ break if prmap_array[0].zero?
382
+
383
+ map_struct = ProcTableMapStruct.new
384
+
385
+ map_struct.size = prmap_array[0] # pr_size
386
+ map_struct.vaddr = prmap_array[1] # pr_vaddr
387
+ map_struct.mapname = prmap_array[2] # pr_mapname
388
+ map_struct.off = prmap_array[3] # pr_off
389
+ map_struct.mflags = prmap_array[4] # pr_mflags
390
+
391
+ # convert pr_mflags value to string sort of like procmap outputs
392
+ mflags = map_struct.mflags
393
+ map_struct.s_mflags = ''
394
+ sep = ''
395
+
396
+ PR_MFLAGS.each do |flag|
397
+ if (mflags & flag[0]).nonzero?
398
+ map_struct.s_mflags << sep << flag[1]
399
+ sep = '/'
400
+ mflags &= ~flag[0]
401
+ end
402
+ end
403
+
404
+ if mflags.nonzero?
405
+ map_struct.s_mflags << sep << sprintf('%08x', mflags)
406
+ end
407
+
408
+ map_struct.pathoff = prmap_array[5] # pr_pathoff
409
+ map_struct.alias = prmap_array[6] # pr_alias
410
+ map_struct.gp = prmap_array[7] # pr_gp
411
+
412
+ struct.map << map_struct
413
+ end
414
+
415
+ struct.map.each do |m|
416
+ next if m.pathoff.zero?
417
+ fd.sysseek(m.pathoff, IO::SEEK_SET)
418
+ buf = fd.sysread(4096)
419
+ buf =~ /^([^\0]*)\0([^\0]*)\0/
420
+ m.path = $2.empty? ? $1 : "#{$1}(#{$2})"
421
+ end
422
+ end
423
+
424
+ struct.map = nil if struct.map.empty?
425
+ rescue
426
+ struct.map = nil
427
+ end
428
+
429
+ # This is read-only data
430
+ struct.freeze
431
+
432
+ if block_given?
433
+ yield struct
434
+ else
435
+ array << struct
436
+ end
437
+ end
438
+
439
+ pid ? struct : array
440
+ end
441
+
442
+ # Returns an array of fields that each ProcTableStruct will contain. This
443
+ # may be useful if you want to know in advance what fields are available
444
+ # without having to perform at least one read of the /proc table.
445
+ #
446
+ # Example:
447
+ #
448
+ # Sys::ProcTable.fields.each do |field|
449
+ # puts "Field: #{field}"
450
+ # end
451
+ #
452
+ def self.fields
453
+ @fields.map{ |f| f.to_s }
454
+ end
455
+ end
456
+ end