Class: Sys::ProcTable

Inherits:
Object
  • Object
show all
Defined in:
lib/linux/sys/proctable.rb

Overview

The ProcTable class encapsulates process table information.

Defined Under Namespace

Classes: Error, ProcTableStruct

Constant Summary collapse

VERSION =

The version of the sys-proctable library

'0.9.2'

Class Method Summary collapse

Class Method Details

.fieldsObject

Returns an array of fields that each ProcTableStruct will contain. This may be useful if you want to know in advance what fields are available without having to perform at least one read of the /proc table.

Example:

Sys::ProcTable.fields.each{ |field|
   puts "Field: #{field}"
}


321
322
323
# File 'lib/linux/sys/proctable.rb', line 321

def self.fields
  @fields
end

.ps(pid = nil) ⇒ Object

In block form, yields a ProcTableStruct for each process entry that you have rights to. This method returns an array of ProcTableStruct’s in non-block form.

If a pid is provided, then only a single ProcTableStruct is yielded or returned, or nil if no process information is found for that pid.

Example:

# Iterate over all processes
ProcTable.ps do |proc_info|
   p proc_info
end

# Print process table information for only pid 1001
p ProcTable.ps(1001)

–

It's possible that a process could terminate while gathering
information for that process. When that happens, this library
will simply skip to the next record. In short, this library will
either return all information for a process, or none at all.

Raises:

  • (NotImplementedError)


166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/linux/sys/proctable.rb', line 166

def self.ps(pid=nil)
  return ps_mac(pid ||-100) if OS.mac?
  return ps_windows(pid ||-100) if OS.windows?
  raise NotImplementedError unless OS.linux?
  array  = block_given? ? nil : []
  struct = nil

  raise TypeError unless pid.is_a?(Fixnum) if pid

  Dir.foreach("/proc"){ |file|
    next if file =~ /\D/ # Skip non-numeric directories
    next unless file.to_i == pid if pid

    struct = ProcTableStruct.new

    # Get /proc/<pid>/cmdline information. Strip out embedded nulls.
    begin
      data = IO.read("/proc/#{file}/cmdline").tr("\000", ' ').strip
      struct.cmdline = data
    rescue
      next # Process terminated, on to the next process
    end

    # Get /proc/<pid>/cwd information
    struct.cwd = File.readlink("/proc/#{file}/cwd") rescue nil

    # Get /proc/<pid>/environ information. Environment information
    # is represented as a Hash, with the environment variable as the
    # key and its value as the hash value.
    struct.environ = {}

    begin
      IO.read("/proc/#{file}/environ").split("\0").each{ |str|
        key, value = str.split('=')
        struct.environ[key] = value
      }
    rescue Errno::EACCES, Errno::ESRCH, Errno::ENOENT
      # Ignore and move on.
    end

    # Get /proc/<pid>/exe information
    struct.exe = File.readlink("/proc/#{file}/exe") rescue nil

    # Get /proc/<pid>/fd information. File descriptor information
    # is represented as a Hash, with the fd as the key, and its
    # symlink as the value.
    struct.fd = {}

    begin
      Dir["/proc/#{file}/fd/*"].each do |fd|
        struct.fd[File.basename(fd)] = File.readlink(fd) rescue nil
      end
    rescue
      # Ignore and move on
    end

    # Get /proc/<pid>/root information
    struct.root = File.readlink("/proc/#{file}/root") rescue nil

    # Get /proc/<pid>/stat information
    stat = IO.read("/proc/#{file}/stat") rescue next

    # Deal with spaces in comm name. Courtesy of Ara Howard.
    re = %r/\([^\)]+\)/
    comm = stat[re]
    comm.tr!(' ', '-')
    stat[re] = comm

    stat = stat.split

    struct.pid         = stat[0].to_i
    struct.comm        = stat[1].tr('()','') # Remove parens
    struct.state       = stat[2]
    struct.ppid        = stat[3].to_i
    struct.pgrp        = stat[4].to_i
    struct.session     = stat[5].to_i
    struct.tty_nr      = stat[6].to_i
    struct.tpgid       = stat[7].to_i
    struct.flags       = stat[8].to_i
    struct.minflt      = stat[9].to_i
    struct.cminflt     = stat[10].to_i
    struct.majflt      = stat[11].to_i
    struct.cmajflt     = stat[12].to_i
    struct.utime       = stat[13].to_i
    struct.stime       = stat[14].to_i
    struct.cutime      = stat[15].to_i
    struct.cstime      = stat[16].to_i
    struct.priority    = stat[17].to_i
    struct.nice        = stat[18].to_i
    # Skip 19
    struct.itrealvalue = stat[20].to_i
    struct.starttime   = stat[21].to_i
    struct.vsize       = stat[22].to_i
    struct.rss         = stat[23].to_i
    struct.rlim        = stat[24].to_i
    struct.startcode   = stat[25].to_i
    struct.endcode     = stat[26].to_i
    struct.startstack  = stat[27].to_i
    struct.kstkesp     = stat[28].to_i
    struct.kstkeip     = stat[29].to_i
    struct.signal      = stat[30].to_i
    struct.blocked     = stat[31].to_i
    struct.sigignore   = stat[32].to_i
    struct.sigcatch    = stat[33].to_i
    struct.wchan       = stat[34].to_i
    struct.nswap       = stat[35].to_i
    struct.cnswap      = stat[36].to_i
    struct.exit_signal = stat[37].to_i
    struct.processor   = stat[38].to_i
    struct.rt_priority = stat[39].to_i
    struct.policy      = stat[40].to_i

    # Get /proc/<pid>/status information (name, uid, euid, gid, egid)
    IO.foreach("/proc/#{file}/status") do |line|
      case line
        when /Name:\s*?(\w+)/
          struct.name = $1
        when /Uid:\s*?(\d+)\s*?(\d+)/
          struct.uid  = $1.to_i
          struct.euid = $2.to_i
        when /Gid:\s*?(\d+)\s*?(\d+)/
          struct.gid  = $1.to_i
          struct.egid = $2.to_i
      end
    end

    # If cmdline is empty use comm instead
    struct.cmdline = struct.comm if struct.cmdline.empty?

    # Manually calculate CPU and memory usage
    struct.pctcpu = get_pctcpu(struct.utime, struct.starttime)
    struct.pctmem = get_pctmem(struct.rss)

    struct.freeze # This is read-only data

    if block_given?
      yield struct
    else
      array << struct
    end
  }

  pid ? struct : array
