sys-proctable 0.7.6 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +1 -0
  4. data/CHANGES +165 -0
  5. data/MANIFEST +33 -41
  6. data/README +115 -135
  7. data/Rakefile +94 -0
  8. data/benchmarks/bench_ps.rb +21 -0
  9. data/doc/top.txt +5 -11
  10. data/examples/example_ps.rb +20 -0
  11. data/lib/aix/sys/proctable.rb +458 -0
  12. data/lib/darwin/sys/proctable.rb +363 -0
  13. data/lib/freebsd/sys/proctable.rb +363 -0
  14. data/lib/linux/sys/proctable.rb +314 -0
  15. data/lib/linux/sys/proctable/cgroup_entry.rb +50 -0
  16. data/lib/linux/sys/proctable/smaps.rb +118 -0
  17. data/lib/sunos/sys/proctable.rb +456 -0
  18. data/lib/sys-proctable.rb +1 -0
  19. data/lib/sys-top.rb +1 -0
  20. data/lib/sys/proctable.rb +18 -0
  21. data/lib/sys/proctable/version.rb +6 -0
  22. data/lib/sys/top.rb +28 -19
  23. data/lib/windows/sys/proctable.rb +208 -0
  24. data/spec/sys_proctable_aix_spec.rb +328 -0
  25. data/spec/sys_proctable_all_spec.rb +89 -0
  26. data/spec/sys_proctable_darwin_spec.rb +120 -0
  27. data/spec/sys_proctable_freebsd_spec.rb +210 -0
  28. data/spec/sys_proctable_linux_spec.rb +310 -0
  29. data/spec/sys_proctable_sunos_spec.rb +316 -0
  30. data/spec/sys_proctable_windows_spec.rb +317 -0
  31. data/spec/sys_top_spec.rb +51 -0
  32. data/sys-proctable.gemspec +38 -0
  33. metadata +140 -64
  34. metadata.gz.sig +0 -0
  35. data/doc/freebsd.txt +0 -90
  36. data/doc/hpux.txt +0 -77
  37. data/doc/linux.txt +0 -85
  38. data/doc/solaris.txt +0 -99
  39. data/doc/windows.txt +0 -122
  40. data/ext/extconf.rb +0 -98
  41. data/ext/sunos/sunos.c +0 -374
  42. data/ext/sunos/sunos.h +0 -177
  43. data/ext/version.h +0 -2
  44. data/test/tc_all.rb +0 -59
  45. data/test/tc_freebsd.rb +0 -45
  46. data/test/tc_hpux.rb +0 -49
  47. data/test/tc_kvm_bsd.rb +0 -31
  48. data/test/tc_linux.rb +0 -45
  49. data/test/tc_sunos.rb +0 -52
  50. data/test/tc_top.rb +0 -26
  51. data/test/tc_windows.rb +0 -40
  52. data/test/test_memleak.rb +0 -54
