sys-proctable 0.9.9-universal-aix5

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,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