end

.ps_mac(process_id = -100)) ⇒ Object

Returns an Array of Proctable structs or just the matching one if pid is given.



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/linux/sys/proctable.rb', line 84

def self.ps_mac(process_id=-100)
  output = `ps aux`
  output = output.split "\n"
  output.delete output.first
  result = []

  output.each do |process_info|
    struct = ProcTableStruct.new
    process_info = process_info.split "  "
    process_info.delete ""
     = `id #{process_info.first}`
    /uid=((?<uid>\d*))/ =~ 
    /gid=((?<gid>\d*))/ =~ 
    pid = process_info[1].to_i
    /[\.|\:]\d\d (?<cmdline>.*)/ =~ process_info.last
    struct.pid = pid
    struct.uid = uid.to_i
    struct.gid = gid.to_i
    struct.cmdline = cmdline
    return struct if pid == process_id    
    result << struct
  end

  raise "Process #{process_id} not found" if process_id.to_i > 0
  result
end

.ps_windows(process_id = -100)) ⇒ Object

Returns an Array of Proctable structs or just the matching one if pid is given.



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/linux/sys/proctable.rb', line 112

def self.ps_windows(process_id=-100)
  output = `tasklist`
  output = output.split "\n"
  output.delete output.first
  output.delete output.first
  output.delete output.first
  result = []

  output.each do |process_info|
    struct = ProcTableStruct.new
    struct.cmdline ||= ""
    process_info = process_info.split
    process_info.each do |field|
      pid = Integer(field) rescue nil  

      if pid.nil?
        struct.cmdline += field
      else
        struct.pid = pid
        return struct if pid == process_id         
        break
      end            
    end

    result << struct
  end
  
  raise "Process #{process_id} not found" if process_id.to_i > 0
  result
end