@@ -0,0 +1,94 @@
1
+ require 'rake'
2
+ require 'rake/clean'
3
+ require 'rake/testtask'
4
+ require 'rbconfig'
5
+ require 'rspec/core/rake_task'
6
+ include RbConfig
7
+
8
+ CLEAN.include('**/*.gem', '**/*.rbc')
9
+
10
+ desc 'Install the sys-proctable library'
11
+ task :install do
12
+ file = nil
13
+ dir = File.join(CONFIG['sitelibdir'], 'sys')
14
+
15
+ Dir.mkdir(dir) unless File.exists?(dir)
16
+
17
+ case CONFIG['host_os']
18
+ when /mswin|win32|msdos|cygwin|mingw|windows/i
19
+ file = 'lib/windows/sys/proctable.rb'
20
+ when /linux/i
21
+ file = 'lib/linux/sys/proctable.rb'
22
+ when /sunos|solaris/i
23
+ file = 'lib/sunos/sys/proctable.rb'
24
+ when /aix/i
25
+ file = 'lib/aix/sys/proctable.rb'
26
+ when /freebsd/i
27
+ file = 'lib/freebsd/sys/proctable.rb'
28
+ when /darwin/i
29
+ file = 'lib/darwin/sys/proctable.rb'
30
+ end
31
+
32
+ cp(file, dir, :verbose => true) if file
33
+ end
34
+
35
+ desc 'Uninstall the sys-proctable library'
36
+ task :uninstall do
37
+ dir = File.join(CONFIG['sitelibdir'], 'sys')
38
+ file = File.join(dir, 'proctable.rb')
39
+ rm(file)
40
+ end
41
+
42
+ desc 'Run the benchmark suite'
43
+ task :bench do
44
+ sh "ruby -Ilib benchmarks/bench_ps.rb"
45
+ end
46
+
47
+ desc 'Run the example program'
48
+ task :example do
49
+ sh 'ruby -Ilib -Iext examples/example_ps.rb'
50
+ end
51
+
52
+ desc 'Run the test suite for the sys-proctable library'
53
+ RSpec::Core::RakeTask.new(:spec) do |t|
54
+ t.pattern = ['spec/sys_proctable_all_spec.rb']
55
+
56
+ case CONFIG['host_os']
57
+ when /aix/i
58
+ t.rspec_opts = '-Ilib/aix'
59
+ t.pattern << 'spec/sys_proctable_aix.rb'
60
+ when /darwin/i
61
+ t.rspec_opts = '-Ilib/darwin'
62
+ t.pattern << 'spec/sys_proctable_darwin_spec.rb'
63
+ when /freebsd/i
64
+ t.rspec_opts = '-Ilib/freebsd'
65
+ t.pattern << 'spec/sys_proctable_freebsd_spec.rb'
66
+ when /linux/i
67
+ t.rspec_opts = '-Ilib/linux'
68
+ t.pattern << 'spec/sys_proctable_linux_spec.rb'
69
+ when /sunos|solaris/i
70
+ t.rspec_opts = '-Ilib/sunos'
71
+ t.pattern << 'spec/sys_proctable_sunos_spec.rb'
72
+ when /mswin|msdos|cygwin|mingw|windows/i
73
+ t.rspec_opts = '-Ilib/windows'
74
+ t.pattern << 'spec/sys_proctable_windows_spec.rb'
75
+ end
76
+ end
77
+
78
+ namespace :gem do
79
+ desc 'Create a gem for the specified OS, or your current OS by default'
80
+ task :create => [:clean] do
81
+ require 'rubygems/package'
82
+ spec = eval(IO.read('sys-proctable.gemspec'))
83
+ spec.signing_key = File.join(Dir.home, '.ssh', 'gem-private_key.pem')
84
+ Gem::Package.build(spec, true)
85
+ end
86
+
87
+ desc 'Install the sys-proctable library as a gem'
88
+ task :install => [:create] do
89
+ gem_name = Dir['*.gem'].first
90
+ sh "gem install -l #{gem_name}"
91
+ end
92
+ end
93
+
94
+ task :default => :spec
@@ -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
@@ -7,9 +7,8 @@
7
7
 
8
8
  = Synopsis
9
9
  require "sys/top"
10
- include Sys
11
10
 
12
- Top.top(5).each{ |ps|
11
+ Sys::Top.top(5).each{ |ps|
13
12
  p ps
14
13
  }
15
14
 
@@ -18,7 +17,7 @@ VERSION
18
17
  Returns the version number of this package as a String.
19
18
 
20
19
  = Class Methods
21
- Top.top(number=10, field="pctcpu")
20
+ Sys::Top.top(number=10, field="pctcpu")
22
21
  Returns an array of ProcTableStruct's. The size of the array (i.e. the
23
22
  number of processes) that it returns is based on +number+, and sorted by
24
23
  +pctcpu+. By default, the size and field values are 10 and "pctcpu",
@@ -27,19 +26,16 @@ Top.top(number=10, field="pctcpu")
27
26
  = Notes
