Permalink
Browse files

Move source code for sys-proctable to git

  • Loading branch information...
0 parents commit 969f76f38031ddf1d5771cab47c8598da48fbc22 @djberg96 committed Oct 20, 2009
289 CHANGES
@@ -0,0 +1,289 @@
+== 0.9.0 - 14-Oct-2009
+* Changed the license to Artistic 2.0.
+* Fixed a bug in the OS X code where a segfault would occur when an attempt
+ was made to gather resource usage information on zombie processes. From
+ now on that information is always set to nil for zombie processes. Thanks
+ go to Tom Lianza for the spot and Philip Kromer for investigating the
+ root cause of the failure.
+* Removed the FreeBSD code that read out of /proc. It was a pain from a
+ maintenance point of view, and most FreeBSD installs do not mount /proc
+ by default. The FreeBSD platform now uses the same code that the other
+ BSD platforms use.
+* Fixed a bug in the BSD code where the ProcTable::Error class had the
+ wrong parent class.
+* Some major gemspec updates, including an updated license. The platform
+ handling logic is now in the Rakefile in the 'gem' task.
+* Updated the README file to include an additional acknowledgement, a
+ license change and some minor formatting changes.
+* The test-unit library was changed from a runtime to a development dependency.
+
+== 0.8.1 - 6-Apr-2009
+* The Linux and Solaris libraries now handle the possibility of a process
+ terminating in the middle of a read more gracefully. If that happens, they
+ merely skip to the next record, i.e. it's all or nothing. Thanks go to
+ Heejong Lee for the spot and patch.
+* Fixed a bug in the Linux version where embedded nulls were not being
+ stripped out of the cmdline data.
+* Added the comm alias back to the Solaris version. Thanks go to Jun Young Kim
+ for the spot.
+
+== 0.8.0 - 26-Jan-2009
+* The Linux and Solaris versions of this library are now pure Ruby. Be warned,
+ however, that only Solaris 8 and later are now supported. This may change
+ in a future release if there's demand to support 2.6 and 2.7.
+* Some Struct::ProcTableStruct members have changed. As a general rule they
+ now more closely match the C struct member name. See individual platforms
+ for more details.
+* Bug fix for the cmd_args struct member on Solaris.
+* Bug fixes for OS X. Added a VERSION constant, fixed struct name, and changed
+ pct_cpu to pctcpu.
+* The .new method is now explicitly illegal.
+* The Struct::ProcTableStruct instances are now frozen. This is read-only data.
+* Added the peak_page_file_usage and status members on MS Windows. The status
+ member is always nil, but was added for completeness.
+* Fixed the quota_peak_paged_pool_usage member on MS Windows.
+* ProcTableError is now ProcTable::Error.
+* Minor test case fix for kvm/bsd based versions.
+* Added the 'time' library as a require for Windows (to parse MS date/time
+ format strings).
+* The kvm (bsd.c) implementation now works for FreeBSD 7.
+* Added many more tests.
+* Added some benchmarking code in the 'benchmarks' directory.
+* Added a 'bench' Rake task.
+* Renamed the test_ps.rb file to example_ps.rb in order to avoid any possible
+ confusion with actual test files.
+* Added an 'example' rake task to run the example file.
+
+== 0.7.6 - 11-Jul-2007
+* Fixed the starttime for Linux. Thanks go to Yaroslav Dmitriev for the spot.
+* Fixed a bug in the MS Windows version within a private method that parsed
+ an MS specific date format. This was caused by a backwards incompatible
+ change in the Time.parse method in Ruby 1.8.6. See ruby-core: 11245 ff.
+* Fixed the gemspec (I hope). Please let me know if you have problems.
+* Added a Rakefile. Building, testing and installing should now be handled via
+ Rake tasks. The install.rb file has been removed - that code is now
+ integrated in the Rakefile.
+* Minor directory layout changes and cleanup (mostly for the extconf.rb file).
+* Side note - it seems that the code for OS X *does* work, at least on 10.4.10.
+ I can only conclude that previous reports about it failing were related to
+ bugs in OS X or were really just build issues. Apologies (and thanks, again)
+ to David Felstead for the code. However, see the README for more information
+ specific to OS X, as there are shortcomings.
+
+== 0.7.5 - 23-Nov-2006
+* Fixed int/long issues for Linux. Thanks go to Matt Lightner for the spot.
+* Minor documentation fixes and changes to the extconf.rb file.
+
+== 0.7.4 - 20-Nov-2006
+* Added a patch that deals with the large file compilation issue on Solaris.
+ You no longer need to build Ruby with --disable-largefile, or build a
+ 64 bit Ruby, in order for this package to work. Thanks go to Steven Jenkins
+ for the information that led to the patch.
+* Added inline rdoc to the source code.
+* Added a gemspec.
+* Fixed some potential 64 bit issues (struct declarations).
+* Added preliminary support for Darwin (OS X). The code was provided by
+ David Felstead, but does not appear to compile successfully. Help wanted.
+
+== 0.7.3 - 27-Oct-2005
+* Fix for 1.8.3 and later (rb_pid_t). This should have only affected
+ Solaris.
+
+== 0.7.2 - 15-May-2005
+* Bug fix for the FreeBSD version that reads from /proc.
+* Eliminated the test bug on Linux (inexplicably caused by File.copy). The
+ test suite should now run without segfaulting.
+* Include bsd.c in tarball (oops).
+* Minor test updates for FreeBSD.
+* The 'pct_cpu' member for the BSD/kvm version has been changed to 'pctcpu'
+ for consistency with other platforms.
+
+== 0.7.1 - 8-May-2005
+* Bug fixed for the cmdline info on Linux. Thanks go to Arash Abedinzadeh
+ for the spot.
+* Added an example program.
+* Minor setup fix for Win32 in tc_all.rb.
+
+== 0.7.0 - 25-Apr-2005
+* Scrapped the C implementation for Windows in favor of an OLE + WMI pure Ruby
+ approach. See documentation for details.
+* Added an optional lkvm implementation for BSD users. This is automatically
+ used if the /proc filesystem isn't found.
+* Added prusage info for the Solaris version.
+* Added name, eid, euid, gid and guid information for Linux. Thanks go to
+ James Hranicky for the patch.
+* Fixed some potential bugs in the Linux version. Thanks go to James
+ Hranicky for the spot.
+* Added the 'sys/top' package.
+* ProcTable.fields no longer supports a block form.
+* The BTIME (boot time) information has been removed from the Linux version.
+ If you want that information, use sys-uptime instead.
+* The .html and .rd files have been removed. You can generate html on your
+ own with rdoc if you like.
+* Some code cleanup on the C side of the house.
+* Most documents made rdoc friendly.
+* Renamed 'install_pure_ruby.rb' to just 'install.rb'.
+* Removed the 'INSTALL' file. Installation instructions are in the README.
+* Some test suite cleanup and reorganization.
+* Moved project to RubyForge.
+
+== 0.6.4 - 31-Mar-2004
+* Fixed a bug in the pure Ruby version for Win32. Thanks go to Mark Hudson
+ for the spot.
+* Fixed a bug in the C implementation for Win32 where the cmdline and path
+ values were sometimes wrong for running processes. Thanks go to Park Heesob
+ for the fix.
+* Updated the VERSION constant and removed the VERSION class method in the
+ pure Ruby version for Win32.
+* Updated install_pure_ruby.rb and test.rb scripts.
+* Updated warranty information.
+* The extconf.rb script has been revamped. See the INSTALL and README files
+ for important changes since the last release.
+* The start ProcInfo struct member on Solaris, HP-UX and FreeBSD is now a
+ Time object, not a Fixnum/Bignum.
+* Modified linux.c yet again to make gcc happy when it comes to multi-line
+ string literals.
+* Minor change to way process state is handled on HP-UX.
+* Documentation additions and updates, including warranty information.
+
+== 0.6.3 - 24-Feb-2004
+* Fixed a bug in the Solaris version where the cmd_args array did not
+ necessarily contain data on 2.7 and later. The current patch still
+ does not quite fix the problem for 2.6 and earlier but can be easily
+ derived manually by parsing the cmdline string.
+
+== 0.6.2 - 20-Jan-2004
+* Fixed a small memory leak in the solaris version.
+
+== 0.6.1 - 31-Dec-2003
+* Fixed a minor bug in the cmdline field on Linux where a blank character
+ was being appended to the end of the field.
+* Fixed a minor annoyance where the windows.rb file was being copied into
+ the Ruby lib directory on install.
+* Added a test_memleak.rb file. Currently only supported on Linux and
+ only does a file descriptor count check. I plan to expand this to
+ other platforms in the future.
+* Minor test suite changes
+* MANIFEST correction and update.
+
+== 0.6.0 - 22-Oct-2003
+* Significant API change (and thus, a version jump) - only a
+ single argument is now accepted to the ps() method, and only a PID
+ (Fixnum) is regarded as a valid argument.
+* Calling ps() with a pid returns a single ProcTable struct (or nil
+ if the pid is not found), instead of a one element array.
+* Argument to ps() now works properly on HP-UX and Win32.
+* Removed the '#include <sys/types32.h>' in sunos.h. It wasn't needed
+ and you're not supposed to include it directly.
+* Fixed 2.6 compatibility issue with regards to cmdline on Solaris.
+* Removed the ProcStatException completely on Linux. There was no reason
+ to fail on a directory read for /proc/xxx/stat. If the read fails
+ (meaning the process died in the middle of collecting info for it), it
+ is simply ignored.
+* The ttynum bug on HPUX has been fixed. In addition, the return value for
+ this field is now a string rather than an int and the field name has
+ been changed to "ttydev".
+* The ttynum field has been changed to ttydev on Solaris and HPUX. On
+ Solaris, the ttydev is now reported as -1 if there is no associated tty.
+ In a future release, Solaris and the other *nix platforms will be changed
+ so that ttydev is always a device name (i.e String).
+* Added plain text documentation for all platforms.
+* Some test suite cleanup.
+* Changed .rd2 extension to just '.rd'.
+
+== 0.5.2 - 18-Jul-2003
+* Modified cmdline to extend past the traditional 80 character limit on
+ Solaris, where possible (Solaris 2.6+ only).
+* Added the cmdline_args and num_args fields on Solaris, which returns
+ an array of cmdline arguments and the number of cmdline arguments,
+ respectively.
+* Minor modification to fields() method, in addition to warning cleanup
+ for Solaris.
+* Changed "defunct" state string to "zombie" for Solaris.
+* Should cleanly compile with -Wall -W now (gcc) on Solaris.
+* Added solaris.txt to doc directory.
+* MANIFEST corrections.
+
+== 0.5.1 - 16-Jul-2003
+* Fixed a nasty file descriptor bug in the Linux code, where file descriptors
+ were continuously being used up.
+* Added the BTIME (boot time) constant for Linux.
+* Fixed up the test/test.rb file a bit.
+* Added BTIME tests to tc_linux.rb.
+
+== 0.5.0 - 11-Jul-200
+* Added HP-UX support!
+* Note that passing PID's or strings as arguments to ps() is not supported
+ in the HP-UX version. This functionality will be stripped out of the
+ other versions in a future release. See the README file for more details.
+* Removed the VERSION() class method. Use the constant instead.
+* Separated the rd docs from their respective source files. Now in the doc
+ directory.
+* Got rid of the interactive html generation in extconf.rb.
+* Changed License to Artistic.
+
+== 0.4.3 - 30-May-2003
+* Added a version.h file to store the version number. Modified all of the
+ C source files to use that instead of hard coding the version everywhere.
+* Added a generic test.rb script for those without TestUnit installed, or
+ just futzing in general. Modified the extconf.rb script to copy this
+ instead of writing an inline HERE document.
+* Modified extconf.rb so that it builds with mingw or cygwin. Thanks go to
+ Peter Fischer for the spot and patch.
+* Modified test suite to work with TestUnit 0.1.6 or 0.1.8.
+
+== 0.4.2 - 14-Apr-2003
+* Added pure Ruby version for Win32 - thanks Park Heesob.
+* Modified extconf.rb file to handle pure Ruby versions.
+* Added install_pure_ruby.rb file, an alternate installation
+ script for pure Ruby versions.
+
+== 0.4.1 - 31-Mar-2003
+* Added support for Solaris 2.5.x.
+* All exceptions are now a direct subclass of StandardError.
+* Value returned for wchan now more meaningful (2.5.x only for now).
+* Fixed the start, utime and ctime for FreeBSD.
+* Minor fix to FreeBSD test suite.
+* Some changes to extconf.rb.
+* Minor doc changes.
+* Added License and Copyright info.
+
+== 0.4.0 - 10-Mar-2003
+* Added MS Windows support (non-cygwin).
+* Added environment information for Linux version.
+* Added real exceptions (type depends on platform).
+* Added a test suite (for those with testunit installed).
+* Removed the sys-uname requirement.
+* Heavily modified the extconf.rb script.
+* Changed "Changelog" to "CHANGES" and "Manifest" to "MANIFEST".
+* Added a VERSION constant and class method.
+* Minor internal directory layout change (put 'os' under 'lib').
+* Changed package name to lower case.
+* Doc changes, including license information.
+
+== 0.3.1 - 16-Aug-2002
+* Added a "comm" field to the sunos version. I am going to try to make this a
+ common field for all platforms to help reduce RUBY_PLATFORM checking.
+* Fixed the release date for 0.3.0 (was accidentally marked *July*).
+* Added an INSTALL file.
+* Minor documentation change to the sunos.c source file.
+
+== 0.3.0 - 11-Aug-2002
+* Added FreeBSD support!
+* Struct name changed to just "ProcTableStruct" to be compliant with future
+ versions of Ruby.
+* The ps() function now returns an array of ProcTableStruct's in lvalue context.
+* Fixed the ability to search by process name in Linux.
+* Modified Linux "comm" field to strip parenthesis.
+* Some doc changes/additions.
+* Added Sean Chittenden to the "Acknowledgements" section. Sean provided me
+ with access to a FreeBSD box, which is how I was able to provide FreeBSD
+ support. Thanks Sean!
+
+== 0.2.0 - 19-Jul-2002
+* Added the ability to search by process name.
+* test.rb modified to be cross-platform.
+* Solaris - fixed bug with fname (was accidentally called "name").
+
+== 0.1.0 - 2-Jul-2002
+- Initial release.
30 MANIFEST
@@ -0,0 +1,30 @@
+* CHANGES
+* MANIFEST
+* Rakefile
+* README
+* sys-proctable.gemspec
+* doc/bsd.txt
+* doc/hpux.txt
+* doc/linux.txt
+* doc/solaris.txt
+* doc/top.txt
+* doc/windows.txt
+* example/example_ps.rb
+* ext/bsd/extconf.rb
+* ext/bsd/sys/proctable.c
+* ext/darwin/extconf.rb
+* ext/darwin/sys/proctable.c
+* ext/hpux/extconf.rb
+* ext/hpux/sys/proctable.c
+* lib/sys/top.rb
+* lib/linux/sys/proctable.rb
+* lib/sunos/sys/proctable.rb
+* lib/windows/sys/proctable.rb
+* test/test_sys_proctable_all.rb
+* test/test_sys_proctable_darwin.rb
+* test/test_sys_proctable_hpux.rb
+* test/test_sys_proctable_bsd.rb
+* test/test_sys_proctable_linux.rb
+* test/test_sys_proctable_sunos.rb
+* test/test_sys_proctable_windows.rb
+* test/test_sys_top.rb
126 README
@@ -0,0 +1,126 @@
+== Description
+ A Ruby interface for gathering process information.
+
+== Prerequisites
+* Ruby 1.8.2 or later
+* Test::Unit 2.x (development only)
+
+== Supported Platforms
+* Windows NT family (NT, 2000, XP, etc)
+* Linux 2.6+
+* BSD (various flavors)
+* Solaris 8+
+* HP-UX 10+
+* OS X 10.4+
+
+== Installation
+=== Rubygems
+gem install sys-proctable
+
+You may need to specify a platform in some cases. For example:
+
+gem install sys-proctable --platform mswin32 # Windows
+gem install sys-proctable --platform sunos # Solaris
+gem install sys-proctalbe --platform linux # Linux
+
+=== Standard
+rake install
+
+= Synopsis
+ require 'sys/proctable'
+ include Sys
+
+ # Everything
+ ProcTable.ps{ |p|
+ puts p.pid.to_s
+ puts p.comm
+ ...
+ }
+
+ or
+
+ # Just one process
+ s = ProcTable.ps(2123)
+ puts s.pid.to_s
+ puts s.comm
+ ...
+
+ # Return the results as an array of ProcTableStructs
+ a = ProcTable.ps
+ a.each do |p|
+ puts a.pid
+ ...
+ end
+
+== Notes
+ Windows users may pass a host name as a second argument to get process
+ information from a different host. This relies on the WMI service running.
+
+== Known Issues
+=== BSD
+ A kvm interface is used. That means the owner of the process using the
+ sys-proctable library needs to be a member of the kvm group (or root).
+
+=== Solaris
+ The cmdline member on Solaris is limited to 80 characters unless you (or
+ your program) own the process. This is a Solaris design flaw/feature.
+
+=== OS X
+ At the moment you do not get the full command line string. The code required
+ to get this information is obnoxious and I don't have any compelling desire
+ to add it. However, if you're willing to submit a patch I'll accept it.
+
+ You can find a good starting point with the OS X code found in Dan Urist's
+ Proc::ProcessTable module. You can find that module on CPAN. Point your
+ browser at http://search.cpan.org.
+
+=== Thread Safety
+ I am not currently using a thread-safe version of readdir(). I am not
+ especially concerned about it either. If you are trying to read information
+ out of /proc from different threads at the same time there is something
+ seriously wrong with your code logic. Using readdir_r() still won't solve
+ all potential thread safety issues anyway.
+
+== Future Plans
+ Research has indicated that the kvm approach is less favored than a sysctl
+ approach on BSD variants. I will try to add this interface in a future
+ release.
+
+== Acknowledgements
+ This library is largely based on the Perl module Proc::ProcessTable by
+ Dan Urist. Many ideas, as well as large chunks of code, were taken
+ from his work. So, a big THANK YOU goes out to Dan Urist.
+
+ A big thanks also goes out to Mike Hall who was very helpful with ideas,
+ logic and testing.
+
+ Thanks also go to Sean Chittenden for providing an account on one of his
+ FreeBSD machines. This is how the FreeBSD support was (initially) added.
+
+ Thanks go to James Hranicky for providing a patch that grabs name, eid,
+ euid, gid and guid info in the Linux version, along with some general
+ debugging help.
+
+ Thanks go to David Felstead for the original OS X code.
+
+ Finally I'd like to thank all the folks who have submitted bug reports
+ and/or patches.
+
+== Help Wanted
+ I do not have access to all platforms. If your platform is not supported
+ then you will need to either submit a patch or give me a remote account
+ on a box with a compiler so that I can write the code.
+
+== More documentation
+ See the documentation under the 'doc' directory for more information,
+ including platform specific notes and issues.
+
+== License
+ Artistic 2.0
+
+== Copyright
+ (C) 2003-2009 Daniel J. Berger
+ All Rights Reserved.
+
+== Author
+ Daniel J. Berger
167 Rakefile
@@ -0,0 +1,167 @@
+require 'rake'
+require 'rake/clean'
+require 'rake/testtask'
+require 'rbconfig'
+
+desc 'Clean the build files for C versions of sys-proctable'
+task :clean do
+ rm_rf('.test-result') if File.exists?('.test-result')
+ Dir['*.gem'].each{ |f| File.delete(f) }
+
+ case Config::CONFIG['host_os']
+ when /bsd/i
+ dir = 'ext/bsd'
+ when /darwin/i
+ dir = 'ext/darwin'
+ when /hpux/i
+ dir = 'ext/hpux'
+ end
+
+ unless Config::CONFIG['host_os'] =~ /win32|mswin|dos|cygwin|mingw|linux|sunos|solaris/i
+ Dir.chdir(dir) do
+ if Dir['*.o'].length > 0
+ sh 'make distclean'
+ Dir['sys/proctable.*'].each{ |f| rm(f) if File.extname(f) != '.c' }
+ end
+ end
+ end
+end
+
+desc 'Build the sys-proctable library for C versions of sys-proctable'
+task :build => [:clean] do
+ case Config::CONFIG['host_os']
+ when /bsd/i
+ dir = 'ext/bsd'
+ when /darwin/i
+ dir = 'ext/darwin'
+ when /hpux/i
+ dir = 'ext/hpux'
+ end
+
+ unless Config::CONFIG['host_os'] =~ /win32|mswin|dos|cygwin|mingw|linux|sunos|solaris/i
+ Dir.chdir(dir) do
+ ruby 'extconf.rb'
+ sh 'make'
+ cp 'proctable.' + Config::CONFIG['DLEXT'], 'sys'
+ end
+ end
+end
+
+desc 'Install the sys-proctable library'
+task :install => [:build] do
+ file = nil
+ dir = File.join(Config::CONFIG['sitelibdir'], 'sys')
+
+ Dir.mkdir(dir) unless File.exists?(dir)
+
+ case Config::CONFIG['host_os']
+ when /mswin|win32|msdos|cygwin|mingw/i
+ file = 'lib/windows/sys/proctable.rb'
+ when /linux/i
+ file = 'lib/linux/sys/proctable.rb'
+ when /sunos|solaris/i
+ file = 'lib/sunos/sys/proctable.rb'
+ when /bsd/i
+ Dir.chdir('ext/bsd'){ sh 'make install' }
+ when /darwin/i
+ Dir.chdir('ext/darwin'){ sh 'make install' }
+ when /hpux/i
+ Dir.chdir('ext/hpux'){ sh 'make install' }
+ end
+
+ cp(file, dir, :verbose => true) if file
+end
+
+desc 'Uninstall the sys-proctable library'
+task :uninstall do
+ case Config::CONFIG['host_os']
+ when /win32|mswin|dos|cygwin|mingw|linux|sunos|solaris/i
+ dir = File.join(Config::CONFIG['sitelibdir'], 'sys')
+ file = File.join(dir, 'proctable.rb')
+ else
+ dir = File.join(Config::CONFIG['sitearchdir'], 'sys')
+ file = File.join(dir, 'proctable.' + Config::CONFIG['DLEXT'])
+ end
+
+ rm(file)
+end
+
+desc 'Run the benchmark suite'
+task :bench => [:build] do
+ sh "ruby -Ilib benchmarks/bench_ps.rb"
+end
+
+desc 'Run the example program'
+task :example => [:build] do
+ sh 'ruby -Ilib -Iext examples/example_ps.rb'
+end
+
+desc 'Run the test suite'
+Rake::TestTask.new do |t|
+ task :test => :build
+ t.libs << 'test'
+
+ case Config::CONFIG['host_os']
+ when /mswin|msdos|cygwin|mingw/i
+ t.test_files = FileList['test/test_sys_proctable_windows.rb']
+ t.libs << 'lib/windows'
+ when /linux/i
+ t.test_files = FileList['test/test_sys_proctable_linux.rb']
+ t.libs << 'lib/linux'
+ when /sunos|solaris/i
+ t.test_files = FileList['test/test_sys_proctable_sunos.rb']
+ t.libs << 'lib/sunos'
+ when /darwin/i
+ t.libs << 'ext/darwin'
+ t.test_files = FileList['test/test_sys_proctable_darwin.rb']
+ when /bsd/i
+ t.libs << 'ext/bsd'
+ t.test_files = FileList['test/test_sys_proctable_bsd.rb']
+ when /hpux/i
+ t.libs << 'ext/hpux'
+ t.test_files = FileList['test/test_sys_proctable_hpux.rb']
+ end
+end
+
+desc 'Create a gem'
+task :gem do
+ spec = eval(IO.read('sys-proctable.gemspec'))
+
+ case Config::CONFIG['host_os']
+ when /bsd/i
+ spec.files << 'ext/bsd/sys/proctable.c'
+ spec.extra_rdoc_files << 'ext/bsd/sys/proctable.c'
+ spec.test_files << 'test/test_sys_proctable_bsd.rb'
+ spec.extensions = ['ext/bsd/extconf.rb']
+ when /darwin/i
+ spec.files << 'ext/darwin/sys/proctable.c'
+ spec.extra_rdoc_files << 'ext/darwin/sys/proctable.c'
+ spec.test_files << 'test/test_sys_proctable_darwin.rb'
+ spec.extensions = ['ext/darwin/extconf.rb']
+ when /hpux/i
+ spec.files << 'ext/hpux/sys/proctable.c'
+ spec.extra_rdoc_files << 'ext/hpux/sys/proctable.c'
+ spec.test_files << 'test/test_sys_proctable_hpux.rb'
+ spec.extensions = ['ext/hpux/extconf.rb']
+ when /linux/i
+ spec.require_paths = ['lib', 'lib/linux']
+ spec.files += ['lib/linux/sys/proctable.rb']
+ spec.test_files << 'test/test_sys_proctable_linux.rb'
+ when /sunos|solaris/i
+ spec.require_paths = ['lib', 'lib/sunos']
+ spec.files += ['lib/sunos/sys/proctable.rb']
+ spec.test_files << 'test/test_sys_proctable_sunos.rb'
+ when /mswin|win32|dos|cygwin|mingw/i
+ spec.require_paths = ['lib', 'lib/windows']
+ spec.files += ['lib/windows/sys/proctable.rb']
+ spec.test_files << 'test/test_sys_proctable_windows.rb'
+ end
+
+ Gem::Builder.new(spec).build
+end
+
+desc 'Install the sys-proctable library as a gem'
+task :install_gem => [:gem] do
+ gem_name = Dir['*.gem'].first
+ sh "gem install #{gem_name}"
+end
21 benchmarks/bench_ps.rb
@@ -0,0 +1,21 @@
+########################################################################
+# bench_ps.rb
+#
+# Benchmark program to show overall speed and compare the block form
+# versus the non-block form. You should run this benchmark via the
+# 'rake bench' Rake task.
+########################################################################
+require 'benchmark'
+require 'sys/proctable'
+
+MAX = 10
+
+Benchmark.bm do |bench|
+ bench.report("Block form"){
+ MAX.times{ Sys::ProcTable.ps{} }
+ }
+
+ bench.report("Non-block form"){
+ MAX.times{ Sys::ProcTable.ps }
+ }
+end
87 doc/bsd.txt
@@ -0,0 +1,87 @@
+= Description
+ sys-proctable
+
+ A Ruby interface to the 'ps' command. This is a C extension, not parsed
+ output. For BSD flavors the kvm interface is used.
+
+= Synopsis
+ require 'sys/proctable'
+ include Sys
+
+ # Everything
+ ProcTable.ps{ |p|
+ puts p.pid.to_s
+ puts p.comm
+ ...
+ }
+
+ or
+
+ # Just one process
+ p = ProcTable.ps(2123)
+ puts p.pid.to_s
+ puts p.comm
+ ...
+
+ or
+
+ # Return the results as an array of ProcTableStructs
+ a = ProcTable.ps()
+ a.each do |p|
+ puts a.pid
+ ...
+ end
+
+= Constants
+VERSION
+ Returns the current version number for this library (as a string).
+
+= Class Methods
+ProcTable.fields
+ Returns an array of fields available on the current OS.
+
+ProcTable.ps(pid = nil)
+ProcTable.ps{ |s| ... }
+ If no pid's or processes are included as arguments, in block form it
+ returns a struct of type ProcTableStruct for every process in the proc
+ table. Otherwise it returns an array of ProcTableStruct's.
+
+ If a pid argument is provided, a single ProcTable struct is returned, or
+ nil if the pid is not found.
+
+= Exception Classes
+ProcTable::Error < StandardError
+ Raised if any of the ProcTable methods fail.
+
+= Supported fields
+ You can view the supported fields with the "fields()" class method.
+
+= Future Plans
+ Add a pure-ruby version as an alternative
+ Add ttydev info
+ Add a sysctl version
+
+= Known Bugs
+ The kvm version for FreeBSD 5.x does not support all of the fields that
+ the 4.x version supports.
+
+ If you find any other bugs please log them on the project
+ page at http://www.rubyforge.org/projects/sysutils
+
+= License
+ Artistic 2.0
+
+= Copyright
+ (C) 2003-2009 Daniel J. Berger
+ All Rights Reserved
+
+= Warranty
+ This package is provided "as is" and without any express or
+ implied warranties, including, without limitation, the implied
+ warranties of merchantability and fitness for a particular purpose
+
+= Author
+ Daniel J. Berger
+
+= See Also
+ ps, proc
75 doc/hpux.txt
@@ -0,0 +1,75 @@
+= Description
+ sys-proctable
+
+ A Ruby version of the 'ps' command. This is a C extension, not parsed
+ output. For HP-UX, proc structs are grabbed via the pstat_getproc() call.
+
+= Synopsis
+ require 'sys/proctable'
+ include Sys
+
+ # Everything
+ ProcTable.ps{ |p|
+ puts p.pid.to_s
+ puts p.comm
+ ...
+ }
+
+ or
+
+ # Return the results as an array of ProcTableStructs
+ a = ProcTable.ps()
+ a.each do |p|
+ puts a.pid
+ ...
+ end
+
+= Constants
+VERSION
+ Returns the current version number for this library (as a string).
+
+= Class Methods
+ProcTable.fields
+ Returns an array of fields available on the current OS.
+
+ProcTable.ps(pid=nil)
+ProcTable.ps{ |s| ... }
+ Returns a struct of type ProcTableStruct for every process in the proc
+ table in block form. Otherwise it returns an array of ProcTableStruct's.
+
+ If a pid is provided then a single ProcTable struct is returned, or nil
+ if the pid is not found.
+
+= Supported fields
+ You can view the supported fields with the "fields()" class method.
+
+= Future Plans
+ Have the flags field return a meaningful value.
+
+= Notes
+ The "comm" field isn't really part of the psinfo struct. It is just a copy
+ (i.e. is identical to) the "fname" field. I added it to provide a degree
+ of consistency between all of the platforms. I will also make a point
+ of adding it to any future platform releases.
+
+= Known Bugs
+ None that I'm aware of. Please log any bugs on the project page at
+ http://www.rubyforge.org/projects/sysutils
+
+= License
+ Artistic 2.0
+
+= Copyright
+ (C) 2003-2009 Daniel J. Berger
+ All Rights Reserved.
+
+= Warranty
+ This package is provided "as is" and without any express or
+ implied warranties, including, without limitation, the implied
+ warranties of merchantability and fitness for a particular purpose.
+
+= Author
+ Daniel J. Berger
+
+= See Also
+ ps, proc
81 doc/linux.txt
@@ -0,0 +1,81 @@
+= Description
+ A Ruby interface for gathering process table information. This is a pure
+ Ruby implementation that reads data out of your /proc filesystem.
+
+= Synopsis
+ require 'sys/proctable'
+ include Sys
+
+ # Everything
+ ProcTable.ps{ |p|
+ puts p.pid.to_s
+ puts p.comm
+ ...
+ }
+
+ or
+
+ # Just one process
+ p = ProcTable.ps(2123)
+ puts p.pid.to_s
+ puts p.comm
+ ...
+
+ or
+
+ # Return the results as an array of ProcTableStructs
+ a = ProcTable.ps()
+ a.each do |p|
+ puts a.pid
+ ...
+ end
+
+= Constants
+VERSION
+ Returns the current version number for this library (as a string).
+
+= Class Methods
+ProcTable.fields
+ Returns an array of fields available on the current OS.
+
+ProcTable.ps(pid=nil)
+ProcTable.ps{ |s| ... }
+ If no pid's or processes are included as arguments, in block form it
+ returns a struct of type ProcTableStruct for every process in the proc
+ table. Otherwise it returns an array of ProcTableStruct's.
+
+ If a process id is provided, a single ProcTable struct is returned, or
+ nil if the pid is not found.
+
+= Exception Classes
+ProcTable::Error < StandardError
+ Raised if the /proc field is unreadable and/or unmounted.
+
+= Supported fields
+ You can view the supported fields with the "fields()" class method.
+
+= Future Plans
+ None at this time. Please post any feature requests on the project page
+ at http://www.rubyforge.org/projects/sysutils.
+
+= Known Bugs
+ None known. Please log any bugs on the project page at
+ http://www.rubyforge.org/projects/sysutils
+
+= License
+ Artistic 2.0
+
+= Copyright
+ (C) 2003-2009 Daniel J. Berger
+ All Rights Reserved
+
+= Warranty
+ This package is provided "as is" and without any express or
+ implied warranties, including, without limitation, the implied
+ warranties of merchantability and fitness for a particular purpose.
+
+= Author
+ Daniel J. Berger
+
+= See Also
+ ps, proc(5)
81 doc/solaris.txt
@@ -0,0 +1,81 @@
+= Description
+ A Ruby interface for gathering process table information. This is a pure
+ Ruby implementation that unpacks data out of your /proc filesystem.
+
+= Synopsis
+ require 'sys/proctable'
+ include Sys
+
+ # Everything
+ ProcTable.ps{ |p|
+ puts p.pid.to_s
+ puts p.comm
+ ...
+ }
+
+ or
+
+ # Just one process
+ s = ProcTable.ps(2123)
+ puts s.pid.to_s
+ puts s.comm
+ ...
+
+ # Return the results as an array of ProcTableStructs
+ a = ProcTable.ps
+ a.each do |p|
+ puts a.pid
+ ...
+ end
+
+= Constants
+VERSION
+ Returns the current version number for this package (as a string).
+
+= Class Methods
+ProcTable.fields
+ Returns an array of fields available on the current OS.
+
+ProcTable.ps(pid=nil)
+ProcTable.ps{ |s| ... }
+ If no pid is included as an argument, in block form it
+ returns a struct of type ProcTableStruct for every process in the proc
+ table. Otherwise it returns an array of ProcTable struct's. If a pid
+ is provided it will return a single ProcTable struct for that pid, or
+ nil if it is not found.
+
+= Exception Classes
+ProcTable::Error < StandardError
+ Raised if the /proc directory is unreadable and/or unmounted.
+
+= Supported fields
+ You can view the supported fields with the "fields()" class method.
+
+= Future Plans
+ Support for 2.6 and 2.7 if requested.
+
+= Notes
+ The cmdline string is limited to 80 characters, except for those processes
+ which you (or your program) own.
+
+= Known Bugs
+ None that I am aware of. Please log any bugs on the RubyForge project page at
+ http://www.rubyforge.org/projects/sysutils
+
+= License
+ Artistic 2.0
+
+= Copyright
+ (C) 2003-2009 Daniel J. Berger
+ All Rights Reserved.
+
+= Warranty
+ This package is provided "as is" and without any express or
+ implied warranties, including, without limitation, the implied
+ warranties of merchantability and fitness for a particular purpose.
+
+= Author
+ Daniel J. Berger
+
+= See Also
+ ps, proc
47 doc/top.txt
@@ -0,0 +1,47 @@
+= Description
+ A simple 'top' interface for Ruby
+
+= Prerequisites
+ Requires the "sys/proctable" package (which should be installed along
+ with this package).
+
+= Synopsis
+ require "sys/top"
+
+ Sys::Top.top(5).each{ |ps|
+ p ps
+ }
+
+= Constants
+VERSION
+ Returns the version number of this package as a String.
+
+= Class Methods
+Sys::Top.top(number=10, field="pctcpu")
+ Returns an array of ProcTableStruct's. The size of the array (i.e. the
+ number of processes) that it returns is based on +number+, and sorted by
+ +pctcpu+. By default, the size and field values are 10 and "pctcpu",
+ respectively.
+
+= Notes
+ Not all fields are available on all platforms. Please check your
+ platform specific documentation for which fields are available.
+
+= Bugs
+ None that I'm aware of. Please log bug reports on the project page at
+ http://www.rubyforge.org/projects/sysutils
+
+= License
+ Artistic 2.0
+
+= Copyright
+ (C) 2004-2009 Daniel J. Berger
+ All Rights Reserved.
+
+= Warranty
+ This package is provided "as is" and without any express or
+ implied warranties, including, without limitation, the implied
+ warranties of merchantability and fitness for a particular purpose.
+
+= Author
+ Daniel J. Berger
104 doc/windows.txt
@@ -0,0 +1,104 @@
+= Description
+ A Ruby interface for gathering process information. For MS Windows,
+ the process information is gathered via OLE + WMI, using pure Ruby.
+
+= Synopsis
+ require 'sys/proctable'
+ include Sys
+
+ # Everything
+ ProcTable.ps{ |p|
+ puts p.pid.to_s
+ puts p.comm
+ ...
+ }
+
+ or
+
+ # A single pid
+ p = ProcTable.ps(1234)
+ puts p.pid.to_s
+ puts p.comm
+ ...
+
+ or
+
+ # Return the results as an array of ProcTableStructs
+ a = ProcTable.ps
+ a.each do |p|
+ puts a.pid
+ ...
+ end
+
+= Constants
+VERSION
+ Returns the current version number for this library (as a string).
+
+= Class Methods
+ProcTable.fields
+ Returns an Array of fields available on the current OS in the
+ ProcTableStruct.
+
+ProcTable.ps(pid=nil, host='localhost')
+ProcTable.ps{ |s| ... }
+ Returns a struct of type ProcTableStruct for every process in the proc
+ table in block form. Otherwise it returns an array of ProcTableStruct's.
+
+ If 'pid' is provided, then only a struct for that pid is returned, or
+ nil if it is not found.
+
+ If 'host' is provided, then processes from that host are gathered. By
+ default, process information is gathered on the local host.
+
+= Supported fields
+ You can also view the supported fields with the Sys::ProcTable.fields
+ method.
+
+= Notes
+ For the sake of attempting to provide a somewhat common API, the 'comm'
+ and 'cmdline' fields have been included as part of the structure. The
+ 'comm' member corresponds to the Name attribute of Win32_Process. The
+ 'cmdline' attribute corresponds to either the Executable_Path attribute
+ (on Windows 2000 or earlier) or the CommandLine attribute (on Windows XP
+ and later).
+
+ Also note that the ProcessId and ParentProcessId attributes have been
+ abbreviated as 'pid' and 'ppid' in the struct members, again to keep the
+ members more consistent between platforms.
+
+ The "Mem Usage" and "VM Size" that you may be used to seeing in your Task
+ Manager window (probably) correspond to the 'working_set_size' and
+ 'page_file_usage' struct members, respectively, keeping in mind that
+ those values are in bytes, not kilobytes. I say 'probably' because
+ comments that I've read online indicate that it may not always line up
+ with what you see in the Task Manager, based on the current version (or
+ even Service Pack) of Windows that you are using.
+
+= Future Plans
+ Possibly use the Win32_PerfFormattedData_PerfProc_Process class to get
+ additional process information.
+
+= Known Bugs
+ Versions of Ruby earlier than 1.8.2 resulted in segfaults when trying to
+ run this code. You will likely encounter the same behavior.
+
+ Please log any additional bug reports on the project page at
+ http://www.rubyforge.org/projects/sysutils
+
+= License
+ Artistic 2.0
+
+= Copyright
+ (C) 2003-2009 Daniel J. Berger
+ All Rights Reserved
+
+= Warranty
+ This package is provided "as is" and without any express or
+ implied warranties, including, without limitation, the implied
+ warranties of merchantability and fitness for a particular purpose.
+
+= Author
+ Daniel J. Berger
+
+= See Also
+ OLE + WMI
20 examples/example_ps.rb
@@ -0,0 +1,20 @@
+#######################################################################
+# example_ps.rb
+#
+# Generic test program that demonstrates the use of ProcTable.ps. You
+# can run this via the 'rake example' task.
+#
+# Modify as you see fit
+#######################################################################
+require 'sys/proctable'
+include Sys
+
+puts "VERSION: " + ProcTable::VERSION
+sleep 2
+
+ProcTable.ps{ |s|
+ ProcTable.fields.each{ |field|
+ puts "#{field}: " + s.send(field).to_s
+ }
+ puts '=' * 30
+}
14 ext/bsd/extconf.rb
@@ -0,0 +1,14 @@
+require 'mkmf'
+
+have_type('rb_pid_t', 'ruby.h')
+
+have_library('kvm')
+have_func('kvm_openfiles')
+have_struct_member('struct kinfo_proc', 'kp_proc', 'sys/user.h')
+have_struct_member('struct kinfo_proc', 'kp_eproc', 'sys/user.h')
+have_struct_member('struct kinfo_proc', 'u_kproc', 'sys/user.h')
+have_struct_member('struct eproc', 'e_stats', 'sys/sysctl.h')
+have_struct_member('struct eproc', 'p_oncpu', 'sys/sysctl.h')
+have_struct_member('struct eproc', 'p_runtime', 'sys/sysctl.h')
+
+create_makefile('sys/proctable', 'sys')
299 ext/bsd/sys/proctable.c
@@ -0,0 +1,299 @@
+/**********************************************************************
+ * proctable.c
+ *
+ * This is a generic kvm interface used by the various BSD flavors
+ * for the sys-proctable library.
+ **********************************************************************/
+#include "ruby.h"
+#include <kvm.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/user.h>
+
+#define SYS_PROCTABLE_VERSION "0.9.0"
+
+VALUE cProcTableError, sProcStruct;
+
+char* fields[] = {
+ "pid","ppid","pgid","ruid",
+ "rgid","comm","state","pctcpu","oncpu","ttynum","ttydev","wmesg",
+ "time", "priority","usrpri","nice","cmdline","start",
+ "maxrss","ixrss","idrss","isrss","minflt","majflt","nswap",
+ "inblock","oublock","msgsnd","msgrcv","nsignals","nvcsw","nivcsw",
+ "utime","stime"
+};
+
+/*
+ * call-seq:
+ * ProcTable.ps(pid=nil)
+ * ProcTable.ps(pid=nil){ |ps| ... }
+ *
+ * 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+.
+ */
+static VALUE pt_ps(int argc, VALUE* argv, VALUE klass){
+ kvm_t *kd;
+ char errbuf[_POSIX2_LINE_MAX];
+ char cmdline[_POSIX_ARG_MAX+1];
+ char state[8];
+ char** args = malloc(sizeof(char*));
+ struct kinfo_proc* procs;
+ int count; /* Holds total number of processes */
+ int i = 0;
+ VALUE v_pid, v_tty_num, v_tty_dev, v_start_time;
+ VALUE v_pstruct = Qnil;
+ VALUE v_array = Qnil;
+
+ rb_scan_args(argc, argv, "01", &v_pid);
+
+ if(!rb_block_given_p())
+ v_array = rb_ary_new();
+
+ // Open the kvm interface, get a descriptor
+ if ((kd = kvm_open(NULL, NULL, NULL, 0, errbuf)) == NULL)
+ rb_raise(cProcTableError, errbuf);
+
+ // Get the list of processes
+ if ((procs = kvm_getprocs(kd, KERN_PROC_ALL, 0, &count)) == NULL) {
+ strcpy(errbuf,kvm_geterr(kd));
+ kvm_close(kd);
+ rb_raise(cProcTableError, errbuf);
+ }
+
+ for(i=0; i<count; i++){
+ // Reset some variables
+ v_tty_num = Qnil;
+ v_tty_dev = Qnil;
+ v_start_time = Qnil;
+
+ // If a PID is provided, skip unless the PID matches
+ if(!NIL_P(v_pid)){
+#ifdef HAVE_ST_KP_PROC
+ if(procs[i].kp_proc.p_pid != NUM2INT(v_pid))
+ continue;
+#else
+ if(procs[i].ki_pid != NUM2INT(v_pid))
+ continue;
+#endif
+ }
+
+ // Get the command line arguments for the process
+ cmdline[0] = '\0';
+ args = kvm_getargv(kd, (const struct kinfo_proc *)&procs[i], 0);
+ if(args){
+ int j = 0;
+ while (args[j] && strlen(cmdline) <= _POSIX_ARG_MAX) {
+ strcat(cmdline, args[j]);
+ strcat(cmdline, " ");
+ j++;
+ }
+ }
+
+ // Get the start time of the process
+ v_start_time = rb_time_new(
+#ifdef HAVE_ST_E_STATS
+ procs[i].kp_eproc.e_stats.p_start.tv_sec,
+ procs[i].kp_eproc.e_stats.p_start.tv_usec
+#else
+ 0,0
+#endif
+ );
+
+ // Get the state of the process
+#ifdef HAVE_ST_KP_PROC
+ switch(procs[i].kp_proc.p_stat)
+#else
+ switch(procs[i].ki_stat)
+#endif
+ {
+ case SIDL:
+ strcpy(state, "idle");
+ break;
+ case SRUN:
+ strcpy(state, "run");
+ break;
+ case SSLEEP:
+ strcpy(state, "sleep");
+ break;
+ case SSTOP:
+ strcpy(state, "stop");
+ break;
+ case SZOMB:
+ strcpy(state, "zombie");
+ break;
+ default:
+ strcpy(state, "unknown");
+ break;
+ }
+
+ // Get ttynum and ttydev. If ttynum is -1, there is no tty
+#ifdef HAVE_ST_KP_EPROC
+ v_tty_num = INT2FIX(procs[i].kp_eproc.e_tdev),
+ v_tty_dev = rb_str_new2(devname(procs[i].kp_eproc.e_tdev, S_IFCHR));
+#elif HAVE_ST_U_KPROC
+ v_tty_num = INT2FIX(procs[i].u_kproc.ki_tdev),
+ v_tty_dev = rb_str_new2(devname(procs[i].u_kproc.ki_tdev, S_IFCHR));
+#else
+ v_tty_num = INT2FIX(procs[i].ki_tdev),
+ v_tty_dev = rb_str_new2(devname(procs[i].ki_tdev, S_IFCHR));
+#endif
+
+#ifdef HAVE_ST_KP_PROC
+ v_pstruct = rb_struct_new(
+ sProcStruct,
+ INT2FIX(procs[i].kp_proc.p_pid),
+ INT2FIX(procs[i].kp_eproc.e_ppid),
+ INT2FIX(procs[i].kp_eproc.e_pgid),
+ INT2FIX(procs[i].kp_eproc.e_pcred.p_ruid),
+ INT2FIX(procs[i].kp_eproc.e_pcred.p_rgid),
+ rb_str_new2(procs[i].kp_proc.p_comm),
+ rb_str_new2(state),
+ rb_float_new(procs[i].kp_proc.p_pctcpu),
+#ifdef HAVE_ST_P_ONCPU
+ INT2FIX(procs[i].kp_proc.p_oncpu),
+#else
+ Qnil,
+#endif
+ v_tty_num,
+ v_tty_dev,
+ rb_str_new2(procs[i].kp_eproc.e_wmesg),
+#ifdef HAVE_ST_P_RUNTIME
+ INT2FIX(procs[i].kp_proc.p_runtime/1000000),
+#else
+ Qnil,
+#endif
+ INT2FIX(procs[i].kp_proc.p_priority),
+ INT2FIX(procs[i].kp_proc.p_usrpri),
+ INT2FIX(procs[i].kp_proc.p_nice),
+ rb_str_new2(cmdline),
+ v_start_time,
+#ifdef HAVE_ST_E_STATS
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_maxrss),
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_ixrss),
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_idrss),
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_isrss),
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_minflt),
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_majflt),
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_nswap),
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_inblock),
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_oublock),
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_msgsnd),
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_msgrcv),
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_nsignals),
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_nvcsw),
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_nivcsw),
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_utime.tv_sec),
+ LONG2NUM(procs[i].kp_eproc.e_stats.p_ru.ru_stime.tv_sec)
+#else
+ Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil,
+ Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil
+#endif
+ );
+#else
+ v_pstruct = rb_struct_new(
+ sProcStruct,
+ INT2FIX(procs[i].ki_pid),
+ INT2FIX(procs[i].ki_ppid),
+ INT2FIX(procs[i].ki_pgid),
+ INT2FIX(procs[i].ki_ruid),
+ INT2FIX(procs[i].ki_rgid),
+ rb_str_new2(procs[i].ki_ocomm),
+ rb_str_new2(state),
+ rb_float_new(procs[i].ki_pctcpu),
+ INT2FIX(procs[i].ki_oncpu),
+ v_tty_num,
+ v_tty_dev,
+ rb_str_new2(procs[i].ki_wmesg),
+ INT2FIX(procs[i].ki_runtime/1000000),
+ INT2FIX(procs[i].ki_pri.pri_level),
+ INT2FIX(procs[i].ki_pri.pri_user),
+ INT2FIX(procs[i].ki_nice),
+ rb_str_new2(cmdline),
+ v_start_time,
+ Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil,
+ Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil, Qnil
+ );
+#endif
+
+ OBJ_FREEZE(v_pstruct); /* Read-only data */
+
+ if(rb_block_given_p())
+ rb_yield(v_pstruct);
+ else
+ rb_ary_push(v_array, v_pstruct);
+ }
+
+ free(args);
+
+ if(kd)
+ kvm_close(kd);
+
+ if(!NIL_P(v_pid))
+ return v_pstruct;
+
+ return v_array; // Nil if block given
+}
+
+/*
+ * call-seq:
+ * ProcTable.fields
+ *
+ * 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.
+ */
+static VALUE pt_fields(VALUE klass){
+ VALUE v_array = rb_ary_new();
+ int size = sizeof(fields) / sizeof(fields[0]);
+ int i;
+
+ for(i = 0; i < size; i++)
+ rb_ary_push(v_array, rb_str_new2(fields[i]));
+
+ return v_array;
+}
+
+/*
+ * A Ruby interface for gathering process table information.
+ */
+void Init_proctable(){
+ VALUE mSys, cProcTable;
+
+ /* The Sys module serves as a namespace only */
+ mSys = rb_define_module("Sys");
+
+ /* The ProcTable class encapsulates process table information */
+ cProcTable = rb_define_class_under(mSys, "ProcTable", rb_cObject);
+
+ /* The error typically raised if any of the ProcTable methods fail */
+ cProcTableError = rb_define_class_under(cProcTable, "Error", rb_eStandardError);
+
+ /* Singleton Methods */
+
+ rb_define_singleton_method(cProcTable, "ps", pt_ps, -1);
+ rb_define_singleton_method(cProcTable, "fields", pt_fields, 0);
+
+ /* There is no constructor */
+ rb_funcall(cProcTable, rb_intern("private_class_method"), 1, ID2SYM(rb_intern("new")));
+
+ /* Constants */
+
+ /* 0.9.0: The version of the sys-proctable library */
+ rb_define_const(cProcTable, "VERSION", rb_str_new2(SYS_PROCTABLE_VERSION));
+
+ /* Structures */
+
+ sProcStruct = rb_struct_define("ProcTableStruct","pid","ppid","pgid","ruid",
+ "rgid","comm","state","pctcpu","oncpu","ttynum","ttydev","wmesg",
+ "time", "priority","usrpri","nice","cmdline","start",
+ "maxrss","ixrss","idrss","isrss","minflt","majflt","nswap",
+ "inblock","oublock","msgsnd","msgrcv","nsignals","nvcsw","nivcsw",
+ "utime","stime", NULL
+ );
+}
4 ext/darwin/extconf.rb
@@ -0,0 +1,4 @@
+require 'mkmf'
+
+have_type('rb_pid_t', 'ruby.h')
+create_makefile('sys/proctable', 'sys')
256 ext/darwin/sys/proctable.c
@@ -0,0 +1,256 @@
+/**********************************************************************
+ * Mac OS X code for sys-proctable Ruby library. *
+ * *
+ * Date: 3-Mar-2006 (original submission date) *
+ * Author: David Felstead (david.felstead at gmail dot com) *
+ * Based on bsd.c by Daniel J. Berger (djberg96 at gmail dot com) *
+ *********************************************************************/
+#include "ruby.h"
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <errno.h>
+
+#define SYS_PROCTABLE_VERSION "0.9.0"
+
+#define PROC_MIB_LEN 4
+#define ARGS_MIB_LEN 3
+#define ARGS_MAX_LEN 4096
+VALUE cProcTableError, sProcStruct;
+
+char* fields[] = {
+ "pid", "ppid", "pgid", "ruid", "rgid", "comm", "state", "pctcpu", "oncpu",
+ "tnum", "tdev", "wmesg", "rtime", "priority", "usrpri", "nice", "cmdline",
+ "starttime", "maxrss", "ixrss", "idrss", "isrss", "minflt", "majflt",
+ "nswap", "inblock", "oublock", "msgsnd", "msgrcv", "nsignals", "nvcsw",
+ "nivcsw", "utime", "stime"
+};
+
+/*
+ * call-seq:
+ * ProcTable.ps(pid=nil)
+ * ProcTable.ps(pid=nil){ |ps| ... }
+ *
+ * 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+.
+ */
+static VALUE pt_ps(int argc, VALUE* argv, VALUE klass){
+ int err;
+ char state[8];
+ struct kinfo_proc* procs;
+ int count; /* Holds total number of processes */
+ int i = 0;
+ VALUE v_pid, v_tty_num, v_tty_dev, v_start_time;
+ VALUE v_pstruct = Qnil;
+ VALUE v_array = rb_ary_new();
+ size_t length;
+ char args[ARGS_MAX_LEN+1];
+
+ // Passed into sysctl call
+ static const int name_mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
+
+ rb_scan_args(argc, argv, "01", &v_pid);
+
+ // Get size of proc kproc buffer
+ err = sysctl( (int *) name_mib, PROC_MIB_LEN, NULL, &length, NULL, 0);
+
+ if(err == -1)
+ rb_raise(cProcTableError, strerror(errno));
+
+ // Populate the kproc buffer
+ procs = malloc(length);
+
+ if(procs == NULL)
+ rb_raise(cProcTableError, strerror(errno));
+
+ err = sysctl( (int *) name_mib, PROC_MIB_LEN, procs, &length, NULL, 0);
+
+ if(err == -1)
+ rb_raise(cProcTableError, strerror(errno));
+
+ // If we're here, we got our list
+ count = length / sizeof(struct kinfo_proc);
+
+ for(i = 0; i < count; i++) {
+ v_tty_num = Qnil;
+ v_tty_dev = Qnil;
+ v_start_time = Qnil;
+
+ // If a PID is provided, skip unless the PID matches
+ if( (!NIL_P(v_pid)) && (procs[i].kp_proc.p_pid != NUM2INT(v_pid)) )
+ continue;
+
+ *args = '\0';
+
+ /* Query the command line args */
+ /* TODO: Cmd line not working for now - fix */
+
+ /*args_mib[ARGS_MIB_LEN - 1] = procs[i].kp_proc.p_pid;
+ args_err = sysctl( (int *) args_mib, ARGS_MIB_LEN, args, &args_size, NULL, 0);
+
+ if(args_err >= 0) {
+ fprintf(stderr, "Ret: %d LEN: %d\n", err, args_size);
+ char *c;
+ for(c = args; c < args+args_size; c++)
+ if(*c == '\0') *c = ' ';
+ args[args_size] = '\0';
+ } else {
+ fprintf(stderr, "err: %s LEN: %d\n", strerror(errno), args_size);
+ }*/
+
+ // Get the start time of the process
+ v_start_time = rb_time_new(
+ procs[i].kp_proc.p_un.__p_starttime.tv_sec,
+ procs[i].kp_proc.p_un.__p_starttime.tv_usec
+ );
+
+ // Get the state of the process
+ switch(procs[i].kp_proc.p_stat)
+ {
+ case SIDL:
+ strcpy(state, "idle");
+ break;
+ case SRUN:
+ strcpy(state, "run");
+ break;
+ case SSLEEP:
+ strcpy(state, "sleep");
+ break;
+ case SSTOP:
+ strcpy(state, "stop");
+ break;
+ case SZOMB:
+ strcpy(state, "zombie");
+ break;
+ default:
+ strcpy(state, "unknown");
+ break;
+ }
+
+ // Get ttynum and ttydev. If ttynum is -1, there is no tty.
+ if(procs[i].kp_eproc.e_tdev != -1){
+ v_tty_num = INT2FIX(procs[i].kp_eproc.e_tdev),
+ v_tty_dev = rb_str_new2(devname(procs[i].kp_eproc.e_tdev, S_IFCHR));
+ }
+
+ v_pstruct = rb_struct_new(
+ sProcStruct,
+ INT2FIX(procs[i].kp_proc.p_pid),
+ INT2FIX(procs[i].kp_eproc.e_ppid),
+ INT2FIX(procs[i].kp_eproc.e_pgid),
+ INT2FIX(procs[i].kp_eproc.e_pcred.p_ruid),
+ INT2FIX(procs[i].kp_eproc.e_pcred.p_rgid),
+ rb_str_new2(procs[i].kp_proc.p_comm),
+ rb_str_new2(state),
+ rb_float_new(procs[i].kp_proc.p_pctcpu),
+ Qnil,
+ v_tty_num,
+ v_tty_dev,
+ rb_str_new2(procs[i].kp_eproc.e_wmesg),
+ INT2FIX(procs[i].kp_proc.p_rtime.tv_sec),
+ INT2FIX(procs[i].kp_proc.p_priority),
+ INT2FIX(procs[i].kp_proc.p_usrpri),
+ INT2FIX(procs[i].kp_proc.p_nice),
+ rb_str_new2(args),
+ v_start_time,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_maxrss) : Qnil,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_ixrss) : Qnil,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_idrss) : Qnil,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_isrss) : Qnil,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_minflt) : Qnil,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_majflt) : Qnil,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_nswap) : Qnil,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_inblock) : Qnil,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_oublock) : Qnil,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_msgsnd) : Qnil,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_msgrcv) : Qnil,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_nsignals) : Qnil,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_nvcsw) : Qnil,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_nivcsw) : Qnil,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_utime.tv_sec) : Qnil,
+ (procs[i].kp_proc.p_ru && procs[i].kp_proc.p_stat != 5) ? LONG2NUM(procs[i].kp_proc.p_ru->ru_stime.tv_sec) : Qnil
+ );
+
+ OBJ_FREEZE(v_pstruct); // This is read-only data
+
+ if(rb_block_given_p())
+ rb_yield(v_pstruct);
+ else
+ rb_ary_push(v_array, v_pstruct);
+ }
+
+ if(procs) free(procs);
+
+ if(!rb_block_given_p()){
+ if(NIL_P(v_pid))
+ return v_array;
+ else
+ return v_pstruct;
+ }
+
+ return Qnil;
+}
+
+/*
+ * call-seq:
+ * ProcTable.fields
+ *
+ * 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.
+ */
+static VALUE pt_fields(VALUE klass){
+ VALUE v_array = rb_ary_new();
+ int size = sizeof(fields) / sizeof(fields[0]);
+ int i;
+
+ for(i = 0; i < size; i++)
+ rb_ary_push(v_array, rb_str_new2(fields[i]));
+
+ return v_array;
+}
+
+/*
+ * A Ruby interface for gathering process table information.
+ */
+void Init_proctable(){
+ VALUE mSys, cProcTable;
+
+ /* The Sys module serves as a namespace only */
+ mSys = rb_define_module("Sys");
+
+ /* The ProcTable class encapsulates process table information */
+ cProcTable = rb_define_class_under(mSys, "ProcTable", rb_cObject);
+
+ /* The Error class typically raised if any of the ProcTable methods fail */
+ cProcTableError = rb_define_class_under(cProcTable, "Error", rb_eStandardError);
+
+ /* Singleton methods */
+
+ rb_define_singleton_method(cProcTable, "ps", pt_ps, -1);
+ rb_define_singleton_method(cProcTable, "fields", pt_fields, 0);
+
+ /* There is no constructor */
+ rb_funcall(cProcTable, rb_intern("private_class_method"), 1, ID2SYM(rb_intern("new")));
+
+ /* Constants */
+
+ /* 0.9.0: The version of the sys-proctable library */
+ rb_define_const(cProcTable, "VERSION", rb_str_new2(SYS_PROCTABLE_VERSION));
+
+ /* Structs */
+
+ sProcStruct = rb_struct_define("ProcTableStruct","pid","ppid","pgid","ruid",
+ "rgid","comm","state","pctcpu","oncpu","tnum","tdev","wmesg",
+ "rtime", "priority","usrpri","nice","cmdline","starttime",
+ "maxrss","ixrss","idrss","isrss","minflt","majflt","nswap",
+ "inblock","oublock","msgsnd","msgrcv","nsignals","nvcsw","nivcsw",
+ "utime","stime", NULL
+ );
+}
4 ext/hpux/extconf.rb
@@ -0,0 +1,4 @@
+require 'mkmf'
+
+have_type('rb_pid_t', 'ruby.h')
+create_makefile('sys/proctable', 'sys')
329 ext/hpux/sys/proctable.c
@@ -0,0 +1,329 @@
+/**********************************************************************
+* proctable.c
+*
+* HP-UX specific code for the Ruby ps extension. Some code has been
+* copied directly from Dan Urist's Proc::ProcessTable Perl module.
+*
+* Author: Daniel Berger
+**********************************************************************/
+#include "ruby.h"
+
+#define _PSTAT64
+
+#define SYS_PROCTABLE_VERSION "0.9.0"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <sys/param.h>
+#include <sys/pstat.h>
+#include <devnm.h>
+
+#define BURST 30 /* pstat structs to get per syscall */
+
+/* Process state strings */
+#define SLEEP "sleep"
+#define RUN "run"
+#define STOP "stop"
+#define ZOMBIE "zombie"
+#define IDLE "idle"
+#define OTHER "other"
+
+VALUE sProcStruct, cProcError;
+
+/*****************************************************************************
+ * This array's only purpose is for the 'fields()' class method. If there's
+ * a way to report fields out of our defined struct (sProc), please tell me
+ * how!
+ *****************************************************************************/
+char *fields[] = {
+ "comm",
+ "uid",
+ "pid",
+ "ppid",
+ "dsize",
+ "tsize",
+ "ssize",
+ "nice",
+ "ttydev",
+ "pgrp",
+ "pri",
+ "addr",
+ "cpu",
+ "utime",
+ "stime",
+ "start",
+ "flag",
+ "stat",
+ "wchan",
+ "procnum",
+ "cmd",
+ "cmdline",
+ "time",
+ "cpticks",
+ "cptickstotal",
+ "fss",
+ "pctcpu",
+ "rssize",
+ "suid",
+ "shmsize",
+ "mmsize",
+ "usize",
+ "iosize",
+ "vtsize",
+ "vdsize",
+ "vssize",
+ "vshmsize",
+ "vmmsize",
+ "vusize",
+ "viosize",
+ "minorfaults",
+ "majorfaults",
+ "nswap",
+ "nsignals",
+ "msgrcv",
+ "msgsnd",
+ "maxrss",
+ "sid",
+ "schedpolicy",
+ "ticksleft",
+ "euid",
+ "egid",
+ "gid",
+ "sgid"
+};
+
+
+/*
+ * Private method that converts a psinfo struct into a Ruby struct.
+ */
+static VALUE proctable_getprocstruct(struct pst_status *p)
+{
+ char state[10];
+ char flag[12];
+ char ttydev[MAXPATHLEN+1];
+ VALUE v_tty, v_struct;
+
+ switch( p->pst_stat )
+ {
+ case PS_SLEEP:
+ strcpy(state,SLEEP);
+ break;
+ case PS_RUN:
+ strcpy(state,RUN);
+ break;
+ case PS_STOP:
+ strcpy(state,STOP);
+ break;
+ case PS_ZOMBIE:
+ strcpy(state,ZOMBIE);
+ break;
+ case PS_IDLE:
+ strcpy(state,IDLE);
+ break;
+ case PS_OTHER:
+ strcpy(state,OTHER);
+ break;
+ default:
+ strcpy(state,"unknown");
+ }
+
+ /* If the major number is -1, there is no associated tty */
+ if(p->pst_term.psd_major != -1){
+ devnm(
+ S_IFCHR,
+ (dev_t)((p->pst_term.psd_major << 24) | p->pst_term.psd_minor),
+ ttydev,
+ sizeof(ttydev),
+ 1
+ );
+ v_tty = rb_str_new2(ttydev);
+ }
+ else{
+ v_tty = rb_str_new2("");
+ }
+
+ v_struct = rb_struct_new(sProcStruct,
+ rb_str_new2(p->pst_ucomm),
+ INT2NUM(p->pst_uid),
+ INT2NUM(p->pst_pid),
+ INT2NUM(p->pst_ppid),
+ INT2NUM(p->pst_dsize),
+ INT2NUM(p->pst_tsize),
+ INT2NUM(p->pst_ssize),
+ INT2NUM(p->pst_nice),
+ v_tty,
+ INT2NUM(p->pst_pgrp),
+ INT2NUM(p->pst_pri),
+ INT2NUM(p->pst_addr),
+ INT2NUM(p->pst_cpu),
+ INT2NUM(p->pst_utime),
+ INT2NUM(p->pst_stime),
+ rb_time_new(p->pst_start,0),
+ INT2NUM(p->pst_flag),
+ rb_str_new2(state),
+ INT2NUM(p->pst_wchan),
+ INT2NUM(p->pst_procnum),
+ rb_str_new2(p->pst_cmd),
+ rb_str_new2(p->pst_cmd),
+ INT2NUM(p->pst_time),
+ INT2NUM(p->pst_cpticks),
+ INT2NUM(p->pst_cptickstotal),
+ INT2NUM(p->pst_fss),
+ rb_float_new(p->pst_pctcpu),
+ INT2NUM(p->pst_rssize),
+ INT2NUM(p->pst_suid),
+ INT2NUM(p->pst_shmsize),
+ INT2NUM(p->pst_mmsize),
+ INT2NUM(p->pst_usize),
+ INT2NUM(p->pst_iosize),
+ INT2NUM(p->pst_vtsize),
+ INT2NUM(p->pst_vdsize),
+ INT2NUM(p->pst_vssize),
+ INT2NUM(p->pst_vshmsize),
+ INT2NUM(p->pst_vmmsize),
+ INT2NUM(p->pst_vusize),
+ INT2NUM(p->pst_viosize),
+ UINT2NUM(p->pst_minorfaults),
+ UINT2NUM(p->pst_majorfaults),
+ UINT2NUM(p->pst_nswap),
+ UINT2NUM(p->pst_nsignals),
+ UINT2NUM(p->pst_msgrcv),
+ UINT2NUM(p->pst_msgsnd),
+ INT2NUM(p->pst_maxrss),
+ INT2NUM(p->pst_sid),
+ INT2NUM(p->pst_schedpolicy),
+ INT2NUM(p->pst_ticksleft),
+ INT2NUM(p->pst_euid),
+ INT2NUM(p->pst_egid),
+ INT2NUM(p->pst_gid),
+ INT2NUM(p->pst_sgid)
+ );
+
+ OBJ_FREEZE(v_struct);
+
+ return v_struct;
+}
+
+/*
+ * call-seq:
+ * ProcTable.ps(pid=nil)
+ * ProcTable.ps(pid=nil){ |ps| ... }
+ *
+ * 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+.
+ */
+static VALUE proctable_ps(int argc, VALUE *argv)
+{
+ struct pst_status pst[BURST];
+ int i, count;
+ int idx = 0;
+ int found = 0;
+ VALUE v_pid = Qnil;
+ VALUE v_arr = rb_ary_new();
+
+ rb_scan_args(argc, argv, "01", &v_pid);
+
+ if(v_pid != Qnil){
+ struct pst_status pst_single;
+ int n = NUM2INT(v_pid);
+ if(pstat_getproc(&pst_single, sizeof(pst_single), 0, n) > 0){
+ if(rb_block_given_p()){
+ rb_yield(proctable_getprocstruct(&pst_single));
+ return Qnil;
+ }
+ else{
+ return(proctable_getprocstruct(&pst_single));
+ }
+ }
+ else{
+ return Qnil; /* not found */
+ }
+ }
+
+ while ((count = pstat_getproc(pst, sizeof(pst[0]), BURST, idx)) > 0){
+ for (i = 0; i < count; i++){
+ if( rb_block_given_p() )
+ rb_yield(proctable_getprocstruct(&pst[i]));
+ else
+ rb_ary_push(v_arr, proctable_getprocstruct(&pst[i]) );
+ }
+ idx = pst[count-1].pst_idx + 1;
+ }
+
+ if(rb_block_given_p())
+ return Qnil;
+
+ return v_arr;
+}
+
+/*
+ * call-seq:
+ * ProcTable.fields
+ *
+ * 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.
+ */
+static VALUE proctable_fields()
+{
+ int i;
+ VALUE v_farray = rb_ary_new();
+
+ for(i = 0; i < (sizeof(fields) / sizeof(fields[0])); i++)
+ rb_ary_push(v_farray,rb_str_new2(fields[i]));
+
+ return v_farray;
+}
+
+/*
+ * A Ruby interface for gathering process table information.
+ */
+void Init_proctable()
+{
+ VALUE mSys, cProcTable;
+
+ /* The Sys module serves as a namespace only */
+ mSys = rb_define_module("Sys");
+
+ /* The ProcTable class encapsulates process table information */
+ cProcTable = rb_define_class_under(mSys, "ProcTable", rb_cObject);
+
+ /* The error typically raised if any of the ProcTable methods fail */
+ cProcError = rb_define_class_under(cProcTable, "Error", rb_eStandardError);
+
+ /* Singleton methods */
+
+ rb_define_singleton_method(cProcTable, "fields", proctable_fields, 0);
+ rb_define_singleton_method(cProcTable, "ps", proctable_ps, -1);
+
+ /* There is no constructor */
+ rb_funcall(cProcTable, rb_intern("private_class_method"), 1, ID2SYM(rb_intern("new")));
+
+ /* Constants */
+
+ /* 0.9.0: The version of the sys-proctable library */
+ rb_define_const(cProcTable, "VERSION", rb_str_new2(SYS_PROCTABLE_VERSION));
+
+ /* Structs */
+
+ sProcStruct = rb_struct_define("ProcTableStruct",
+ "comm","uid","pid","ppid","dsize","tsize","ssize","nice","ttydev","pgrp",
+ "pri","addr","cpu","utime","stime","start","flag","stat","wchan",
+ "procnum","cmd","cmdline","time","cpticks","cptickstotal","fss","pctcpu",
+ "rssize","suid","shmsize","mmsize", "usize","iosize","vtsize","vdsize",
+ "vssize","vshmsize","vmmsize","vusize","viosize","minorfaults",
+ "majorfaults","nswap","nsignals","msgrcv","msgsnd","maxrss","sid",
+ "schedpolicy","ticksleft","euid","egid","gid","sgid",NULL
+ );
+}
+
+#ifdef __cplusplus
+}
+#endif
250 lib/linux/sys/proctable.rb
@@ -0,0 +1,250 @@
+# The Sys module serves as a namespace only.
+module Sys
+
+ # The ProcTable class encapsulates process table information.
+ class ProcTable
+
+ class Error < StandardError; end
+
+ # There is no constructor
+ private_class_method :new
+
+ # The version of the sys-proctable library
+ VERSION = '0.9.0'
+
+ private
+
+ @fields = [
+ 'cmdline', # Complete command line
+ 'cwd', # Current working directory
+ 'environ', # Environment
+ 'exe', # Actual pathname of the executed command
+ 'fd', # File descriptors open by process
+ 'root', # Root directory of process
+ 'pid', # Process ID
+ 'comm', # Filename of executable
+ 'state', # Single character state abbreviation
+ 'ppid', # Parent process ID
+ 'pgrp', # Process group
+ 'session', # Session ID
+ 'tty_nr', # TTY (terminal) associated with the process
+ 'tpgid', # Group ID of the TTY
+ 'flags', # Kernel flags
+ 'minflt', # Number of minor faults
+ 'cminflt', # Number of minor faults of waited-for children
+ 'majflt', # Number of major faults
+ 'cmajflt', # Number of major faults of waited-for children
+ 'utime', # Number of user mode jiffies
+ 'stime', # Number of kernel mode jiffies
+ 'cutime', # Number of children's user mode jiffies
+ 'cstime', # Number of children's kernel mode jiffies
+ 'priority', # Nice value plus 15
+ 'nice', # Nice value
+ 'itrealvalue', # Time in jiffies before next SIGALRM
+ 'starttime', # Time in jiffies since system boot
+ 'vsize', # Virtual memory size in bytes
+ 'rss', # Resident set size
+ 'rlim', # Current limit on the rss in bytes
+ 'startcode', # Address above which program text can run
+ 'endcode', # Address below which program text can run
+ 'startstack', # Address of the startstack
+ 'kstkesp', # Kernel stack page address
+ 'kstkeip', # Kernel instruction pointer
+ 'signal', # Bitmap of pending signals
+ 'blocked', # Bitmap of blocked signals
+ 'sigignore', # Bitmap of ignored signals
+ 'sigcatch', # Bitmap of caught signals
+ 'wchan', # Channel in which the process is waiting
+ 'nswap', # Number of pages swapped
+ 'cnswap', # Cumulative nswap for child processes
+ 'exit_signal', # Signal to be sent to parent when process dies
+ 'processor', # CPU number last executed on
+ 'rt_priority', # Real time scheduling priority
+ 'policy', # Scheduling policy
+ 'name', # Process name
+ 'uid', # Real user ID
+ 'euid', # Effective user ID
+ 'gid', # Real group ID
+ 'egid' # Effective group ID
+ ]
+
+ public
+
+ ProcTableStruct = Struct.new('ProcTableStruct', *@fields)
+
+ # 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.
+ #
+ def self.ps(pid=nil)
+ 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
+ # 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?
+
+ struct.freeze # This is read-only data
+
+ if block_given?
+ yield struct
+ else
+ array << struct
+ end
+ }
+
+ pid ? struct : array
+ end
+
+ # 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}"
+ # }
+ #
+ def self.fields
+ @fields
+ end
+ end
+end
462 lib/sunos/sys/proctable.rb
@@ -0,0 +1,462 @@
+########################################################################
+# proctable.rb
+#
+# A pure Ruby version of sys-proctable for SunOS 5.8 or later.
+########################################################################
+
+# The Sys module serves as a namespace only.
+module Sys
+
+ # The ProcTable class encapsulates process table information.
+ class ProcTable
+
+ class Error < StandardError; end
+
+ # There is no constructor
+ private_class_method :new
+
+ # The version of the sys-proctable library
+ VERSION = '0.9.0'
+
+ private
+
+ PRNODEV = -1 # non-existent device
+
+ @fields = [
+ :flag, # process flags (deprecated)
+ :nlwp, # number of active lwp's in the process
+ :pid, # unique process id
+ :ppid, # process id of parent
+ :pgid, # pid of session leader
+ :sid, # session id
+ :uid, # real user id
+ :euid, # effective user id
+ :gid, # real group id
+ :egid, # effective group id
+ :addr, # address of the process
+ :size, # size of process in kbytes
+ :rssize, # resident set size in kbytes
+ :ttydev, # tty device (or PRNODEV)
+ :pctcpu, # % of recent cpu used by all lwp's
+ :pctmem, # % of system memory used by process
+ :start, # absolute process start time
+ :time, # usr + sys cpu time for this process
+ :ctime, # usr + sys cpu time for reaped children
+ :fname, # name of the exec'd file
+ :psargs, # initial characters argument list - same as cmdline
+ :wstat, # if a zombie, the wait status
+ :argc, # initial argument count
+ :argv, # address of initial argument vector
+ :envp, # address of initial environment vector
+ :dmodel, # data model of the process
+ :taskid, # task id
+ :projid, # project id
+ :nzomb, # number of zombie lwp's in the process
+ :poolid, # pool id
+ :zoneid, # zone id
+ :contract, # process contract
+ :lwpid, # lwp id
+ :wchan, # wait address for sleeping lwp
+ :stype, # synchronization event type
+ :state, # numeric lwp state
+ :sname, # printable character for state
+ :nice, # nice for cpu usage
+ :syscall, # system call number (if in syscall)
+ :pri, # priority
+ :clname, # scheduling class name
+ :name, # name of system lwp
+ :onpro, # processor which last ran thsi lwp
+ :bindpro, # processor to which lwp is bound
+ :bindpset, # processor set to which lwp is bound
+ :count, # number of contributing lwp's
+ :tstamp, # current time stamp
+ :create, # process/lwp creation time stamp
+ :term, # process/lwp termination time stamp
+ :rtime, # total lwp real (elapsed) time
+ :utime, # user level cpu time
+ :stime, # system call cpu time
+ :ttime, # other system trap cpu time
+ :tftime, # text page fault sleep time
+ :dftime, # text page fault sleep time
+ :kftime, # kernel page fault sleep time
+ :ltime, # user lock wait sleep time
+ :slptime, # all other sleep time
+ :wtime, # wait-cpu (latency) time
+ :stoptime, # stopped time
+ :minf, # minor page faults
+ :majf, # major page faults
+ :nswap, # swaps
+ :inblk, # input blocks
+ :oublk, # output blocks
+ :msnd, # messages sent
+ :mrcv, # messages received
+ :sigs, # signals received
+ :vctx, # voluntary context switches
+ :ictx, # involuntary context switches
+ :sysc, # system calls
+ :ioch, # chars read and written
+ :path, # array of symbolic link paths from /proc/<pid>/pid
+ :contracts, # array symbolic link paths from /proc/<pid>/contracts
+ :fd, # array of used file descriptors
+ :cmd_args, # array of command line arguments
+ :environ, # hash of environment associated with the process,
+ :cmdline # joined cmd_args if present, otherwise psargs
+ ]
+
+ @psinfo_pack_directive = [
+ 'i', # pr_flag
+ 'i', # pr_nlwp
+ 'i', # pr_pid
+ 'i', # pr_ppid
+ 'i', # pr_pgid
+ 'i', # pr_sid
+ 'i', # pr_uid