sys-proctable 0.7.6 → 1.2.0
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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -0
- data/CHANGES +165 -0
- data/MANIFEST +33 -41
- data/README +115 -135
- data/Rakefile +94 -0
- data/benchmarks/bench_ps.rb +21 -0
- data/doc/top.txt +5 -11
- data/examples/example_ps.rb +20 -0
- data/lib/aix/sys/proctable.rb +458 -0
- data/lib/darwin/sys/proctable.rb +363 -0
- data/lib/freebsd/sys/proctable.rb +363 -0
- data/lib/linux/sys/proctable.rb +314 -0
- data/lib/linux/sys/proctable/cgroup_entry.rb +50 -0
- data/lib/linux/sys/proctable/smaps.rb +118 -0
- data/lib/sunos/sys/proctable.rb +456 -0
- data/lib/sys-proctable.rb +1 -0
- data/lib/sys-top.rb +1 -0
- data/lib/sys/proctable.rb +18 -0
- data/lib/sys/proctable/version.rb +6 -0
- data/lib/sys/top.rb +28 -19
- data/lib/windows/sys/proctable.rb +208 -0
- data/spec/sys_proctable_aix_spec.rb +328 -0
- data/spec/sys_proctable_all_spec.rb +89 -0
- data/spec/sys_proctable_darwin_spec.rb +120 -0
- data/spec/sys_proctable_freebsd_spec.rb +210 -0
- data/spec/sys_proctable_linux_spec.rb +310 -0
- data/spec/sys_proctable_sunos_spec.rb +316 -0
- data/spec/sys_proctable_windows_spec.rb +317 -0
- data/spec/sys_top_spec.rb +51 -0
- data/sys-proctable.gemspec +38 -0
- metadata +140 -64
- metadata.gz.sig +0 -0
- data/doc/freebsd.txt +0 -90
- data/doc/hpux.txt +0 -77
- data/doc/linux.txt +0 -85
- data/doc/solaris.txt +0 -99
- data/doc/windows.txt +0 -122
- data/ext/extconf.rb +0 -98
- data/ext/sunos/sunos.c +0 -374
- data/ext/sunos/sunos.h +0 -177
- data/ext/version.h +0 -2
- data/test/tc_all.rb +0 -59
- data/test/tc_freebsd.rb +0 -45
- data/test/tc_hpux.rb +0 -49
- data/test/tc_kvm_bsd.rb +0 -31
- data/test/tc_linux.rb +0 -45
- data/test/tc_sunos.rb +0 -52
- data/test/tc_top.rb +0 -26
- data/test/tc_windows.rb +0 -40
- data/test/test_memleak.rb +0 -54
data/Rakefile
ADDED
@@ -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
|
data/doc/top.txt
CHANGED
@@ -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
|
-
|
35
|
+
Artistic 2.0
|
40
36
|
|
41
37
|
= Copyright
|
42
|
-
(C) 2004-
|
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
|