28
27
  Not all fields are available on all platforms. Please check your
29
28
  platform specific documentation for which fields are available.
30
-
31
- I used sort() instead of sort_by() internally to maintain backward
32
- compatability with Ruby 1.6.8, which I happen to need.
33
29
 
34
30
  = Bugs
35
31
  None that I'm aware of. Please log bug reports on the project page at
36
32
  http://www.rubyforge.org/projects/sysutils
37
33
 
38
34
  = License
39
- Ruby's
35
+ Artistic 2.0
40
36
 
41
37
  = Copyright
42
- (C) 2004-2006 Daniel J. Berger
38
+ (C) 2004-2009 Daniel J. Berger
43
39
  All Rights Reserved.
44
40
 
45
41
  = Warranty
@@ -48,6 +44,4 @@ Top.top(number=10, field="pctcpu")
48
44
  warranties of merchantability and fitness for a particular purpose.
49
45
 
50
46
  = Author
51
- Daniel J. Berger
52
- djberg96 at nospam at gmail dot com
53
- imperator on IRC (Freenode)
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,458 @@
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(pid: 1001)
206
+ #
207
+ def self.ps(**kwargs)
208
+ pid = kwargs[:pid]
209
+
210
+ raise TypeError unless pid.is_a?(Numeric) if pid
211
+
212
+ array = block_given? ? nil : []
213
+ struct = nil
214
+
215
+ Dir.foreach("/proc") do |file|
216
+ next if file =~ /\D/ # Skip non-numeric entries under /proc
217
+
218
+ # Only return information for a given pid, if provided
219
+ if pid
220
+ next unless file.to_i == pid
221
+ end
222
+
223
+ # Skip over any entries we don't have permissions to read
224
+ next unless File.readable?("/proc/#{file}/psinfo")
225
+
226
+ psinfo = IO.read("/proc/#{file}/psinfo") rescue next
227
+
228
+ psinfo_array = psinfo.unpack(@psinfo_pack_directive)
229
+
230
+ struct = ProcTableStruct.new
231
+
232
+ struct.flag = psinfo_array[0] # pr_flag
233
+ struct.flag2 = psinfo_array[1] # pr_flag2
234
+ struct.nlwp = psinfo_array[2] # pr_nlwp
235
+ # pr__pad1
236
+ struct.uid = psinfo_array[4] # pr_uid
237
+ struct.euid = psinfo_array[5] # pr_euid
238
+ struct.gid = psinfo_array[6] # pr_gid
239
+ struct.egid = psinfo_array[7] # pr_egid
240
+ struct.pid = psinfo_array[8] # pr_pid
241
+ struct.ppid = psinfo_array[9] # pr_ppid
242
+ struct.pgid = psinfo_array[10] # pr_pgid
243
+ struct.sid = psinfo_array[11] # pr_sid
244
+ struct.ttydev = psinfo_array[12] # pr_ttydev
245
+
246
+ # convert from 64-bit dev_t to 32-bit dev_t and then map the device
247
+ # number to a name
248
+ ttydev = struct.ttydev
249
+ ttydev = (((ttydev & 0x0000FFFF00000000) >> 16) | (ttydev & 0xFFFF))
250
+ struct.s_ttydev = @devs.has_key?(ttydev) ? @devs[ttydev] : '-'
251
+
252
+ struct.addr = psinfo_array[13] # pr_addr
253
+ struct.size = psinfo_array[14] * 1024 # pr_size
254
+ struct.rssize = psinfo_array[15] * 1024 # pr_rssize
255
+ struct.start = Time.at(psinfo_array[16], psinfo_array[17]) # pr_start
256
+ # skip pr_start.__pad
257
+ struct.time = psinfo_array[19] # pr_time
258
+ # skip pr_time.tv_nsec and pr_time.__pad
259
+ struct.cid = psinfo_array[22] # pr_cid
260
+ # skip pr__pad2
261
+ struct.argc = psinfo_array[24] # pr_argc
262
+ struct.argv = psinfo_array[25] # pr_argv
263
+ struct.envp = psinfo_array[26] # pr_envp
264
+ struct.fname = psinfo_array[27] # pr_fname
265
+ struct.psargs = psinfo_array[28] # pr_psargs
266
+ # skip pr__pad
267
+
268
+ ### lwpsinfo_t info
269
+
270
+ struct.lwpid = psinfo_array[37] # pr_lwpid
271
+ # skip pr_addr
272
+ struct.wchan = psinfo_array[39] # pr_wchan
273
+ # skip pr_flag
274
+ struct.wtype = psinfo_array[41] # pr_wtype
275
+ struct.state = psinfo_array[42] # pr_state
276
+ struct.sname = psinfo_array[43] # pr_sname
277
+ struct.nice = psinfo_array[44] # pr_nice
278
+ struct.pri = psinfo_array[45] # pr_pri
279
+ struct.policy = psinfo_array[46] # pr_policy
280
+ struct.clname = psinfo_array[47] # pr_clname
281
+ struct.onpro = psinfo_array[48] # pr_onpro
282
+ struct.bindpro = psinfo_array[49] # pr_bindpro
283
+ struct.ptid = psinfo_array[50] # pr_ptid
284
+ # skip pr__pad1
285
+ # skip pr__pad
286
+
287
+ # Get the full command line out of /proc/<pid>/as.
288
+ begin
289
+ File.open("/proc/#{file}/as", 'rb') do |fd|
290
+ np = fd.sysseek(struct.argv, IO::SEEK_SET)
291
+
292
+ if np != struct.argv
293
+ raise Error, "argv seek to #{struct.argv}, result #{np}", caller
294
+ end
295
+
296
+ argv = fd.sysread(4).unpack('L')[0]
297
+
298
+ np = fd.sysseek(argv, IO::SEEK_SET)
299
+
300
+ if np != argv
301
+ raise Error, "*argv seek to #{argv}, result #{np}", caller
302
+ end
303
+
304
+ argv = fd.sysread(4 * struct.argc).unpack("L#{struct.argc}")
305
+
306
+ struct.cmd_args = []
307
+
308
+ argv.each_with_index do |address, i|
309
+ np = fd.sysseek(address, IO::SEEK_SET)
310
+
311
+ if np != address
312
+ raise Error, "argv[#{i}] seek to #{address}, result #{np}",
313
+ caller
314
+ end
315
+
316
+ data = fd.sysread(512)[/^[^\0]*/] # Null strip
317
+ struct.cmd_args << data
318
+ end
319
+
320
+ # Get the environment hash associated with the process.
321
+ struct.environ = {}
322
+
323
+ # First have to go to the address given by struct.envp. That will
324
+ # give us the address of the environment pointer array.
325
+
326
+ np = fd.sysseek(struct.envp, IO::SEEK_SET)
327
+
328
+ if np != struct.envp
329
+ raise Error, "envp seek to #{struct.envp}, result #{np}", caller
330
+ end
331
+
332
+ envloc = fd.sysread(4).unpack('L')[0]
333
+ n = 0
334
+
335
+ loop do
336
+ np = fd.sysseek(envloc, IO::SEEK_SET)
337
+
338
+ if np != envloc
339
+ raise Error, "envp[#{n}] seek to #{envloc}, result #{np}",
340
+ caller
341
+ end
342
+
343
+ envp = fd.sysread(4).unpack("L")[0]
344
+ break if envp.zero?
345
+ np = fd.sysseek(envp, IO::SEEK_SET)
346
+ data = fd.sysread(1024)[/^[^\0]*/] # Null strip
347
+ key, value = data.split('=')
348
+ struct.environ[key] = value
349
+ envloc += 4
350
+ n += 1
351
+ end
352
+ end
353
+ rescue Errno::EACCES, Errno::EOVERFLOW, EOFError
354
+ # Skip this if we don't have proper permissions, if there's
355
+ # no associated environment, or if there's a largefile issue.
356
+ rescue Errno::ENOENT
357
+ next # The process has terminated. Bail out!
358
+ end
359
+
360
+ # Information from /proc/<pid>/fd. This returns an array of
361
+ # numeric file descriptors used by the process.
362
+ struct.fd = Dir["/proc/#{file}/fd/*"].map { |f| File.basename(f).to_i }
363
+
364
+ # Use the cmd_args as the cmdline if available. Otherwise use
365
+ # the psargs. This struct member is provided to provide a measure
366
+ # of consistency with the other platform implementations.
367
+ if struct.cmd_args.nil? || struct.cmd_args.empty?
368
+ struct.cmdline = struct.psargs
369
+ else
370
+ struct.cmdline = struct.cmd_args.join(' ')
371
+ end
372
+
373
+ # get current working directory from /proc/<pid>/cwd
374
+ struct.cwd = File.readlink("/proc/#{file}/cwd") rescue nil
375
+
376
+ # get virtual address map from /proc/<pid>/map
377
+ begin
378
+ struct.map = []
379
+
380
+ File.open("/proc/#{file}/map", 'rb') do |fd|
381
+ loop do
382
+ prmap_array = fd.sysread(176).unpack(@prmap_pack_directive)
383
+ break if prmap_array[0].zero?
384
+
385
+ map_struct = ProcTableMapStruct.new
386
+
387
+ map_struct.size = prmap_array[0] # pr_size
388
+ map_struct.vaddr = prmap_array[1] # pr_vaddr
389
+ map_struct.mapname = prmap_array[2] # pr_mapname
390
+ map_struct.off = prmap_array[3] # pr_off
391
+ map_struct.mflags = prmap_array[4] # pr_mflags
392
+
393
+ # convert pr_mflags value to string sort of like procmap outputs
394
+ mflags = map_struct.mflags
395
+ map_struct.s_mflags = ''
396
+ sep = ''
397
+
398
+ PR_MFLAGS.each do |flag|
399
+ if (mflags & flag[0]).nonzero?
400
+ map_struct.s_mflags << sep << flag[1]
401
+ sep = '/'
402
+ mflags &= ~flag[0]
403
+ end
404
+ end
405
+
406
+ if mflags.nonzero?
407
+ map_struct.s_mflags << sep << sprintf('%08x', mflags)
408
+ end
409
+
410
+ map_struct.pathoff = prmap_array[5] # pr_pathoff
411
+ map_struct.alias = prmap_array[6] # pr_alias
412
+ map_struct.gp = prmap_array[7] # pr_gp
413
+
414
+ struct.map << map_struct
415
+ end
416
+
417
+ struct.map.each do |m|
418
+ next if m.pathoff.zero?
419
+ fd.sysseek(m.pathoff, IO::SEEK_SET)
420
+ buf = fd.sysread(4096)
421
+ buf =~ /^([^\0]*)\0([^\0]*)\0/
422
+ m.path = $2.empty? ? $1 : "#{$1}(#{$2})"
423
+ end
424
+ end
425
+
426
+ struct.map = nil if struct.map.empty?
427
+ rescue
428
+ struct.map = nil
429
+ end
430
+
431
+ # This is read-only data
432
+ struct.freeze
433
+
434
+ if block_given?
435
+ yield struct
436
+ else
437
+ array << struct
438
+ end
439
+ end
440
+
441
+ pid ? struct : array
442
+ end
443
+
444
+ # Returns an array of fields that each ProcTableStruct will contain. This
445
+ # may be useful if you want to know in advance what fields are available
446
+ # without having to perform at least one read of the /proc table.
447
+ #
448
+ # Example:
449
+ #
450
+ # Sys::ProcTable.fields.each do |field|
451
+ # puts "Field: #{field}"
452
+ # end
453
+ #
454
+ def self.fields
455
+ @fields.map{ |f| f.to_s }
456
+ end
457
+ end
458
+ end