pax_global_header00006660000000000000000000000064143523362010014511gustar00rootroot0000000000000052 comment=cab42827c5278425c68d8c59e1e31b2067b5f280 sys-proctable-sys-proctable-1.3.0/000077500000000000000000000000001435233620100170665ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/.github/000077500000000000000000000000001435233620100204265ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/.github/FUNDING.yml000066400000000000000000000001371435233620100222440ustar00rootroot00000000000000# These are supported funding model platforms github: djberg96 open_collective: daniel-berger sys-proctable-sys-proctable-1.3.0/.github/workflows/000077500000000000000000000000001435233620100224635ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/.github/workflows/ruby.yml000066400000000000000000000040751435233620100241750ustar00rootroot00000000000000# This workflow uses actions that are not certified by GitHub. # They are provided by a third-party and are governed by # separate terms of service, privacy policy, and support # documentation. # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby name: Ruby on: push: branches: [ main ] paths-ignore: - '**/*.md' pull_request: branches: [ main ] paths-ignore: - '**/*.md' workflow_dispatch: jobs: test: strategy: fail-fast: false matrix: ruby-version: [2.6, 2.7, 3.0, jruby] platform: [ubuntu-latest, macos-latest, windows-latest] exclude: - ruby-version: jruby platform: windows-latest - ruby-version: 3.0 platform: windows-latest runs-on: ${{ matrix.platform }} steps: - uses: actions/checkout@v2 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby-version }} bundler-cache: true # runs 'bundle install' and caches installed gems automatically - name: Run tests run: bundle exec rake # test_solaris: # runs-on: macos-12 # name: A job to run test in Solaris # steps: # - uses: actions/checkout@v2 # - name: test Solaris # id: test # uses: vmactions/solaris-vm@v0 # with: # usesh: true # prepare: | # # as far as i know latest possible version ist 2.6.x in Solaris 11.4 # pkgutil -y -i runtime/ruby-26 # ruby -v # gem install bundler # bundle install # # # # maybe use puppet to get new ruby (?) # # so we would get ruby 2.7.6p219 # # curl -JLO 'https://pm.puppetlabs.com/puppet-agent/2021.7.1/7.20.0/repos/solaris/11/puppet7/puppet-agent@7.20.0,5.11-1.i386.p5p' # # pkg install -g file://$(pwd)/puppet-agent\@7.20.0\,5.11-1.i386.p5p pkg:/puppet-agent # run: | # bundle exec rake sys-proctable-sys-proctable-1.3.0/.gitignore000066400000000000000000000000231435233620100210510ustar00rootroot00000000000000Gemfile.lock *.swp sys-proctable-sys-proctable-1.3.0/.rubocop.yml000066400000000000000000000027111435233620100213410ustar00rootroot00000000000000require: rubocop-rspec RSpec/BeforeAfterAll: Enabled: false RSpec/MultipleExpectations: Max: 4 RSpec/ContextWording: Enabled: false RSpec/FilePath: SpecSuffixOnly: true RSpec/InstanceVariable: Enabled: false AllCops: NewCops: enable Exclude: - sys-proctable.gemspec - Gemfile - Rakefile - examples/*.rb - benchmarks/*.rb Lint/AssignmentInCondition: Enabled: false Style/BlockDelimiters: Exclude: - spec/*.rb Lint/EmptyBlock: Exclude: - spec/*.rb Style/MethodCallWithoutArgsParentheses: Enabled: false Style/NumericLiterals: Enabled: false Style/NumericPredicate: Enabled: false Style/ClassAndModuleChildren: Enabled: false Style/ConditionalAssignment: Enabled: false Style/HashSyntax: EnforcedStyle: hash_rockets Style/IfUnlessModifier: Enabled: false Style/RedundantBegin: Enabled: false Style/SafeNavigation: Enabled: false Layout/EmptyLineAfterGuardClause: Enabled: false Layout/FirstArrayElementIndentation: Enabled: false Layout/CaseIndentation: IndentOneStep: true Layout/SpaceBeforeBlockBraces: Enabled: false Metrics/AbcSize: Enabled: false Metrics/BlockLength: IgnoredMethods: ['describe', 'context'] Metrics/ClassLength: Enabled: false Metrics/MethodLength: Enabled: false Metrics/CyclomaticComplexity: Enabled: false Metrics/PerceivedComplexity: Enabled: false Naming/RescuedExceptionsVariableName: PreferredName: 'err' Naming/FileName: Exclude: - 'lib/sys-proctable.rb' sys-proctable-sys-proctable-1.3.0/CHANGES.md000066400000000000000000000522331435233620100204650ustar00rootroot00000000000000## 1.3.0 - 26-Dec-2022 * Added DragonflyBSD support. * Reorganized the BSD code so that FreeBSD and Dragonfly BSD live in their own space for easier maintenance. ## 1.2.7 - 28-Oct-2022 * Fix bug on Solaris where it would fail trying to read zero-byte pseudo-kernel processes. Thanks go to Robert Waffen for the spot and the patch. * Fixed a bug for MacOS that potentially caused it to miss thread info. * Fixed specs for AIX that had gotten mangled when I switched to rspec * Some gemspec updates, including the addition of rubocop as a development dependency, and mandatory MFA. * Lots of rubocop related updates, mostly stylistic, but in some cases things that were always meant to be private (like C struct wrappers) have been explicitly marked as private. * Lots of general spec refactoring, including updates for MacOS since Catalina and later that no longer allow you to collect env information for spawned processes. * Switched to github actions. ## 1.2.6 - 25-Aug-2020 * Made some updates so that it worked properly with TruffleRuby on Mac. * Fixed an issue on Linux where non-ascii environ strings could cause failure. Thanks go to deemytch for the spot and original patch. * Removed the spec_helper.rb file, just use Process.spawn instead of messing around with custom fork implementations. This also helps with implementations that don't support fork. * Updated the MANIFEST. ## 1.2.5 - 19-Jun-2020 * Added the delayacct_blkio_ticks, guest_time, and cguest_time fields on Linux. These require 2.6.18 or later, but will simply be nil on earlier versions. * Added the rsslim synonym for the rlim field for Linux. ## 1.2.4 - 18-Jun-2020 * Added the num_threads field for Linux. This was originally a dead field in older versions of Linux that was skipped, but as of Linux 2.6+ it actually holds meaningful data. * Updated the specs for Linux. ## 1.2.3 - 17-Mar-2020 * Properly include a copy of Apache-2.0 in LICENSE file as part of library. * Add explicit .rdoc extensions to CHANGES and MANIFEST files. ## 1.2.2 - 12-Aug-2019 * Added compatibility for JRuby on Mac which apparently doesn't define a read_uint64 method, nor a CharArray. Thanks go to Adithya Pentela for the spot. * Refactored the specs a bit, adding a spec_helper.rb. This was mainly for JRuby compatibility. * Updates to the travis.yml file for both Ruby and JRuby versions. * Removed the doc directory and all the files it contained. It was redundant, and some of the information was wrong. All of the documentation you need is on the wiki. * Cleaned up the MANIFEST file, updated the gemspec, and fixed the license name, which was missing a hyphen. ## 1.2.1 - 8-Jun-2018 * The code for OSX is now more efficient when a pid argument is provided. Thanks go to Nick LaMuro for his efforts. * Added metadata to the gemspec. * Switched the README (now README.md) to markdown format. Thanks go to Tim Meusel for the update. * Updated the cert. Should be good for ten years now. ## 1.2.0 - 20-Feb-2018 * There has been an API change. The ProcTable.ps method now uses keyword arguments. The 'pid' option is universal, the rest depend on the platform. As part of this change, support for Ruby < 2.0 has been dropped. * Support for HP-UX has been dropped, both because it was the last remaining platform that still used C code, and because it's basically a dead platform. * There are no more platform-specific gems. There is now a single gem that will load the appropriate code based on your host's operating system. * The tests were switched from test-unit to rspec. * Lots of Rakefile updates based on the above changes. * The cert was updated. ## 1.1.5 - 10-Aug-2017 * Fixed a warning that cropped up in Ruby 2.4.x because I was type checking against Fixnum. Those have been replaced with Numeric. ## 1.1.4 - 30-Mar-2017 * Fixed a potential issue where OSX could return a struct with invalid data. * Set the default field to :pid for OSX when using Sys::Top. * Fixed a duplicate test warning for OSX. ## 1.1.3 - 28-Sep-2016 * Fixed an issue on OSX where the value returned for argc is invalid. ## 1.1.2 - 18-Sep-2016 * Fixed cmdline parsing and handling for OSX. Thanks go to Ben Mathwig for the spot and the patch. ## 1.1.1 - 30-Jun-2016 * Added thread information for OS X. * Fixed VERSION constant for HP-UX. ## 1.1.0 - 27-Jun-2016 * License was changed to Apache 2.0. * The OS X version now requires OS X 10.7 or later. * Scrapped the C implementation for OS X, and replaced it with a libproc wrapper using FFI, so it is now pure Ruby. Note that some new struct members have been added, while others have been dropped. This includes pctcpu, so Sys::Top does not work at the moment. * Rakefile updates to accomodate the changes for OS X. * Some test suite updates and refactoring. ## 1.0.0 - 11-Jan-2016 * Added smaps information for Linux. Thanks go to Joe Rafaniello for the patch. * This really should not have been a major release, sorry. ## 0.9.9 - 8-Nov-2015 * Added support for cgroups on Linux. Thanks go to Dennis Günnewig for the patch. * Added a sys-proctable.rb file for convenience. * This gem is now signed. * Gem related tasks in the Rakefile now assume Rubygems 2.x. ## 0.9.8 - 18-Apr-2015 * Fixed a bug in the gemspec. Last version got yanked. ## 0.9.7 - 18-Apr-2015 * Fixed a bug in the OSX code that could cause the ps method to fail. Thanks go to Koshevoy Anton for the spot. * Some internal refactoring of version handling. Now all platforms use a single version file. * Replaced vm_size_t and lwpid_t with universal data types on FreeBSD because FFI on FreeBSD 10 no longer understands them. Thanks go to Mike Owens for the spot. ## 0.9.6 - 24-Feb-2015 * Added NLWP field on Linux. Thanks go to Rich Chatterton for the patch. ## 0.9.5 - 10-Feb-2015 * Significant cleanup and memory reduction of the OSX code. Thanks go to Ivan (toy) for the patches. * Skip over /proc//status if unreadable on Linux. Thanks go to Jianjun Mao for the patch. ## 0.9.4 - 4-Mar-2014 * Added support for AIX 5.3 or later courtesy of Rick Ohnemus. * The Solaris version now uses FFI structs instead of a packed array. It solved issues with 64-bit versions of Ruby and it's self-documenting. * The FreeBSD version has been converted to use FFI. In addition, additional struct members have been added, and members that previously returned nil now return meaningful data. * Support for NetBSD and OpenBSD has been temporarily dropped. Considering that the C code did not build on those platforms anyway, I doubt most of you will notice. Patches for those platforms are welcome, but only using FFI. ## 0.9.3 - 17-Mar-2013 * Fixed a bug on OSX where a long command string arg could cause a segfault. Thanks go to Nathaniel Bibler for the spot. * Changed the gem platform from mingw to mingw32 for Windows. ## 0.9.2 - 8-Oct-2012 * Added cmdline support for OS X. Thanks go to Matthias Zirnstein for the patch. * Warning cleanup for 1.9. * Updated the gem platform handling. Replaced the borked string approach with a two element array for Gem::Platform.new. * MS date strings are now parse with DateTime instead of Date. ## 0.9.1 - 3-Aug-2011 * Added the pctcpu and pctmem members for Linux. * Added Errno::ESRCH to a rescue clause on Linux that fixed a bug where a missing entry wasn't being skipped when run as root. Thanks go to Austin Ziegler for the spot and patch. * Fixed a build warning for Darwin. * Updates to the test suite for both Darwin and Linux. * Added an explicit type check for BSD for pids. * Added nicer error messages for BSD if kvm_open fails. * Added .core files to the clean task. * Altered the platform settings in the Rakefile so that generated gems use 'universal' platform architectures for any particular operating system. ## 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 ' 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. sys-proctable-sys-proctable-1.3.0/Gemfile000066400000000000000000000000461435233620100203610ustar00rootroot00000000000000source 'https://rubygems.org' gemspec sys-proctable-sys-proctable-1.3.0/LICENSE000066400000000000000000000236761435233620100201110ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS sys-proctable-sys-proctable-1.3.0/MANIFEST.md000066400000000000000000000020651435233620100206210ustar00rootroot00000000000000* CHANGES * LICENSE * MANIFEST * Rakefile * README * sys-proctable.gemspec * benchmarks/bench_ps.rb * benchmarks/bench_ips_ps.rb * example/example_ps.rb * lib/sys-proctable.rb * lib/sys-top.rb * lib/sys/proctable.rb * lib/sys/top.rb * lib/sys/proctable/version.rb * lib/aix/sys/proctable.rb * lib/darwin/sys/proctable.rb * lib/bsd/sys/dragonfly/sys/proctable.rb * lib/bsd/sys/dragonfly/sys/proctable/constants.rb * lib/bsd/sys/dragonfly/sys/proctable/functions.rb * lib/bsd/sys/dragonfly/sys/proctable/structs.rb * lib/bsd/sys/freebsd/sys/proctable.rb * lib/bsd/sys/freebsd/sys/proctable/constants.rb * lib/bsd/sys/freebsd/sys/proctable/functions.rb * lib/bsd/sys/freebsd/sys/proctable/structs.rb * lib/linux/sys/proctable.rb * lib/sunos/sys/proctable.rb * lib/windows/sys/proctable.rb * spec/spec_helper.rb * spec/sys_proctable_aix_spec.rb * spec/sys_proctable_all_spec.rb * spec/sys_proctable_darwin_spec.rb * spec/sys_proctable_freebsd_spec.rb * spec/sys_proctable_linux_spec.rb * spec/sys_proctable_sunos_spec.rb * spec/sys_proctable_windows_spec.rb * spec/sys_top_spec.rb sys-proctable-sys-proctable-1.3.0/README.md000066400000000000000000000075111435233620100203510ustar00rootroot00000000000000[![Ruby](https://github.com/djberg96/sys-proctable/actions/workflows/ruby.yml/badge.svg)](https://github.com/djberg96/sys-proctable/actions/workflows/ruby.yml) # sys-proctable ## Description A Ruby interface for gathering process information. ## Prerequisites * ffi * rspec (development only) * rake (development only) * rubocop (development only) ## Supported Platforms * Windows 2000 or later * Linux 2.6+ * FreeBSD * DragonflyBSD * Solaris 8+ * OS X 10.7+ * AIX 5.3+ ## Installation ```sh gem install sys-proctable ``` For version 1.1.5 or earlier, you may need to specify a platform in some cases. For example: ```sh gem install sys-proctable --platform mswin32 # Windows gem install sys-proctable --platform sunos # Solaris gem install sys-proctable --platform linux # Linux gem install sys-proctable --platform freebsd # FreeBSD gem install sys-proctable --platform darwin # OS X ``` ## Synopsis ```ruby require 'sys/proctable' include Sys # Everything ProcTable.ps{ |p| puts p.pid.to_s puts p.comm # ... } # Just one process s = ProcTable.ps(pid: 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 p.pid # ... end ``` ## Notes Various platforms support different options. Mostly this is to let you skip the collection of certain bits of information in order to improve speed and/or reduce memory. For example on Linux you can do this to skip the collection of smaps information: ```ruby Sys::ProcTable.ps(smaps: false) ``` Windows users may send a host name to get process information from a different host. This relies on the WMI service running. ```ruby Sys::ProcTable.ps(host: some_host) ``` ## Known Issues ### FreeBSD 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). ### Bundler For version 1.1.5 or earlier, Bundler seems to have trouble installing the proper gem because of the platform specific gem names. To deal with that, run this command first: ```sh bundle config specific_platform true ``` You should not have to do this for version 1.2.0 or later. ### 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 The libproc interface is used. That means you will only get list of processes that you have access to. To get a full listing, run as root. ## Future Plans Support for Solaris will probably be dropped in the next major release. ## Acknowledgements This library was originally 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. Thanks also go to Matthias Zirnstein for adding the original cmdline support for OS X. 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 Apache-2.0 ## Copyright (C) 2003-2022 Daniel J. Berger All Rights Reserved. ## Author Daniel J. Berger sys-proctable-sys-proctable-1.3.0/Rakefile000066400000000000000000000051071435233620100205360ustar00rootroot00000000000000require 'rake' require 'rake/clean' require 'rake/testtask' require 'rbconfig' require 'rspec/core/rake_task' require 'rubocop/rake_task' include RbConfig CLEAN.include('**/*.gem', '**/*.rbc', '**/*.lock') RuboCop::RakeTask.new desc 'Install the sys-proctable library' task :install do file = nil dir = File.join(CONFIG['sitelibdir'], 'sys') Dir.mkdir(dir) unless File.exists?(dir) case CONFIG['host_os'] when /mswin|win32|msdos|cygwin|mingw|windows/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 /aix/i file = 'lib/aix/sys/proctable.rb' when /freebsd/i file = 'lib/freebsd/sys/proctable.rb' when /darwin/i file = 'lib/darwin/sys/proctable.rb' end cp(file, dir, :verbose => true) if file end desc 'Uninstall the sys-proctable library' task :uninstall do dir = File.join(CONFIG['sitelibdir'], 'sys') file = File.join(dir, 'proctable.rb') rm(file) end desc 'Run the benchmark suite' task :bench do sh "ruby -Ilib benchmarks/bench_ps.rb" end desc 'Run the example program' task :example do sh 'ruby -Ilib -Iext examples/example_ps.rb' end desc 'Run the test suite for the sys-proctable library' RSpec::Core::RakeTask.new(:spec) do |t| t.pattern = ['spec/sys_proctable_all_spec.rb', 'spec/sys_top_spec.rb'] case CONFIG['host_os'] when /aix/i t.rspec_opts = '-Ilib/aix' t.pattern << 'spec/sys_proctable_aix.rb' when /darwin/i t.rspec_opts = '-Ilib/darwin' t.pattern << 'spec/sys_proctable_darwin_spec.rb' when /bsd|dragonfly/i t.rspec_opts = '-Ilib/bsd' t.pattern << 'spec/sys_proctable_bsd_spec.rb' when /linux/i t.rspec_opts = '-Ilib/linux' t.pattern << 'spec/sys_proctable_linux_spec.rb' when /sunos|solaris/i t.rspec_opts = '-Ilib/sunos' t.pattern << 'spec/sys_proctable_sunos_spec.rb' when /mswin|msdos|cygwin|mingw|windows/i t.rspec_opts = '-Ilib/windows' t.pattern << 'spec/sys_proctable_windows_spec.rb' end end namespace :gem do desc 'Create a gem for the specified OS, or your current OS by default' task :create => [:clean] do require 'rubygems/package' spec = Gem::Specification.load('sys-proctable.gemspec') spec.signing_key = File.join(Dir.home, '.ssh', 'gem-private_key.pem') Gem::Package.build(spec) end desc 'Install the sys-proctable library as a gem' task :install => [:create] do gem_name = Dir['*.gem'].first sh "gem install -l #{gem_name}" end end task :default => :spec sys-proctable-sys-proctable-1.3.0/benchmarks/000077500000000000000000000000001435233620100212035ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/benchmarks/bench_ips_ps.rb000077500000000000000000000033471435233620100241760ustar00rootroot00000000000000#!/usr/bin/env ruby require 'json' require 'optparse' require 'rbconfig' require 'benchmark/ips' @source, @gem = false OptionParser.new do |opt| opt.banner = "Usage: #{File.basename $0} [--gem|--source]" opt.separator "" opt.separator "Benchmark IPS (iterations per second) changes between" opt.separator "source version of sys-proctable and previous gem" opt.separator "version." opt.separator "" opt.separator "Requires that the both the source version of the gem" opt.separator "be installed (run `rake install` to do this after" opt.separator "each of your changes) and version installed via" opt.separator "rubygems." opt.separator "" opt.separator "To run, call with `--gem` two times, and then with " opt.separator "`--source` two times again." opt.separator "" opt.on("--source") { @source = true } opt.on("--gem") { @gem = true } end.parse! if @source && !@gem # Being paranoid here and making sure we get the version installed to # sitelibdir require File.join(RbConfig::CONFIG["sitelibdir"], "sys", "proctable") else @gem = true require 'sys-proctable' end Benchmark.ips do |bench| bench.report("Block form - pre patch") do (puts "ERR: Please run with --gem"; exit 1) unless @gem Sys::ProcTable.ps {} end bench.report("Non-block form - pre patch") do (puts "ERR: Please run with --gem"; exit 1) unless @gem Sys::ProcTable.ps end bench.report("Block form - post patch") do (puts "ERR: Please run with --source"; exit 1) unless @source Sys::ProcTable.ps {} end bench.report("Non-block form - post patch") do (puts "ERR: Please run with --source"; exit 1) unless @source Sys::ProcTable.ps end bench.hold! "bench_ips_ps.results" bench.compare! end sys-proctable-sys-proctable-1.3.0/benchmarks/bench_ps.rb000066400000000000000000000010601435233620100233060ustar00rootroot00000000000000######################################################################## # 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 sys-proctable-sys-proctable-1.3.0/certs/000077500000000000000000000000001435233620100202065ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/certs/djberg96_pub.pem000066400000000000000000000030761435233620100232010ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEcDCCAtigAwIBAgIBATANBgkqhkiG9w0BAQsFADA/MREwDwYDVQQDDAhkamJl cmc5NjEVMBMGCgmSJomT8ixkARkWBWdtYWlsMRMwEQYKCZImiZPyLGQBGRYDY29t MB4XDTE4MDMxODE1MjIwN1oXDTI4MDMxNTE1MjIwN1owPzERMA8GA1UEAwwIZGpi ZXJnOTYxFTATBgoJkiaJk/IsZAEZFgVnbWFpbDETMBEGCgmSJomT8ixkARkWA2Nv bTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALgfaroVM6CI06cxr0/h A+j+pc8fgpRgBVmHFaFunq28GPC3IvW7Nvc3Y8SnAW7pP1EQIbhlwRIaQzJ93/yj u95KpkP7tA9erypnV7dpzBkzNlX14ACaFD/6pHoXoe2ltBxk3CCyyzx70mTqJpph 75IB03ni9a8yqn8pmse+s83bFJOAqddSj009sGPcQO+QOWiNxqYv1n5EHcvj2ebO 6hN7YTmhx7aSia4qL/quc4DlIaGMWoAhvML7u1fmo53CYxkKskfN8MOecq2vfEmL iLu+SsVVEAufMDDFMXMJlvDsviolUSGMSNRTujkyCcJoXKYYxZSNtIiyd9etI0X3 ctu0uhrFyrMZXCedutvXNjUolD5r9KGBFSWH1R9u2I3n3SAyFF2yzv/7idQHLJJq 74BMnx0FIq6fCpu5slAipvxZ3ZkZpEXZFr3cIBtO1gFvQWW7E/Y3ijliWJS1GQFq 058qERadHGu1yu1dojmFRo6W2KZvY9al2yIlbkpDrD5MYQIDAQABo3cwdTAJBgNV HRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUFZsMapgzJimzsbaBG2Tm8j5e AzgwHQYDVR0RBBYwFIESZGpiZXJnOTZAZ21haWwuY29tMB0GA1UdEgQWMBSBEmRq YmVyZzk2QGdtYWlsLmNvbTANBgkqhkiG9w0BAQsFAAOCAYEAW2tnYixXQtKxgGXq /3iSWG2bLwvxS4go3srO+aRXZHrFUMlJ5W0mCxl03aazxxKTsVVpZD8QZxvK91OQ h9zr9JBYqCLcCVbr8SkmYCi/laxIZxsNE5YI8cC8vvlLI7AMgSfPSnn/Epq1GjGY 6L1iRcEDtanGCIvjqlCXO9+BmsnCfEVehqZkQHeYczA03tpOWb6pon2wzvMKSsKH ks0ApVdstSLz1kzzAqem/uHdG9FyXdbTAwH1G4ZPv69sQAFAOCgAqYmdnzedsQtE 1LQfaQrx0twO+CZJPcRLEESjq8ScQxWRRkfuh2VeR7cEU7L7KqT10mtUwrvw7APf DYoeCY9KyjIBjQXfbj2ke5u1hZj94Fsq9FfbEQg8ygCgwThnmkTrrKEiMSs3alYR ORVCZpRuCPpmC8qmqxUnARDArzucjaclkxjLWvCVHeFa9UP7K3Nl9oTjJNv+7/jM WZs4eecIcUc4tKdHxcAJ0MO/Dkqq7hGaiHpwKY76wQ1+8xAh -----END CERTIFICATE----- sys-proctable-sys-proctable-1.3.0/examples/000077500000000000000000000000001435233620100207045ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/examples/example_ps.rb000066400000000000000000000007771435233620100234010ustar00rootroot00000000000000####################################################################### # 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 } sys-proctable-sys-proctable-1.3.0/lib/000077500000000000000000000000001435233620100176345ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/aix/000077500000000000000000000000001435233620100204155ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/aix/sys/000077500000000000000000000000001435233620100212335ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/aix/sys/proctable.rb000066400000000000000000000353251435233620100235430ustar00rootroot00000000000000####################################################################### # proctable.rb # # A pure Ruby version of sys-proctable for AIX 5.3 or later. ######################################################################## require 'sys/proctable/version' # 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 private @fields = [ # --- psinfo_t --- :flag, # process flags from proc struct p_flag :flag2, # process flags from proc struct p_flag2 :nlwp, # number of threads in process #:pad1, # reserved for future use :uid, # real user id :euid, # effective user id :gid, # real group id :egid, # effective group id :pid, # unique process id :ppid, # process id of parent :pgid, # pid of process group leader :sid, # session id :ttydev, # controlling tty device (device #) :s_ttydev, # controlling tty device name or '-' :addr, # internal address of proc struct :size, # process image size in KB (1024) units :rssize, # resident set size in KB (1024) units :start, # process start time, time since epoch :time, # usr+sys cpu time for this process :cid, # corral id #:pad2, # reserved for future use :argc, # initial argument count :argv, # address of initial argument vector in user process :envp, # address of initial environment vector in user process :fname, # last component of exec()ed pathname :psargs, # initial characters of arg list #:pad, # reserved for future use # --- lwpsinfo_t --- :lwpid, # thread id #:addr, # internal address of thread :wchan, # wait addr for sleeping thread #:flag, # thread flags :wtype, # type of thread wait :state, # thread state :sname, # printable thread state character :nice, # nice for cpu usage :pri, # priority, high value = high priority :policy, # scheduling policy :clname, # printable scheduling policy string :onpro, # processor on which thread last ran :bindpro, # processor to which thread is bound :ptid, # pthread id #:pad1, # reserved for future use #:pad, # reserved for future use # --- prmap_t --- :map, # array of prmap_t structures # --- lwp --- #:lwp # array of lwp information # other... :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 :cwd, # current working directory ] @psinfo_pack_directive = [ 'L', # pr_flag 'L', # pr_flag2 'L', # pr_nlwp 'L', # pr__pad1 'Q', # pr_uid 'Q', # pr_euid 'Q', # pr_gid 'Q', # pr_egid 'Q', # pr_pid 'Q', # pr_ppid 'Q', # pr_pgid 'Q', # pr_sid 'Q', # pr_ttydev 'Q', # pr_addr 'Q', # pr_size 'Q', # pr_rssize 'QlL', # pr_start 'QlL', # pr_time 'S', # pr_cid 'S', # pr__pad2 'L', # pr_argc 'Q', # pr_argv 'Q', # pr_envp 'A16', # pr_fname[PRFNSZ] 'A80', # pr_psargs[PRARGSZ] 'Q8', # pr__pad[8] # --- lwpsinfo_t --- pr_lwp 'Q', # pr_lwpid 'Q', # pr_addr 'Q', # pr_wchan 'L', # pr_flag 'C', # pr_wtype 'c', # pr_state 'A', # pr_sname 'C', # pr_nice 'l', # pr_pri 'L', # pr_policy 'A8', # pr_clname 'l', # pr_onpro 'l', # pr_bindpro 'L', # pr_ptid 'L', # pr__pad1 'Q7' # pr__pad[7] ].join # --- prmap_t --- @map_fields = [ :size, :vaddr, :mapname, :off, :mflags, :s_mflags, :pathoff, :alias, :gp, #:pad, :path, ] @prmap_pack_directive = [ 'Q', # pr_size 'Q', # pr_vaddr 'A64', # pr_mapname[PRMAPSZ] 'Q', # pr_off 'L', # pr_mflags 'L', # pr_pathoff 'Q', # pr_alias 'Q', # pr_gp 'Q8', # pr__pad[8] ].join # prmap_t pr_mflags PR_MFLAGS = [ [ 0x80000000, 'main' ], # MA_MAINEXEC - main executable [ 0x40000000, 'kernel' ], # MA_KERNTEXT - kernel text [ 0x00000004, 'read' ], # MA_READ - readable [ 0x00000002, 'write' ], # MA_WRITE - writable [ 0x00000001, 'exec' ], # MA_EXEC - executable [ 0x00000008, 'shared' ], # MA_SHARED - shared memory region [ 0x00000010, 'heap' ], # MA_BREAK - heap -- grown by brk [ 0x00000020, 'stack' ], # MA_STACK - stack -- grows on stack faults ] @devs = {} Dir['/dev/**/*'].map do |filename| begin rdev = File.stat(filename).rdev rescue next end @devs[rdev] = filename[5..-1] if rdev.nonzero? end public ProcTableStruct = Struct.new("ProcTableStruct", *@fields) do alias comm fname end ProcTableMapStruct = Struct.new("ProcTableMapStruct", *@map_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(pid: 1001) # def self.ps(**kwargs) pid = kwargs[:pid] raise TypeError unless pid.is_a?(Numeric) if pid array = block_given? ? nil : [] struct = nil Dir.foreach("/proc") do |file| next if file =~ /\D/ # Skip non-numeric entries under /proc # Only return information for a given pid, if provided if pid next unless file.to_i == pid end # Skip over any entries we don't have permissions to read next unless File.readable?("/proc/#{file}/psinfo") psinfo = IO.read("/proc/#{file}/psinfo") rescue next psinfo_array = psinfo.unpack(@psinfo_pack_directive) struct = ProcTableStruct.new struct.flag = psinfo_array[0] # pr_flag struct.flag2 = psinfo_array[1] # pr_flag2 struct.nlwp = psinfo_array[2] # pr_nlwp # pr__pad1 struct.uid = psinfo_array[4] # pr_uid struct.euid = psinfo_array[5] # pr_euid struct.gid = psinfo_array[6] # pr_gid struct.egid = psinfo_array[7] # pr_egid struct.pid = psinfo_array[8] # pr_pid struct.ppid = psinfo_array[9] # pr_ppid struct.pgid = psinfo_array[10] # pr_pgid struct.sid = psinfo_array[11] # pr_sid struct.ttydev = psinfo_array[12] # pr_ttydev # convert from 64-bit dev_t to 32-bit dev_t and then map the device # number to a name ttydev = struct.ttydev ttydev = (((ttydev & 0x0000FFFF00000000) >> 16) | (ttydev & 0xFFFF)) struct.s_ttydev = @devs.has_key?(ttydev) ? @devs[ttydev] : '-' struct.addr = psinfo_array[13] # pr_addr struct.size = psinfo_array[14] * 1024 # pr_size struct.rssize = psinfo_array[15] * 1024 # pr_rssize struct.start = Time.at(psinfo_array[16], psinfo_array[17]) # pr_start # skip pr_start.__pad struct.time = psinfo_array[19] # pr_time # skip pr_time.tv_nsec and pr_time.__pad struct.cid = psinfo_array[22] # pr_cid # skip pr__pad2 struct.argc = psinfo_array[24] # pr_argc struct.argv = psinfo_array[25] # pr_argv struct.envp = psinfo_array[26] # pr_envp struct.fname = psinfo_array[27] # pr_fname struct.psargs = psinfo_array[28] # pr_psargs # skip pr__pad ### lwpsinfo_t info struct.lwpid = psinfo_array[37] # pr_lwpid # skip pr_addr struct.wchan = psinfo_array[39] # pr_wchan # skip pr_flag struct.wtype = psinfo_array[41] # pr_wtype struct.state = psinfo_array[42] # pr_state struct.sname = psinfo_array[43] # pr_sname struct.nice = psinfo_array[44] # pr_nice struct.pri = psinfo_array[45] # pr_pri struct.policy = psinfo_array[46] # pr_policy struct.clname = psinfo_array[47] # pr_clname struct.onpro = psinfo_array[48] # pr_onpro struct.bindpro = psinfo_array[49] # pr_bindpro struct.ptid = psinfo_array[50] # pr_ptid # skip pr__pad1 # skip pr__pad # Get the full command line out of /proc//as. begin File.open("/proc/#{file}/as", 'rb') do |fd| np = fd.sysseek(struct.argv, IO::SEEK_SET) if np != struct.argv raise Error, "argv seek to #{struct.argv}, result #{np}", caller end argv = fd.sysread(4).unpack('L')[0] np = fd.sysseek(argv, IO::SEEK_SET) if np != argv raise Error, "*argv seek to #{argv}, result #{np}", caller end argv = fd.sysread(4 * struct.argc).unpack("L#{struct.argc}") struct.cmd_args = [] argv.each_with_index do |address, i| np = fd.sysseek(address, IO::SEEK_SET) if np != address raise Error, "argv[#{i}] seek to #{address}, result #{np}", caller end data = fd.sysread(512)[/^[^\0]*/] # Null strip struct.cmd_args << data end # Get the environment hash associated with the process. struct.environ = {} # First have to go to the address given by struct.envp. That will # give us the address of the environment pointer array. np = fd.sysseek(struct.envp, IO::SEEK_SET) if np != struct.envp raise Error, "envp seek to #{struct.envp}, result #{np}", caller end envloc = fd.sysread(4).unpack('L')[0] n = 0 loop do np = fd.sysseek(envloc, IO::SEEK_SET) if np != envloc raise Error, "envp[#{n}] seek to #{envloc}, result #{np}", caller end envp = fd.sysread(4).unpack("L")[0] break if envp.zero? np = fd.sysseek(envp, IO::SEEK_SET) data = fd.sysread(1024)[/^[^\0]*/] # Null strip key, value = data.split('=') struct.environ[key] = value envloc += 4 n += 1 end end rescue Errno::EACCES, Errno::EOVERFLOW, EOFError # Skip this if we don't have proper permissions, if there's # no associated environment, or if there's a largefile issue. rescue Errno::ENOENT next # The process has terminated. Bail out! end # Information from /proc//fd. This returns an array of # numeric file descriptors used by the process. struct.fd = Dir["/proc/#{file}/fd/*"].map { |f| File.basename(f).to_i } # Use the cmd_args as the cmdline if available. Otherwise use # the psargs. This struct member is provided to provide a measure # of consistency with the other platform implementations. if struct.cmd_args.nil? || struct.cmd_args.empty? struct.cmdline = struct.psargs else struct.cmdline = struct.cmd_args.join(' ') end # get current working directory from /proc//cwd struct.cwd = File.readlink("/proc/#{file}/cwd") rescue nil # get virtual address map from /proc//map begin struct.map = [] File.open("/proc/#{file}/map", 'rb') do |fd| loop do prmap_array = fd.sysread(176).unpack(@prmap_pack_directive) break if prmap_array[0].zero? map_struct = ProcTableMapStruct.new map_struct.size = prmap_array[0] # pr_size map_struct.vaddr = prmap_array[1] # pr_vaddr map_struct.mapname = prmap_array[2] # pr_mapname map_struct.off = prmap_array[3] # pr_off map_struct.mflags = prmap_array[4] # pr_mflags # convert pr_mflags value to string sort of like procmap outputs mflags = map_struct.mflags map_struct.s_mflags = '' sep = '' PR_MFLAGS.each do |flag| if (mflags & flag[0]).nonzero? map_struct.s_mflags << sep << flag[1] sep = '/' mflags &= ~flag[0] end end if mflags.nonzero? map_struct.s_mflags << sep << sprintf('%08x', mflags) end map_struct.pathoff = prmap_array[5] # pr_pathoff map_struct.alias = prmap_array[6] # pr_alias map_struct.gp = prmap_array[7] # pr_gp struct.map << map_struct end struct.map.each do |m| next if m.pathoff.zero? fd.sysseek(m.pathoff, IO::SEEK_SET) buf = fd.sysread(4096) buf =~ /^([^\0]*)\0([^\0]*)\0/ m.path = $2.empty? ? $1 : "#{$1}(#{$2})" end end struct.map = nil if struct.map.empty? rescue struct.map = nil end # This is read-only data struct.freeze if block_given? yield struct else array << struct end 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 do |field| # puts "Field: #{field}" # end # def self.fields @fields.map{ |f| f.to_s } end end end sys-proctable-sys-proctable-1.3.0/lib/bsd/000077500000000000000000000000001435233620100204045ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/000077500000000000000000000000001435233620100212225ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/dragonfly/000077500000000000000000000000001435233620100232075ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/dragonfly/sys/000077500000000000000000000000001435233620100240255ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/dragonfly/sys/proctable.rb000066400000000000000000000113151435233620100263260ustar00rootroot00000000000000require_relative 'proctable/constants' require_relative 'proctable/structs' require_relative 'proctable/functions' require 'sys/proctable/version' module Sys class ProcTable include Sys::ProcTableConstants include Sys::ProcTableStructs extend Sys::ProcTableFunctions # Error typically raised if the ProcTable.ps method fails. class Error < StandardError; end # There is no constructor private_class_method :new @fields = %w[ paddr flags stat lock acflag traceflag fd siglist sigignore sigcatch sigflag start comm uid ngroups groups ruid svuid rgid svgid pid ppid pgid jobc sid login tdev tpgid tsid exitstat nthreads nice swtime vm_map_size vm_rssize vm_swrss vm_tsize vm_dsize vm_ssize vm_prssize jailid ru cru auxflags lwp ktaddr ] ProcTableStruct = Struct.new('ProcTableStruct', *@fields) do alias cmdline comm end # 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(pid: 1001) # def self.ps(**kwargs) pid = kwargs[:pid] begin kd = kvm_open(nil, nil, nil, 0, nil) if kd.null? raise SystemCallError.new('kvm_open', FFI.errno) end ptr = FFI::MemoryPointer.new(:int) # count if pid procs = kvm_getprocs(kd, KERN_PROC_PID, pid, ptr) else procs = kvm_getprocs(kd, KERN_PROC_ALL, 0, ptr) end if procs.null? if pid && FFI.errno == Errno::ESRCH::Errno return nil else raise SystemCallError.new('kvm_getprocs', FFI.errno) end end count = ptr.read_int array = [] 0.upto(count-1){ |i| cmd = nil kinfo = KInfoProc.new(procs[i * KInfoProc.size]) args = kvm_getargv(kd, kinfo, 0) unless args.null? cmd = [] until ((ptr = args.read_pointer).null?) cmd << ptr.read_string args += FFI::Type::POINTER.size end cmd = cmd.join(' ') end struct = ProcTableStruct.new( kinfo[:kp_paddr], kinfo[:kp_flags], kinfo[:kp_stat], kinfo[:kp_lock], kinfo[:kp_acflag], kinfo[:kp_traceflag], kinfo[:kp_fd], kinfo[:kp_siglist].bits, kinfo[:kp_sigignore].bits, kinfo[:kp_sigcatch].bits, kinfo[:kp_sigflag], Time.at(kinfo[:kp_start][:tv_sec]), kinfo[:kp_comm].to_s, kinfo[:kp_uid], kinfo[:kp_ngroups], kinfo[:kp_groups].to_a[0..kinfo[:kp_ngroups]-1], kinfo[:kp_ruid], kinfo[:kp_svuid], kinfo[:kp_rgid], kinfo[:kp_svgid], kinfo[:kp_pid], kinfo[:kp_ppid], kinfo[:kp_pgid], kinfo[:kp_jobc], kinfo[:kp_sid], kinfo[:kp_login].to_s, kinfo[:kp_tdev], kinfo[:kp_tpgid], kinfo[:kp_tsid], kinfo[:kp_exitstat], kinfo[:kp_nthreads], kinfo[:kp_nice], kinfo[:kp_swtime], kinfo[:kp_vm_map_size], kinfo[:kp_vm_rssize], kinfo[:kp_vm_swrss], kinfo[:kp_vm_tsize], kinfo[:kp_vm_dsize], kinfo[:kp_vm_ssize], kinfo[:kp_vm_prssize], kinfo[:kp_jailid], kinfo[:kp_ru], kinfo[:kp_cru], kinfo[:kp_auxflags], kinfo[:kp_lwp], kinfo[:kp_ktaddr], ) struct.freeze # This is readonly data if block_given? yield struct else array << struct end } ensure kvm_close(kd) unless kd.null? end if block_given? nil else pid ? array.first : array end 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 sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/dragonfly/sys/proctable/000077500000000000000000000000001435233620100260005ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/dragonfly/sys/proctable/constants.rb000066400000000000000000000002551435233620100303430ustar00rootroot00000000000000module Sys module ProcTableConstants WMESGLEN = 8 MAXCOMLEN = 16 NGROUPS = 16 MAXLOGNAME = 33 KERN_PROC_ALL = 0 KERN_PROC_PID = 1 end end sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/dragonfly/sys/proctable/functions.rb000066400000000000000000000006751435233620100303450ustar00rootroot00000000000000require 'ffi' module Sys module ProcTableFunctions extend FFI::Library ffi_lib :kvm attach_function :devname, [:dev_t, :mode_t], :string attach_function :kvm_open, [:string, :string, :string, :int, :string], :pointer attach_function :kvm_close, [:pointer], :int attach_function :kvm_getprocs, [:pointer, :int, :int, :pointer], :pointer attach_function :kvm_getargv, [:pointer, :pointer, :int], :pointer end end sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/dragonfly/sys/proctable/structs.rb000066400000000000000000000126271435233620100300440ustar00rootroot00000000000000require 'ffi' require_relative 'constants' module Sys module ProcTableStructs extend FFI::Library class Timeval < FFI::Struct layout(:tv_sec, :time_t, :tv_usec, :suseconds_t) end class RTPrio < FFI::Struct layout(:type, :ushort, :prio, :ushort) end class Rusage < FFI::Struct layout( :ru_utime, Timeval, :ru_stime, Timeval, :ru_maxrss, :long, :ru_ixrss, :long, :ru_idrss, :long, :ru_isrss, :long, :ru_minflt, :long, :ru_majflt, :long, :ru_nswap, :long, :ru_inblock, :long, :ru_oublock, :long, :ru_msgsnd, :long, :ru_msgrcv, :long, :ru_nsignals, :long, :ru_nvcsw, :long, :ru_nivcsw, :long ) def utime Time.at(self[:ru_utime][:tv_sec]) end def stime Time.at(self[:ru_stime][:tv_sec]) end def maxrss self[:ru_maxrss] end def ixrss self[:ru_ixrss] end def idrss self[:ru_idrss] end def isrss self[:ru_isrss] end def minflt self[:ru_minflt] end def majflt self[:ru_majflt] end def nswap self[:ru_nswap] end def inblock self[:ru_inblock] end def oublock self[:ru_oublock] end def msgsnd self[:ru_msgsnd] end def msgrcv self[:ru_msgrcv] end def nsignals self[:ru_nsignals] end def nvcsw self[:ru_nivcsw] end def nivcsw self[:ru_nivcsw] end end enum :lwpstat, [:LSRUN, 1, :LSSTOP, :LSSLEEP] enum :procstat, [:SIDL, 1, :SACTIVE, :SSTOP, :SZOMB, :SCORE] class Sigset < FFI::Struct layout(:__bits, [:uint, 4]) def bits self[:__bits].to_a end end class KInfoLWP < FFI::Struct include Sys::ProcTableConstants layout( :kl_pid, :pid_t, :kl_tid, :lwpid_t, :kl_flags, :int, :kl_stat, :lwpstat, :kl_lock, :int, :kl_tdflags, :int, :kl_mpcount, :int, :kl_prio, :int, :kl_tdprio, :int, :kl_rtprio, RTPrio, :kl_uticks, :uint64_t, :kl_sticks, :uint64_t, :kl_iticks, :uint64_t, :kl_cpticks, :uint64_t, :kl_pctcpu, :uint, :kl_slptime, :uint, :kl_origcpu, :int, :kl_estcpu, :int, :kl_cpuid, :int, :kl_ru, Rusage, :kl_siglist, Sigset, :kl_sigmask, Sigset, :kl_wchan, :uintptr_t, :kl_wmesg, [:char, WMESGLEN+1], :kl_comm, [:char, MAXCOMLEN+1] ) def pid self[:kl_pid] end def tid self[:kl_tid] end def flags self[:kl_flags] end def stat self[:kl_stat] end def lock self[:kl_lock] end def tdflags self[:kl_tdflags] end def prio self[:kl_prio] end def tdprio self[:kl_tdprio] end def rtprio self[:kl_rtprio] end def uticks self[:kl_uticks] end def sticks self[:kl_sticks] end def iticks self[:kl_iticks] end def cpticks self[:kl_cpticks] end def pctcpu self[:kl_pctcpu] end def slptime self[:kl_slptime] end def origcpu self[:kl_origcpu] end def estcpu self[:kl_estcpu] end def cpuid self[:kl_cpuid] end def ru self[:kl_ru] end def siglist self[:kl_siglist] end def sigmask self[:kl_sigmask] end def wchan self[:kl_wchan] end def wmesg self[:kl_wmesg].to_s end def comm self[:kl_comm].to_s end end class KInfoProc < FFI::Struct include Sys::ProcTableConstants def self.roundup(x, y) ((x + y-1) / y) * y end layout( :kp_paddr, :uintptr_t, :kp_flags, :int, :kp_stat, :procstat, :kp_lock, :int, :kp_acflag, :int, :kp_traceflag, :int, :kp_fd, :uintptr_t, :kp_siglist, Sigset, :kp_sigignore, Sigset, :kp_sigcatch, Sigset, :kp_sigflag, :int, :kp_start, Timeval, :kp_comm, [:char, MAXCOMLEN+1], :kp_uid, :uid_t, :kp_ngroups, :short, :kp_groups, [:gid_t, NGROUPS], :kp_ruid, :uid_t, :kp_svuid, :uid_t, :kp_rgid, :gid_t, :kp_svgid, :gid_t, :kp_pid, :pid_t, :kp_ppid, :pid_t, :kp_pgid, :pid_t, :kp_jobc, :int, :kp_sid, :pid_t, :kp_login, [:char, roundup(MAXLOGNAME, FFI::Type::LONG.size)], :kp_tdev, :dev_t, :kp_tpgid, :pid_t, :kp_tsid, :pid_t, :kp_exitstat, :ushort, :kp_nthreads, :int, :kp_nice, :int, :kp_swtime, :uint, :kp_vm_map_size, :size_t, :kp_vm_rssize, :segsz_t, :kp_vm_swrss, :segsz_t, :kp_vm_tsize, :segsz_t, :kp_vm_dsize, :segsz_t, :kp_vm_ssize, :segsz_t, :kp_vm_prssize, :uint, :kp_jailid, :int, :kp_ru, Rusage, :kp_cru, Rusage, :kp_auxflags, :int, :kp_lwp, KInfoLWP, :kp_ktaddr, :uintptr_t, :kp_spare, [:int, 2] ) end end end sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/freebsd/000077500000000000000000000000001435233620100226345ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/freebsd/sys/000077500000000000000000000000001435233620100234525ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/freebsd/sys/proctable.rb000066400000000000000000000230741435233620100257600ustar00rootroot00000000000000require 'ffi' require 'sys/proctable/version' module Sys class ProcTable extend FFI::Library # Error typically raised if the ProcTable.ps method fails. class Error < StandardError; end # There is no constructor private_class_method :new private ffi_lib :kvm attach_function :devname, [:dev_t, :mode_t], :string attach_function :kvm_open, [:string, :string, :string, :int, :string], :pointer attach_function :kvm_close, [:pointer], :int attach_function :kvm_getprocs, [:pointer, :int, :int, :pointer], :pointer attach_function :kvm_getargv, [:pointer, :pointer, :int], :pointer POSIX_ARG_MAX = 4096 KERN_PROC_PID = 1 KERN_PROC_PROC = 8 S_IFCHR = 0020000 WMESGLEN = 8 LOCKNAMELEN = 8 OCOMMLEN = 16 COMMLEN = 19 KI_EMULNAMELEN = 16 KI_NGROUPS = 16 LOGNAMELEN = 17 KI_NSPARE_INT = 9 KI_NSPARE_LONG = 12 KI_NSPARE_PTR = 6 class Timeval < FFI::Struct layout(:tv_sec, :time_t, :tv_usec, :suseconds_t) end class Priority < FFI::Struct layout( :pri_class, :uchar, :pri_level, :uchar, :pri_native, :uchar, :pri_user, :uchar ) end class Rusage < FFI::Struct layout( :ru_utime, Timeval, :ru_stime, Timeval, :ru_maxrss, :long, :ru_ixrss, :long, :ru_idrss, :long, :ru_isrss, :long, :ru_minflt, :long, :ru_majflt, :long, :ru_nswap, :long, :ru_inblock, :long, :ru_oublock, :long, :ru_msgsnd, :long, :ru_msgrcv, :long, :ru_nsignals, :long, :ru_nvcsw, :long, :ru_nivcsw, :long ) end class Pargs < FFI::Struct layout( :ar_ref, :uint, :ar_length, :uint, :ar_args, [:uchar, 1] ) end class KInfoProc < FFI::Struct layout( :ki_structsize, :int, :ki_layout, :int, :ki_args, :pointer, :ki_paddr, :pointer, :ki_addr, :pointer, :ki_tracep, :pointer, :ki_textvp, :pointer, :ki_fd, :pointer, :ki_vmspace, :pointer, :ki_wchan, :pointer, :ki_pid, :pid_t, :ki_ppid, :pid_t, :ki_pgid, :pid_t, :ki_tpgid, :pid_t, :ki_sid, :pid_t, :ki_tsid, :pid_t, :ki_jobc, :short, :ki_spare_short1, :short, :ki_tdev, :dev_t, :ki_siglist, [:uint32_t, 4], :ki_sigmask, [:uint32_t, 4], :ki_sigignore, [:uint32_t, 4], :ki_sigcatch, [:uint32_t, 4], :ki_uid, :uid_t, :ki_ruid, :uid_t, :ki_svuid, :uid_t, :ki_rgid, :gid_t, :ki_svgid, :gid_t, :ki_ngroups, :short, :ki_spare_short2, :short, :ki_groups, [:gid_t, KI_NGROUPS], :ki_size, :uint32_t, :ki_rssize, :segsz_t, :ki_swrss, :segsz_t, :ki_tsize, :segsz_t, :ki_dsize, :segsz_t, :ki_ssize, :segsz_t, :ki_xstat, :u_short, :ki_acflag, :u_short, :ki_pctcpu, :fixpt_t, :ki_estcpu, :uint, :ki_slptime, :uint, :ki_swtime, :uint, :ki_swtime, :int, :ki_runtime, :uint64_t, :ki_start, Timeval, :ki_childtime, Timeval, :ki_flag, :long, :ki_kiflag, :long, :ki_traceflag, :int, :ki_stat, :char, :ki_nice, :char, :ki_lock, :char, :ki_rqindex, :char, :ki_oncpu, :uchar, :ki_lastcpu, :uchar, :ki_ocomm, [:char, OCOMMLEN+1], :ki_wmesg, [:char, WMESGLEN+1], :ki_login, [:char, LOGNAMELEN+1], :ki_lockname, [:char, LOCKNAMELEN+1], :ki_comm, [:char, COMMLEN+1], :ki_emul, [:char, KI_EMULNAMELEN+1], :ki_sparestrings, [:char, 68], :ki_spareints, [:int, KI_NSPARE_INT], :ki_cr_flags, :uint, :ki_jid, :int, :ki_numthreads, :int, :ki_tid, :pid_t, :ki_pri, Priority, :ki_rusage, Rusage, :ki_rusage_ch, Rusage, :ki_pcb, :pointer, :ki_kstack, :pointer, :ki_udata, :pointer, :ki_tdaddr, :pointer, :ki_spareptrs, [:pointer, KI_NSPARE_PTR], :ki_sparelongs, [:long, KI_NSPARE_LONG], :ki_sflags, :long, :ki_tdflags, :long ) end @fields = %w[ pid ppid pgid tpgid sid tsid jobc uid ruid rgid ngroups groups size rssize swrss tsize dsize ssize xstat acflag pctcpu estcpu slptime swtime runtime start flag state nice lock rqindex oncpu lastcpu wmesg login lockname comm ttynum ttydev jid priority usrpri cmdline utime stime maxrss ixrss idrss isrss minflt majflt nswap inblock oublock msgsnd msgrcv nsignals nvcsw nivcsw ] ProcTableStruct = Struct.new('ProcTableStruct', *@fields) public # 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) # def self.ps(**kwargs) pid = kwargs[:pid] begin kd = kvm_open(nil, nil, nil, 0, nil) if kd.null? raise SystemCallError.new('kvm_open', FFI.errno) end ptr = FFI::MemoryPointer.new(:int) # count if pid procs = kvm_getprocs(kd, KERN_PROC_PID, pid, ptr) else procs = kvm_getprocs(kd, KERN_PROC_PROC, 0, ptr) end if procs.null? if pid && FFI.errno == Errno::ESRCH::Errno return nil else raise SystemCallError.new('kvm_getprocs', FFI.errno) end end count = ptr.read_int array = [] 0.upto(count-1){ |i| cmd = nil kinfo = KInfoProc.new(procs[i * KInfoProc.size]) args = kvm_getargv(kd, kinfo, 0) unless args.null? cmd = [] until ((ptr = args.read_pointer).null?) cmd << ptr.read_string args += FFI::Type::POINTER.size end cmd = cmd.join(' ') end struct = ProcTableStruct.new( kinfo[:ki_pid], kinfo[:ki_ppid], kinfo[:ki_pgid], kinfo[:ki_tpgid], kinfo[:ki_sid], kinfo[:ki_tsid], kinfo[:ki_jobc], kinfo[:ki_uid], kinfo[:ki_ruid], kinfo[:ki_rgid], kinfo[:ki_ngroups], kinfo[:ki_groups].to_a[0...kinfo[:ki_ngroups]], kinfo[:ki_size], kinfo[:ki_rssize], kinfo[:ki_swrss], kinfo[:ki_tsize], kinfo[:ki_dsize], kinfo[:ki_ssize], kinfo[:ki_xstat], kinfo[:ki_acflag], kinfo[:ki_pctcpu].to_f, kinfo[:ki_estcpu], kinfo[:ki_slptime], kinfo[:ki_swtime], kinfo[:ki_runtime], Time.at(kinfo[:ki_start][:tv_sec]), kinfo[:ki_flag], get_state(kinfo[:ki_stat]), kinfo[:ki_nice], kinfo[:ki_lock], kinfo[:ki_rqindex], kinfo[:ki_oncpu], kinfo[:ki_lastcpu], kinfo[:ki_wmesg].to_s, kinfo[:ki_login].to_s, kinfo[:ki_lockname].to_s, kinfo[:ki_comm].to_s, kinfo[:ki_tdev], devname(kinfo[:ki_tdev], S_IFCHR), kinfo[:ki_jid], kinfo[:ki_pri][:pri_level], kinfo[:ki_pri][:pri_user], cmd, kinfo[:ki_rusage][:ru_utime][:tv_sec], kinfo[:ki_rusage][:ru_stime][:tv_sec], kinfo[:ki_rusage][:ru_maxrss], kinfo[:ki_rusage][:ru_ixrss], kinfo[:ki_rusage][:ru_idrss], kinfo[:ki_rusage][:ru_isrss], kinfo[:ki_rusage][:ru_minflt], kinfo[:ki_rusage][:ru_majflt], kinfo[:ki_rusage][:ru_nswap], kinfo[:ki_rusage][:ru_inblock], kinfo[:ki_rusage][:ru_oublock], kinfo[:ki_rusage][:ru_msgsnd], kinfo[:ki_rusage][:ru_msgrcv], kinfo[:ki_rusage][:ru_nsignals], kinfo[:ki_rusage][:ru_nvcsw], kinfo[:ki_rusage][:ru_nivcsw] ) struct.freeze # This is readonly data if block_given? yield struct else array << struct end } ensure kvm_close(kd) unless kd.null? end if block_given? nil else pid ? array.first : array end 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 private SIDL = 1 SRUN = 2 SSLEEP = 3 SSTOP = 4 SZOMB = 5 SWAIT = 6 SLOCK = 7 def self.get_state(int) case int when SIDL; "idle" when SRUN; "run" when SSLEEP; "sleep" when SSTOP; "stop" when SZOMB; "zombie" when SWAIT; "waiting" when SLOCK; "locked" else; "unknown" end end end end sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/freebsd/sys/proctable/000077500000000000000000000000001435233620100254255ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/freebsd/sys/proctable/constants.rb000066400000000000000000000000001435233620100277540ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/freebsd/sys/proctable/functions.rb000066400000000000000000000000001435233620100277500ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/freebsd/sys/proctable/structs.rb000066400000000000000000000000001435233620100274470ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/bsd/sys/proctable.rb000066400000000000000000000003251435233620100235220ustar00rootroot00000000000000case RbConfig::CONFIG['host_os'] when /freebsd/i require_relative 'freebsd/sys/proctable' when /dragonfly/i require_relative 'dragonfly/sys/proctable' else raise "Unsupported version of BSD" end sys-proctable-sys-proctable-1.3.0/lib/darwin/000077500000000000000000000000001435233620100211205ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/darwin/sys/000077500000000000000000000000001435233620100217365ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/darwin/sys/proctable.rb000066400000000000000000000333071435233620100242440ustar00rootroot00000000000000require 'sys/proctable/version' require 'ffi' module Sys class ProcTable extend FFI::Library # Error typically raised if the ProcTable.ps method fails. class Error < StandardError; end # There is no constructor private_class_method :new PROC_PIDTASKALLINFO = 2 PROC_PIDTHREADINFO = 5 PROC_PIDLISTTHREADS = 6 private_constant :PROC_PIDTASKALLINFO private_constant :PROC_PIDTHREADINFO private_constant :PROC_PIDLISTTHREADS CTL_KERN = 1 KERN_PROCARGS = 38 KERN_PROCARGS2 = 49 MAXCOMLEN = 16 MAXPATHLEN = 256 private_constant :CTL_KERN private_constant :KERN_PROCARGS private_constant :KERN_PROCARGS2 private_constant :MAXCOMLEN private_constant :MAXPATHLEN MAXTHREADNAMESIZE = 64 PROC_PIDPATHINFO_MAXSIZE = MAXPATHLEN * 4 private_constant :MAXTHREADNAMESIZE private_constant :PROC_PIDPATHINFO_MAXSIZE # JRuby/Truffleruby on Mac unless defined? FFI::StructLayout::CharArray if defined? FFI::StructLayout::CharArrayProxy FFI::StructLayout::CharArray = FFI::StructLayout::CharArrayProxy else FFI::StructLayout::CharArray = FFI::Struct::CharArray end end class ProcBsdInfo < FFI::Struct layout( :pbi_flags, :uint32_t, :pbi_status, :uint32_t, :pbi_xstatus, :uint32_t, :pbi_pid, :uint32_t, :pbi_ppid, :uint32_t, :pbi_uid, :uid_t, :pbi_gid, :uid_t, :pbi_ruid, :uid_t, :pbi_rgid, :gid_t, :pbi_svuid, :uid_t, :pbi_svgid, :gid_t, :rfu1, :uint32_t, :pbi_comm, [:char, MAXCOMLEN], :pbi_name, [:char, MAXCOMLEN * 2], :pbi_nfiles, :uint32_t, :pbi_pgid, :uint32_t, :pbi_pjobc, :uint32_t, :e_tdev, :uint32_t, :e_tpgid, :uint32_t, :pbi_nice, :int32_t, :pbi_start_tvsec, :uint64_t, :pbi_start_tvusec, :uint64_t ) end private_constant :ProcBsdInfo class ProcTaskInfo < FFI::Struct layout( :pti_virtual_size, :uint64_t, :pti_resident_size, :uint64_t, :pti_total_user, :uint64_t, :pti_total_system, :uint64_t, :pti_threads_user, :uint64_t, :pti_threads_system, :uint64_t, :pti_policy, :int32_t, :pti_faults, :int32_t, :pti_pageins, :int32_t, :pti_cow_faults, :int32_t, :pti_messages_sent, :int32_t, :pti_messages_received, :int32_t, :pti_syscalls_mach, :int32_t, :pti_syscalls_unix, :int32_t, :pti_csw, :int32_t, :pti_threadnum, :int32_t, :pti_numrunning, :int32_t, :pti_priority, :int32_t ) end private_constant :ProcTaskInfo class ProcThreadInfo < FFI::Struct layout( :pth_user_time, :uint64_t, :pth_system_time, :uint64_t, :pth_cpu_usage, :int32_t, :pth_policy, :int32_t, :pth_run_state, :int32_t, :pth_flags, :int32_t, :pth_sleep_time, :int32_t, :pth_curpri, :int32_t, :pth_priority, :int32_t, :pth_maxpriority, :int32_t, :pth_name, [:char, MAXTHREADNAMESIZE] ) end private_constant :ProcThreadInfo # Map the fields from the FFI::Structs to the Sys::ProcTable struct on # class load to reduce the amount of objects needing to be generated for # each invocation of Sys::ProcTable.ps all_members = ProcBsdInfo.members + ProcTaskInfo.members + ProcThreadInfo.members PROC_STRUCT_FIELD_MAP = all_members.map do |member| temp = member.to_s.split('_') sproperty = temp.size > 1 ? temp[1..-1].join('_') : temp.first [member, sproperty.to_sym] end.to_h class ProcTaskAllInfo < FFI::Struct layout(:pbsd, ProcBsdInfo, :ptinfo, ProcTaskInfo) end private_constant :ProcTaskAllInfo ffi_lib 'proc' attach_function :proc_listallpids, %i[pointer int], :int attach_function :proc_pidinfo, %i[int int uint64_t pointer int], :int ffi_lib FFI::Library::LIBC attach_function :sysctl, %i[pointer uint pointer pointer pointer size_t], :int private_class_method :proc_listallpids private_class_method :proc_pidinfo private_class_method :sysctl # These mostly mimic the struct members, but we've added a few custom ones as well. @fields = %w[ flags status xstatus pid ppid uid gid ruid rgid svuid svgid rfu1 comm name nfiles pgid pjobc tdev tpgid nice start_tvsec start_tvusec virtual_size resident_size total_user total_system threads_user threads_system policy faults pageins cow_faults messages_sent messages_received syscalls_mach syscalls_unix csw threadnum numrunning priority cmdline exe environ threadinfo ] # Add a couple aliases to make it similar to Linux ProcTableStruct = Struct.new("ProcTableStruct", *@fields) do alias_method :vsize, :virtual_size alias_method :rss, :resident_size end private_constant :ProcTableStruct ThreadInfoStruct = Struct.new("ThreadInfo", :user_time, :system_time, :cpu_usage, :policy, :run_state, :flags, :sleep_time, :curpri, :priority, :maxpriority, :name ) private_constant :ThreadInfoStruct # 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 process table. # # Example: # # Sys::ProcTable.fields.each{ |field| # puts "Field: #{field}" # } # def self.fields @fields end # 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(pid: 1001) # # # Same as above, but do not include thread information # p ProcTable.ps(pid: 1001, thread_info: false) # def self.ps(**kwargs) pid = kwargs[:pid] thread_info = kwargs[:thread_info] if pid raise TypeError unless pid.is_a?(Numeric) info = ProcTaskAllInfo.new nb = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, info, info.size) if nb <= 0 if [Errno::EPERM::Errno, Errno::ESRCH::Errno].include?(FFI.errno) return # Either we don't have permission, or the pid no longer exists else raise SystemCallError.new('proc_pidinfo', FFI.errno) end end return nil if nb != info.size # Invalid data struct = ProcTableStruct.new # Pass by reference get_cmd_args_and_env(pid, struct) get_thread_info(pid, struct, info[:ptinfo]) unless thread_info == false apply_info_to_struct(info, struct) struct.freeze yield struct if block_given? struct else num = proc_listallpids(nil, 0) ptr = FFI::MemoryPointer.new(:pid_t, num) num = proc_listallpids(ptr, ptr.size) raise SystemCallError.new('proc_listallpids', FFI.errno) if num == 0 pids = ptr.get_array_of_int32(0, num).sort array = block_given? ? nil : [] pids.each do |lpid| next if pid && pid != lpid info = ProcTaskAllInfo.new nb = proc_pidinfo(lpid, PROC_PIDTASKALLINFO, 0, info, info.size) if nb <= 0 if [Errno::EPERM::Errno, Errno::ESRCH::Errno].include?(FFI.errno) next # Either we don't have permission, or the pid no longer exists else raise SystemCallError.new('proc_pidinfo', FFI.errno) end end # Avoid potentially invalid data next if nb != info.size struct = ProcTableStruct.new # Pass by reference get_cmd_args_and_env(lpid, struct) get_thread_info(lpid, struct, info[:ptinfo]) unless thread_info == false apply_info_to_struct(info, struct) struct.freeze if block_given? yield struct else array << struct end end array end end # Pass by reference method that updates the Ruby struct based on the FFI struct. # def self.apply_info_to_struct(info, struct) # Chop the leading xx_ from the FFI struct members for our ruby struct. info.members.each do |nested| info[nested].members.each do |member| if info[nested][member].is_a?(FFI::StructLayout::CharArray) struct[PROC_STRUCT_FIELD_MAP[member]] = info[nested][member].to_s else struct[PROC_STRUCT_FIELD_MAP[member]] = info[nested][member] end end end end private_class_method :apply_info_to_struct # Returns an array of ThreadInfo objects for the given pid. # def self.get_thread_info(pid, struct, ptinfo) buf = FFI::MemoryPointer.new(:uint64_t, ptinfo[:pti_threadnum]) num = proc_pidinfo(pid, PROC_PIDLISTTHREADS, 0, buf, buf.size) if num <= 0 if [Errno::EPERM::Errno, Errno::ESRCH::Errno].include?(FFI.errno) return # Either we don't have permission, or the pid no longer exists else raise SystemCallError.new('proc_pidinfo', FFI.errno) end end max = ptinfo[:pti_threadnum] struct[:threadinfo] = [] 0.upto(max - 1) do |index| tinfo = ProcThreadInfo.new # Use read_array_of_uint64 for compatibility with JRuby if necessary. if buf[index].respond_to?(:read_uint64) nb = proc_pidinfo(pid, PROC_PIDTHREADINFO, buf[index].read_uint64, tinfo, tinfo.size) else nb = proc_pidinfo(pid, PROC_PIDTHREADINFO, buf[index].read_array_of_uint64(1).first, tinfo, tinfo.size) end if nb <= 0 if [Errno::EPERM::Errno, Errno::ESRCH::Errno].include?(FFI.errno) next # Either we don't have permission, or the pid no longer exists else raise SystemCallError.new('proc_pidinfo', FFI.errno) end end tinfo_struct = ThreadInfoStruct.new( tinfo[:pth_user_time], tinfo[:pth_system_time], tinfo[:pth_cpu_usage], tinfo[:pth_policy], tinfo[:pth_run_state], tinfo[:pth_flags], tinfo[:pth_sleep_time], tinfo[:pth_curpri], tinfo[:pth_priority], tinfo[:pth_maxpriority], tinfo[:pth_name].to_s ) struct[:threadinfo] << tinfo_struct end end private_class_method :get_thread_info # Get the command line arguments, as well as the environment settings, # for the given PID. #-- # Note that on Big Sur and later it seems that you cannot get environment # variable information on spawned processes except in certain circumstances, # e.g. SIP has been disabled, the kernel is in debug mode, etc. # def self.get_cmd_args_and_env(pid, struct) len = FFI::MemoryPointer.new(:size_t) mib = FFI::MemoryPointer.new(:int, 3) # Since we may not have access to the process information due # to improper privileges, just bail if we see a failure here. # First use KERN_PROCARGS2 to discover the argc value of the running process. mib.write_array_of_int([CTL_KERN, KERN_PROCARGS2, pid]) return if sysctl(mib, 3, nil, len, nil, 0) < 0 buf = FFI::MemoryPointer.new(:char, len.read_ulong) return if sysctl(mib, 3, buf, len, nil, 0) < 0 # The argc value is located in the first byte of buf argc = buf.read_bytes(1).ord buf.free # Now use KERN_PROCARGS to fetch the rest of the process information mib.write_array_of_int([CTL_KERN, KERN_PROCARGS, pid]) return if sysctl(mib, 3, nil, len, nil, 0) < 0 buf = FFI::MemoryPointer.new(:char, len.read_ulong) return if sysctl(mib, 3, buf, len, nil, 0) < 0 exe = buf.read_string # Read up to first null, does not include args struct[:exe] = exe # Parse the rest of the information out of a big, ugly string array = buf.read_bytes(len.read_ulong).split(0.chr) array.delete('') # Delete empty strings # The format that sysctl outputs is as follows: # # [full executable path] # [executable name] # [arguments] # [environment variables] # ... # \FF\BF # [full executable path] # # Strip the first executable path and the last two entries from the array. # What is left is the name, arguments, and environment variables array = array[1..-3] # It seems that argc sometimes returns a bogus value. In that case, delete # any environment variable strings, and reset the argc value. # if argc > array.size array.delete_if{ |e| e.include?('=') } argc = array.size end cmdline = '' # Extract the full command line and its arguments from the array argc.times do cmdline << ' ' << array.shift end struct[:cmdline] = cmdline.strip # Anything remaining at this point is a collection of key=value # pairs which we convert into a hash. environ = array.each_with_object({}) do |string, hash| if string && string.include?('=') key, value = string.split('=') hash[key] = value end end struct[:environ] = environ end private_class_method :get_cmd_args_and_env end end sys-proctable-sys-proctable-1.3.0/lib/linux/000077500000000000000000000000001435233620100207735ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/linux/sys/000077500000000000000000000000001435233620100216115ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/linux/sys/proctable.rb000066400000000000000000000325551435233620100241230ustar00rootroot00000000000000# frozen_string_literal: true require 'sys/proctable/version' require_relative 'proctable/cgroup_entry' require_relative 'proctable/smaps' # The Sys module serves as a namespace only. module Sys # The ProcTable class encapsulates process table information. class ProcTable # Error typically raised if the ProcTable.ps method fails. class Error < StandardError; end # There is no constructor private_class_method :new @mem_total = File.read("/proc/meminfo")[/MemTotal.*/].split[1].to_i * 1024 rescue nil @boot_time = File.read("/proc/stat")[/btime.*/].split.last.to_i rescue nil @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 'num_threads', # Number of threads in this process '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 (old) 'rsslim', # Current limit on the rss in bytes (current) '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 'delayacct_blkio_ticks', # Aggregated block I/O delays 'guest_time', # Guest time of the process 'cguest_time', # Guest time of the process's children 'name', # Process name 'uid', # Real user ID 'euid', # Effective user ID 'gid', # Real group ID 'egid', # Effective group ID 'pctcpu', # Percent of CPU usage (custom field) 'pctmem', # Percent of Memory usage (custom field) 'nlwp', # Number of Light-Weight Processes associated with the process (threads) 'cgroup', # Control groups to which the process belongs 'smaps' # Process memory size for all mapped files ] ProcTableStruct = Struct.new('ProcTableStruct', *@fields) private_constant :ProcTableStruct # 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(pid: 1001) # # # Skip smaps collection and/or cgroup collection # p ProcTable.ps(smaps: false, cgroup: false) # #-- # 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(**kwargs) pid = kwargs[:pid] smaps = kwargs[:smaps] cgroup = kwargs[:cgroup] array = block_given? ? nil : [] struct = nil raise TypeError if pid && !pid.is_a?(Numeric) Dir.foreach("/proc") do |file| next if file =~ /\D/ # Skip non-numeric directories next if pid && file.to_i != pid struct = ProcTableStruct.new # Get /proc//cmdline information. Strip out embedded nulls. begin data = File.read("/proc/#{file}/cmdline").tr("\000", ' ').strip struct.cmdline = data rescue StandardError next # Process terminated, on to the next process end # Get /proc//cwd information struct.cwd = File.readlink("/proc/#{file}/cwd") rescue nil # Get /proc//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 File.read("/proc/#{file}/environ").force_encoding("UTF-8").split("\0").each do |str| key, value = str.split('=') struct.environ[key] = value end rescue Errno::EACCES, Errno::ESRCH, Errno::ENOENT # Ignore and move on. end # Get /proc//exe information struct.exe = File.readlink("/proc/#{file}/exe") rescue nil # Get /proc//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 StandardError # Ignore and move on end # Get /proc//root information struct.root = File.readlink("/proc/#{file}/root") rescue nil # Get /proc//stat information stat = File.read("/proc/#{file}/stat") rescue next # Get number of LWP, one directory for each in /proc//task/ # Every process has at least one thread, so if we fail to read the task directory, set nlwp to 1. struct.nlwp = Dir.glob("/proc/#{file}/task/*").length rescue struct.nlwp = 1 # Get control groups to which the process belongs unless cgroup == false struct.cgroup = File.readlines("/proc/#{file}/cgroup").map { |l| CgroupEntry.new(l) } rescue [] end # Read smaps, returning a parsable string if we don't have permissions. # Note: We're blindly rescuing because File.readable?/readable_real? # are true for a file in the /proc fileystem but raises a Errno:EACCESS # when your try to read it without permissions. unless smaps == false smaps_contents = File.read("/proc/#{file}/smaps") rescue "" struct.smaps = Smaps.new(file, smaps_contents) end # Deal with spaces in comm name. This isn't supposed to happen, but in # rare cases - the original offending case was "(xzen thread)" - it can # occur. So we parse it out, replace the spaces with hyphens, and # re-insert it into the stat string so that it splits properly later on. # # Courtesy of Ara Howard. # re = /\([^)]+\)/ 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 struct.num_threads = stat[19].to_i 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 # Old name for backwards compatibility struct.rsslim = 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 struct.delayacct_blkio_ticks = stat[41].to_i struct.guest_time = stat[42].to_i struct.cguest_time = stat[43].to_i # Get /proc//status information (name, uid, euid, gid, egid) begin File.foreach("/proc/#{file}/status") do |line| case line when /Name:\s*?(\w+)/ struct.name = Regexp.last_match(1) when /Uid:\s*?(\d+)\s*?(\d+)/ struct.uid = Regexp.last_match(1).to_i struct.euid = Regexp.last_match(2).to_i when /Gid:\s*?(\d+)\s*?(\d+)/ struct.gid = Regexp.last_match(1).to_i struct.egid = Regexp.last_match(2).to_i end end rescue Errno::ESRCH, Errno::ENOENT next 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 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}" # } # class << self attr_reader :fields end # Calculate the percentage of memory usage for the given process. # def self.get_pctmem(rss) return nil unless @mem_total page_size = 4096 rss_total = rss * page_size format("%3.2f", (rss_total.to_f / @mem_total) * 100).to_f end private_class_method :get_pctmem # Calculate the percentage of CPU usage for the given process. # def self.get_pctcpu(utime, start_time) return nil unless @boot_time hertz = 100.0 utime = (utime * 10000).to_f stime = (start_time.to_f / hertz) + @boot_time format("%3.2f", (utime / 10000.0) / (Time.now.to_i - stime)).to_f end private_class_method :get_pctcpu end end sys-proctable-sys-proctable-1.3.0/lib/linux/sys/proctable/000077500000000000000000000000001435233620100235645ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/linux/sys/proctable/cgroup_entry.rb000066400000000000000000000024041435233620100266310ustar00rootroot00000000000000# frozen_string_literal: true module Sys class ProcTable # This represents a cgroup entry # # Have a look at `man 5 proc` on a linux distribution, to get some more # information about the lines and their fields in `/proc/[pid]/cgroup`. # # Example: # # entry = CgroupEntry.new '7:devices:/init.scope' # entry.hierarchy_id # => 7 # entry.subsystems # => ['devices'] # entry.control_group # => '/init.scope' # class CgroupEntry # Create a new cgroup entry object # # This expects a string of '7:devices:/init.scope' - see `man 5 proc` for a # reference. def initialize(string) @string = string.chomp @fields = @string.split(/:/) rescue StandardError @fields = [] end # This returns the hierarchy id of the cgroup entry def hierarchy_id @fields[0].to_i end # Return sets of subsystems bound to the hierarchy def subsystems @fields[1].split(/,/) rescue StandardError [] end # control group in the hierarchy to which the process belongs def control_group @fields[2] end # Return the line itself def to_s @string end end end end sys-proctable-sys-proctable-1.3.0/lib/linux/sys/proctable/smaps.rb000066400000000000000000000075071435233620100252450ustar00rootroot00000000000000# frozen_string_literal: true module Sys class ProcTable # Smaps represents a process' memory size for all mapped files # # A single mapped file memory entry looks like this: # # 00400000-004d4000 r-xp 00000000 fd:00 785 /bin/bash # Size: 848 kB # Rss: 572 kB # Pss: 572 kB # Shared_Clean: 0 kB # Shared_Dirty: 0 kB # Private_Clean: 572 kB # Private_Dirty: 0 kB # Referenced: 572 kB # Anonymous: 0 kB # AnonHugePages: 0 kB # Swap: 0 kB # KernelPageSize: 4 kB # MMUPageSize: 4 kB # # Have a look at `man 5 proc` on a linux distribution, to get some more # information about the lines and fields in `/proc/[pid]/smaps`. # # Example: # # smaps = Smaps.new(123, IO.read("/proc/1234/smaps") # # # result # # # # # smaps.pss # => 109568 # smaps.rss # => 376832 # smaps.uss # => 98304 # smaps.swap # => 196608 # smaps.vss # => 140034048 # class Smaps # Process ID for this smaps attr_reader :pid # Proportional set size # # PSS is the size of private pages added to each shared mapping's size # divided by the number of processes that share it. It is meant to # provide a better representation of the amount of memory actually used # by a process. # # If a process has 4k of private pages, 4k of shared pages shared with one # other process, and 3k of pages shared with two other processes, the PSS # is: # # 4k + (4k / 2) + (3k / 3) = 7k # attr_reader :pss alias proportional_set_size pss # Resident set size # # RSS is the total size of all pages, shared or not, mapped to a process. attr_reader :rss alias resident_set_size rss # Unique set size # # USS is the total size of all private pages mapped to a process. attr_reader :uss alias unique_set_size uss # Swap # # Swap is the total size of all swapped pages mapped to a process. attr_reader :swap # Virtual set size # # VSS is the total accessible address space in a process. Since files are # lazily loaded, this value represents the total size of all mapped files # if they were all loaded. attr_reader :vss alias virtual_set_size vss # Create a new smaps object # # # This expects a process id and a string containing the contents of # /proc/PID/smaps - see `man 5 proc` for a reference. # # The smaps contents are parsed and memory sizes are calculated in bytes. def initialize(pid, smaps_contents) @pid = pid @pss = 0 @rss = 0 @uss = 0 @swap = 0 @vss = 0 smaps_contents.each_line { |line| parse_smaps_line(line) } end alias to_s inspect private def parse_smaps_line(line) case line when /^Pss:\s+?(\d+)/ @pss += Regexp.last_match[1].to_i * 1000 when /^Rss:\s+?(\d+)/ @rss += Regexp.last_match[1].to_i * 1000 when /^Size:\s+?(\d+)/ @vss += Regexp.last_match[1].to_i * 1000 when /^Swap:\s+?(\d+)/ @swap += Regexp.last_match[1].to_i * 1000 when /^Private_(Clean|Dirty):\s+?(\d+)/ @uss += Regexp.last_match[2].to_i * 1000 end end end end end sys-proctable-sys-proctable-1.3.0/lib/sunos/000077500000000000000000000000001435233620100210035ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/sunos/sys/000077500000000000000000000000001435233620100216215ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/sunos/sys/proctable.rb000066400000000000000000000371711435233620100241320ustar00rootroot00000000000000######################################################################## # proctable.rb # # A pure Ruby version of sys-proctable for SunOS 5.8 or later. ######################################################################## require 'ffi' require 'sys/proctable/version' # The Sys module serves as a namespace only. module Sys # The ProcTable class encapsulates process table information. class ProcTable extend FFI::Library class Error < StandardError; end # There is no constructor private_class_method :new private class Timeval < FFI::Struct layout(:tv_sec, :time_t, :tv_usec, :time_t) end class LWPSInfo < FFI::Struct layout( :pr_flag, :int, :pr_lwpid, :id_t, :pr_addr, :uintptr_t, :pr_wchan, :uintptr_t, :pr_stype, :char, :pr_state, :char, :pr_sname, :char, :pr_nice, :char, :pr_syscall, :short, :pr_oldpri, :char, :pr_cpu, :char, :pr_pri, :int, :pr_pctcpu, :ushort_t, :pr_pad, :ushort_t, :pr_start, Timeval, :pr_time, Timeval, :pr_clname, [:char, 8], :pr_name, [:char, 16], :pr_onpro, :int, :pr_bindpro, :int, :pr_bindpset, :int, :pr_filler, [:int, 5] ) end class PSInfo < FFI::Struct layout( :pr_flag, :int, :pr_nlwp, :int, :pr_pid, :pid_t, :pr_ppid, :pid_t, :pr_pgid, :pid_t, :pr_sid, :pid_t, :pr_uid, :uid_t, :pr_euid, :uid_t, :pr_gid, :gid_t, :pr_egid, :gid_t, :pr_addr, :uintptr_t, :pr_size, :size_t, :pr_rssize, :size_t, :pr_pad1, :size_t, :pr_ttydev, :dev_t, :pr_pctcpu, :ushort_t, :pr_pctmem, :ushort_t, :pr_start, Timeval, :pr_time, Timeval, :pr_ctime, Timeval, :pr_fname, [:char, 16], :pr_psargs, [:char, 80], :pr_wstat, :int, :pr_argc, :int, :pr_argv, :uintptr_t, :pr_envp, :uintptr_t, :pr_dmodel, :char, :pr_pad2, [:char, 3], :pr_taskid, :taskid_t, :pr_projid, :projid_t, :pr_nzomb, :int, :pr_poolid, :poolid_t, :pr_zoneid, :zoneid_t, :pr_contract, :id_t, :pr_filler, [:int, 1], :pr_lwp, LWPSInfo ) end class PRUsage < FFI::Struct layout( :pr_lwpid, :id_t, :pr_count, :int, :pr_tstamp, Timeval, :pr_create, Timeval, :pr_term, Timeval, :pr_rtime, Timeval, :pr_utime, Timeval, :pr_stime, Timeval, :pr_ttime, Timeval, :pr_tftime, Timeval, :pr_dftime, Timeval, :pr_kftime, Timeval, :pr_ltime, Timeval, :pr_slptime, Timeval, :pr_wtime, Timeval, :pr_stoptime, Timeval, :pr_filetime, [Timeval, 6], :pr_minf, :ulong_t, :pr_majf, :ulong_t, :pr_nswap, :ulong_t, :pr_inblk, :ulong_t, :pr_oublk, :ulong_t, :pr_msnd, :ulong_t, :pr_mrcv, :ulong_t, :pr_sigs, :ulong_t, :pr_vctx, :ulong_t, :pr_ictx, :ulong_t, :pr_sysc, :ulong_t, :pr_ioch, :ulong_t, :filler, [:ulong_t, 10] ) end PRNODEV = (1</path :contracts, # array symbolic link paths from /proc//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 ] public ProcTableStruct = Struct.new("ProcTableStruct", *@fields) do alias comm fname end # 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(pid: 1001) # # # Skip prusage information # p ProcTable.ps(prusage: false) # def self.ps(**kwargs) pid = kwargs[:pid] prusage_info = kwargs[:prusage] raise TypeError unless pid.is_a?(Numeric) if pid array = block_given? ? nil : [] struct = nil Dir.foreach("/proc") do |file| next if file =~ /\D/ # Skip non-numeric entries under /proc # Only return information for a given pid, if provided next unless file.to_i == pid if pid # Skip over any entries we don't have permissions to read next unless File.readable?("/proc/#{file}/psinfo") data = IO.read("/proc/#{file}/psinfo") rescue next psinfo = PSInfo.new(FFI::MemoryPointer.from_string(data)) struct = ProcTableStruct.new struct.flag = psinfo[:pr_flag] struct.nlwp = psinfo[:pr_nlwp] struct.pid = psinfo[:pr_pid] struct.ppid = psinfo[:pr_ppid] struct.pgid = psinfo[:pr_pgid] struct.sid = psinfo[:pr_sid] struct.uid = psinfo[:pr_uid] struct.euid = psinfo[:pr_euid] struct.gid = psinfo[:pr_gid] struct.egid = psinfo[:pr_egid] struct.addr = psinfo[:pr_addr] struct.size = psinfo[:pr_size] * 1024 # bytes struct.rssize = psinfo[:pr_rssize] * 1024 # bytes struct.ttydev = psinfo[:pr_ttydev] == PRNODEV ? -1 : psinfo[:pr_ttydev] struct.pctcpu = (psinfo[:pr_pctcpu] * 100).to_f / 0x8000 struct.pctmem = (psinfo[:pr_pctmem] * 100).to_f / 0x8000 struct.start = Time.at(psinfo[:pr_start][:tv_sec]) struct.time = psinfo[:pr_time][:tv_sec] struct.ctime = psinfo[:pr_ctime][:tv_sec] struct.fname = psinfo[:pr_fname].to_s struct.psargs = psinfo[:pr_psargs].to_s struct.wstat = psinfo[:pr_wstat] struct.argc = psinfo[:pr_argc] struct.argv = psinfo[:pr_argv] struct.envp = psinfo[:pr_envp] struct.dmodel = psinfo[:pr_dmodel] struct.taskid = psinfo[:pr_taskid] struct.projid = psinfo[:pr_projid] struct.nzomb = psinfo[:pr_nzomb] struct.poolid = psinfo[:pr_poolid] struct.zoneid = psinfo[:pr_zoneid] struct.contract = psinfo[:pr_contract] ### LWPSINFO struct info struct.lwpid = psinfo[:pr_lwp][:pr_lwpid] struct.wchan = psinfo[:pr_lwp][:pr_wchan] struct.stype = psinfo[:pr_lwp][:pr_stype] struct.state = psinfo[:pr_lwp][:pr_state] struct.sname = psinfo[:pr_lwp][:pr_sname].chr struct.nice = psinfo[:pr_lwp][:pr_nice] struct.syscall = psinfo[:pr_lwp][:pr_syscall] struct.pri = psinfo[:pr_lwp][:pr_pri] struct.clname = psinfo[:pr_lwp][:pr_clname].to_s struct.name = psinfo[:pr_lwp][:pr_name].to_s struct.onpro = psinfo[:pr_lwp][:pr_onpro] struct.bindpro = psinfo[:pr_lwp][:pr_bindpro] struct.bindpset = psinfo[:pr_lwp][:pr_bindpset] # Get the full command line out of /proc//as. begin File.open("/proc/#{file}/as") do |fd| fd.sysseek(struct.argv, IO::SEEK_SET) address = fd.sysread(struct.argc * 4).unpack("L")[0] struct.cmd_args = [] 0.upto(struct.argc - 1){ |i| fd.sysseek(address, IO::SEEK_SET) data = fd.sysread(128)[/^[^\0]*/] # Null strip struct.cmd_args << data address += data.length + 1 # Add 1 for the space } # Get the environment hash associated with the process. struct.environ = {} fd.sysseek(struct.envp, IO::SEEK_SET) env_address = fd.sysread(128).unpack("L")[0] # TODO: Optimization potential here. loop do fd.sysseek(env_address, IO::SEEK_SET) data = fd.sysread(1024)[/^[^\0]*/] # Null strip break if data.empty? key, value = data.split('=') struct.environ[key] = value env_address += data.length + 1 # Add 1 for the space end end rescue Errno::EACCES, Errno::EBADF, Errno::EOVERFLOW, EOFError, RangeError # Skip this if we don't have proper permissions, if there's # no associated environment, or if there's a largefile issue. rescue Errno::ENOENT next # The process has terminated. Bail out! end ### struct prusage if prusage_info != false begin data = IO.read("/proc/#{file}/usage") prusage = PRUsage.new(FFI::MemoryPointer.from_string(data)) struct.count = prusage[:pr_count] struct.tstamp = prusage[:pr_tstamp][:tv_sec] struct.create = prusage[:pr_create][:tv_sec] struct.term = prusage[:pr_term][:tv_sec] struct.rtime = prusage[:pr_rtime][:tv_sec] struct.utime = prusage[:pr_utime][:tv_sec] struct.stime = prusage[:pr_stime][:tv_sec] struct.ttime = prusage[:pr_ttime][:tv_sec] struct.tftime = prusage[:pr_tftime][:tv_sec] struct.dftime = prusage[:pr_dftime][:tv_sec] struct.kftime = prusage[:pr_kftime][:tv_sec] struct.ltime = prusage[:pr_ltime][:tv_sec] struct.slptime = prusage[:pr_slptime][:tv_sec] struct.wtime = prusage[:pr_wtime][:tv_sec] struct.stoptime = prusage[:pr_stoptime][:tv_sec] struct.minf = prusage[:pr_minf] struct.majf = prusage[:pr_majf] struct.nswap = prusage[:pr_nswap] struct.inblk = prusage[:pr_inblk] struct.oublk = prusage[:pr_oublk] struct.msnd = prusage[:pr_msnd] struct.mrcv = prusage[:pr_mrcv] struct.sigs = prusage[:pr_sigs] struct.vctx = prusage[:pr_vctx] struct.ictx = prusage[:pr_ictx] struct.sysc = prusage[:pr_sysc] struct.ioch = prusage[:pr_ioch] rescue Errno::EACCES # Do nothing if we lack permissions. Just move on. rescue Errno::ENOENT next # The process has terminated. Bail out! end end # Information from /proc//path. This is represented as a hash, # with the symbolic link name as the key, and the file it links to # as the value, or nil if it cannot be found. #-- # Note that cwd information can be gathered from here, too. struct.path = {} Dir["/proc/#{file}/path/*"].each{ |entry| link = File.readlink(entry) rescue nil struct.path[File.basename(entry)] = link } # Information from /proc//contracts. This is represented as # a hash, with the symbolic link name as the key, and the file # it links to as the value. struct.contracts = {} Dir["/proc/#{file}/contracts/*"].each{ |entry| link = File.readlink(entry) rescue nil struct.contracts[File.basename(entry)] = link } # Information from /proc//fd. This returns an array of # numeric file descriptors used by the process. struct.fd = Dir["/proc/#{file}/fd/*"].map{ |f| File.basename(f).to_i } # Use the cmd_args as the cmdline if available. Otherwise use # the psargs. This struct member is provided to provide a measure # of consistency with the other platform implementations. if struct.cmd_args && struct.cmd_args.length > 0 struct.cmdline = struct.cmd_args.join(' ') else struct.cmdline = struct.psargs end # This is read-only data struct.freeze if block_given? yield struct else array << struct end 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.map(&:to_s) end end end sys-proctable-sys-proctable-1.3.0/lib/sys-proctable.rb000066400000000000000000000000411435233620100227430ustar00rootroot00000000000000require_relative 'sys/proctable' sys-proctable-sys-proctable-1.3.0/lib/sys-top.rb000066400000000000000000000000221435233620100215710ustar00rootroot00000000000000require 'sys/top' sys-proctable-sys-proctable-1.3.0/lib/sys/000077500000000000000000000000001435233620100204525ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/sys/proctable.rb000066400000000000000000000010061435233620100227470ustar00rootroot00000000000000require 'rbconfig' case RbConfig::CONFIG['host_os'] when /aix/i require_relative '../aix/sys/proctable' when /darwin/i require_relative '../darwin/sys/proctable' when /freebsd|dragonfly/i require_relative '../bsd/sys/proctable' when /linux/i require_relative '../linux/sys/proctable' when /sunos|solaris/i require_relative '../sunos/sys/proctable' when /mswin|win32|dos|cygwin|mingw|windows/i require_relative '../windows/sys/proctable' else raise "Unsupported platform" end sys-proctable-sys-proctable-1.3.0/lib/sys/proctable/000077500000000000000000000000001435233620100224255ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/sys/proctable/version.rb000066400000000000000000000001631435233620100244370ustar00rootroot00000000000000module Sys class ProcTable # The version of the sys-proctable library VERSION = '1.3.0'.freeze end end sys-proctable-sys-proctable-1.3.0/lib/sys/top.rb000066400000000000000000000022031435233620100215760ustar00rootroot00000000000000require 'sys/proctable' # The Sys module serves as a namespace only module Sys # The Top class serves as a toplevel name for the 'top' method. class Top # The version of the sys-top library VERSION = '1.0.5'.freeze # Returns an array of Struct::ProcTableStruct elements containing up # to +num+ elements, sorted by +field+. The default number of elements # is 10, while the default field is 'pctcpu'. # # Exception: the default sort field is 'pid' on AIX, Darwin and Windows. # def self.top(num = 10, field = 'pctcpu') field = field.to_s if field.is_a?(Symbol) aix = RbConfig::CONFIG['host_os'] =~ /aix/i darwin = RbConfig::CONFIG['host_os'] =~ /darwin/i dragonfly = RbConfig::CONFIG['host_os'] =~ /dragonfly/i # Sort by pid on Windows and AIX by default if (File::ALT_SEPARATOR || aix || darwin) && field == 'pctcpu' field = 'pid' end if dragonfly && field == 'pctcpu' Sys::ProcTable.ps.sort_by{ |obj| obj.lwp.pctcpu }[0..num-1] else Sys::ProcTable.ps.sort_by{ |obj| obj.send(field) || '' }[0..num-1] end end end end sys-proctable-sys-proctable-1.3.0/lib/windows/000077500000000000000000000000001435233620100213265ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/windows/sys/000077500000000000000000000000001435233620100221445ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/lib/windows/sys/proctable.rb000066400000000000000000000144331435233620100244510ustar00rootroot00000000000000# frozen_string_literal: true require 'win32ole' require 'socket' require 'date' require 'sys/proctable/version' # The Sys module serves as a namespace only module Sys # The ProcTable class encapsulates process table information class ProcTable # There is no constructor private_class_method :new # Error typically raised if one of the Sys::ProcTable methods fails class Error < StandardError; end # The comm field corresponds to the 'name' field. The 'cmdline' field # is the CommandLine attribute on Windows XP or later, or the # 'executable_path' field on Windows 2000 or earlier. # @fields = %w[ caption cmdline comm creation_class_name creation_date cs_creation_class_name cs_name description executable_path execution_state handle handle_count install_date kernel_mode_time maximum_working_set_size minimum_working_set_size name os_creation_class_name os_name other_operation_count other_transfer_count page_faults page_file_usage ppid peak_page_file_usage peak_virtual_size peak_working_set_size priority private_page_count pid quota_non_paged_pool_usage quota_paged_pool_usage quota_peak_non_paged_pool_usage quota_peak_paged_pool_usage read_operation_count read_transfer_count session_id status termination_date thread_count user_mode_time virtual_size windows_version working_set_size write_operation_count write_transfer_count ] ProcTableStruct = Struct.new("ProcTableStruct", *@fields) # 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. # class << self attr_reader :fields end # 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+. # def self.ps(**kwargs) pid = kwargs[:pid] host = kwargs[:host] || Socket.gethostname if pid && !pid.is_a?(Numeric) raise TypeError end array = block_given? ? nil : [] struct = nil begin wmi = WIN32OLE.connect("winmgmts://#{host}/root/cimv2") rescue WIN32OLERuntimeError => err raise Error, err # Re-raise as ProcTable::Error else wmi.InstancesOf("Win32_Process").each do |wproc| if pid && wproc.ProcessId != pid next end # Some fields are added later, and so are nil initially struct = ProcTableStruct.new( wproc.Caption, nil, # Added later, based on OS version wproc.Name, wproc.CreationClassName, parse_ms_date(wproc.CreationDate), wproc.CSCreationClassName, wproc.CSName, wproc.Description, wproc.ExecutablePath, wproc.ExecutionState, wproc.Handle, wproc.HandleCount, parse_ms_date(wproc.InstallDate), convert(wproc.KernelModeTime), wproc.MaximumWorkingSetSize, wproc.MinimumWorkingSetSize, wproc.Name, wproc.OSCreationClassName, wproc.OSName, convert(wproc.OtherOperationCount), convert(wproc.OtherTransferCount), wproc.PageFaults, wproc.PageFileUsage, wproc.ParentProcessId, convert(wproc.PeakPageFileUsage), convert(wproc.PeakVirtualSize), convert(wproc.PeakWorkingSetSize), wproc.Priority, convert(wproc.PrivatePageCount), wproc.ProcessId, wproc.QuotaNonPagedPoolUsage, wproc.QuotaPagedPoolUsage, wproc.QuotaPeakNonPagedPoolUsage, wproc.QuotaPeakPagedPoolUsage, convert(wproc.ReadOperationCount), convert(wproc.ReadTransferCount), wproc.SessionId, wproc.Status, parse_ms_date(wproc.TerminationDate), wproc.ThreadCount, convert(wproc.UserModeTime), convert(wproc.VirtualSize), wproc.WindowsVersion, convert(wproc.WorkingSetSize), convert(wproc.WriteOperationCount), convert(wproc.WriteTransferCount) ) ############################################################### # On Windows XP or later, set the cmdline to the CommandLine # attribute. Otherwise, set it to the ExecutablePath # attribute. ############################################################### if wproc.WindowsVersion.to_f < 5.1 struct.cmdline = wproc.ExecutablePath else struct.cmdline = wproc.CommandLine end struct.freeze # This is read-only data if block_given? yield struct else array << struct end end end pid ? struct : array end ####################################################################### # Converts a string in the format '20040703074625.015625-360' into a # Ruby Time object. ####################################################################### def self.parse_ms_date(str) return if str.nil? DateTime.parse(str) end private_class_method :parse_ms_date ##################################################################### # There is a bug in win32ole where uint64 types are returned as a # String instead of a Fixnum. This method deals with that for now. ##################################################################### def self.convert(str) return nil if str.nil? # Return nil, not 0 str.to_i end private_class_method :convert end end sys-proctable-sys-proctable-1.3.0/spec/000077500000000000000000000000001435233620100200205ustar00rootroot00000000000000sys-proctable-sys-proctable-1.3.0/spec/spec_helper.rb000066400000000000000000000015141435233620100226370ustar00rootroot00000000000000require 'rspec' require 'sys-proctable' require 'sys-top' RSpec.configure do |config| config.filter_run_excluding(:aix) unless RbConfig::CONFIG['host_os'] =~ /aix/i config.filter_run_excluding(:darwin) unless RbConfig::CONFIG['host_os'] =~ /mac|darwin/i config.filter_run_excluding(:linux) unless RbConfig::CONFIG['host_os'] =~ /linux/i config.filter_run_excluding(:bsd) unless RbConfig::CONFIG['host_os'] =~ /bsd|dragonfly/i config.filter_run_excluding(:freebsd) unless RbConfig::CONFIG['host_os'] =~ /freebsd/i config.filter_run_excluding(:dragonfly) unless RbConfig::CONFIG['host_os'] =~ /dragonfly/i config.filter_run_excluding(:sunos) unless RbConfig::CONFIG['host_os'] =~ /sunos|solaris/i config.filter_run_excluding(:windows) unless Gem.win_platform? config.filter_run_excluding(:jruby) if RUBY_PLATFORM == 'java' end sys-proctable-sys-proctable-1.3.0/spec/sys_proctable_aix_spec.rb000066400000000000000000000252411435233620100250750ustar00rootroot00000000000000####################################################################### # sys_proctable_aix_spec.rb # # Test suite for the AIX version of the sys-proctable library. You # should run these tests via the 'rake spec' task. ####################################################################### require 'spec_helper' RSpec.describe Sys::ProcTable, :aix do let(:fields){ %w[ addr argc argv bindpro cid clname cmd_args cmdline cwd egid environ envp euid fd flag flag2 fname gid lwpid map nice nlwp onpro pgid pid policy ppid pri psargs ptid rssize sid size sname start state time ttydev uid wchan wtype s_ttydev ] } let(:map_fields){ %w[size vaddr mapname off mflags pathoff alias gp s_mflags path] } before(:all) do File.open('aix-child.rb', 'w') do |out| out.puts 'trap("HUP") { exit }' out.puts 'trap("TERM") { exit }' out.puts 'sleep(60)' end @myenv = ENV.to_hash @p1args = %w[aix-child.rb testing how well this works 1] @p2args = %w[aix-child.rb testing how well this works 2] @pid1 = fork do exec('ruby', *@p1args) end @pid2 = fork do exec('ruby', *@p2args) end sleep(2) # wait to make sure the above execs have completed in children @p1info = ProcTable.ps(@pid1) @p2info = ProcTable.ps.select { |e| e.pid == @pid2 } if @p2info.size == 1 @p2info = @p2info[0] else $stderr.puts "expected a single process, have #{@p2info.size}" exit 1 end end after(:all) do Process.kill('TERM', @pid1) Process.kill('TERM', @pid2) File.unlink('aix-child.rb') rescue nil end context 'fields singleton method' do it 'responds to a fields method' do expect(described_class).to respond_to(:fields) end it 'returns the expected results for the fields method' do expect(described_class.fields).to be_kind_of(Array) expect(described_class.fields).to eql(fields) end end context 'ProcTable::Struct members' do it 'contains a flag member and returns the expected value' do expect(@p1info).to respond_to(:flag) expect(@p1info.flag).to be_kind_of(Integer) end it 'contains a flag2 member and returns the expected value' do expect(@p1info).to respond_to(:flag2) expect(@p1info.flag2).to be_kind_of(Integer) end it 'contains a nlwp member and returns the expected value' do expect(@p1info).to respond_to(:nlwp) expect(@p1info.nlwp).to be_kind_of(Integer) end it 'contains a uid member and returns the expected value' do expect(@p1info).to respond_to(:uid) expect(@p1info.uid).to be_kind_of(Integer) expect(@p1info.uid).to eql(Process.uid) end it 'contains a euid member and returns the expected value' do expect(@p1info).to respond_to(:euid) expect(@p1info.euid).to be_kind_of(Integer) expect(@p1info.euid).to eql(Process.euid) end it 'contains a gid member and returns the expected value' do expect(@p1info).to respond_to(:gid) expect(@p1info.gid).to be_kind_of(Integer) expect(@p1info.gid).to eql(Process.gid) end it 'contains a egid member and returns the expected value' do expect(@p1info).to respond_to(:egid) expect(@p1info.egid).to be_kind_of(Integer) expect(@p1info.egid).to eql(Process.egid) end it 'contains a pid member and returns the expected value' do expect(@p1info).to respond_to(:pid) expect(@p1info.pid).to be_kind_of(Integer) expect(@p1info.pid).to eql(@pid1) end it 'contains a ppid member and returns the expected value' do expect(@p1info).to respond_to(:ppid) expect(@p1info.ppid).to be_kind_of(Integer) expect(@p1info.ppid).to eql(Process.pid) end it 'contains a pgid member and returns the expected value' do expect(@p1info).to respond_to(:pgid) expect(@p1info.pgid).to be_kind_of(Integer) expect(@p1info.pgid).to eql(Process.getpgrp) end it 'contains a sid member and returns the expected value' do expect(@p1info).to respond_to(:sid) expect(@p1info.sid).to be_kind_of(Integer) end it 'contains a ttydev member and returns the expected value' do expect(@p1info).to respond_to(:ttydev) expect(@p1info.ttydev).to be_kind_of(Integer) end it 'contains a addr member and returns the expected value' do expect(@p1info).to respond_to(:addr) expect(@p1info.addr).to be_kind_of(Integer) end it 'contains a size member and returns the expected value' do expect(@p1info).to respond_to(:size) expect(@p1info.size).to be_kind_of(Integer) end it 'contains a rssize member and returns the expected value' do expect(@p1info).to respond_to(:rssize) expect(@p1info.rssize).to be_kind_of(Integer) end it 'contains a start member and returns the expected value' do expect(@p1info).to respond_to(:start) expect(@p1info.start).to be_kind_of(Time) end it 'contains a time member and returns the expected value' do expect(@p1info).to respond_to(:time) expect(@p1info.time).to be_kind_of(Time) end it 'contains a cid member and returns the expected value' do expect(@p1info).to respond_to(:cid) expect(@p1info.cid).to be_kind_of(Integer) end it 'contains an argc member and returns the expected value' do expect(@p1info).to respond_to(:argc) expect(@p1info.argc).to be_kind_of(Integer) expect(@p1info.argc).to eql(@p1args.size + 1) end it 'contains an argv member and returns the expected value' do expect(@p1info).to respond_to(:argv) expect(@p1info.argv).to be_kind_of(Integer) end it 'contains an envp member and returns the expected value' do expect(@p1info).to respond_to(:envp) expect(@p1info.envp).to be_kind_of(Integer) end it 'contains an fname member and returns the expected value' do expect(@p1info).to respond_to(:fname) expect(@p1info.fname).to be_kind_of(String) end it 'contains an psargs member and returns the expected value' do expect(@p1info).to respond_to(:psargs) expect(@p1info.psargs).to be_kind_of(String) end it 'contains an lwpid member and returns the expected value' do expect(@p1info).to respond_to(:lwpid) expect(@p1info.lwpid).to be_kind_of(Integer) end it 'contains a wchan member and returns the expected value' do expect(@p1info).to respond_to(:wchan) expect(@p1info.wchan).to be_kind_of(Integer) end it 'contains a wtype member and returns the expected value' do expect(@p1info).to respond_to(:wtype) expect(@p1info.wchan).to be_kind_of(Integer) end it 'contains a state member and returns the expected value' do expect(@p1info).to respond_to(:state) expect(@p1info.state).to be_kind_of(Integer) end it 'contains an sname member and returns the expected value' do expect(@p1info).to respond_to(:sname) expect(@p1info.sname).to be_kind_of(String) end it 'contains a nice member and returns the expected value' do expect(@p1info).to respond_to(:nice) expect(@p1info.nice).to be_kind_of(Integer) end it 'contains a pri member and returns the expected value' do expect(@p1info).to respond_to(:pri) expect(@p1info.pri).to be_kind_of(Integer) end it 'contains a policy member and returns the expected value' do expect(@p1info).to respond_to(:policy) expect(@p1info.policy).to be_kind_of(Integer) end it 'contains a clname member and returns the expected value' do expect(@p1info).to respond_to(:clname) expect(@p1info.clname).to be_kind_of(String) end it 'contains an onpro member and returns the expected value' do expect(@p1info).to respond_to(:onpro) expect(@p1info.onpro).to be_kind_of(Integer) end it 'contains a bindpro member and returns the expected value' do expect(@p1info).to respond_to(:bindpro) expect(@p1info.bindpro).to be_kind_of(Integer) end it 'contains a ptid member and returns the expected value' do expect(@p1info).to respond_to(:ptid) expect(@p1info.ptid).to be_kind_of(Integer) end it 'contains a comm member and returns the expected value' do expect(@p1info).to respond_to(:comm) expect(@p1info.comm).to be_kind_of(String) end it 'contains a fd member and returns the expected value' do expect(@p1info).to respond_to(:fd) expect(@p1info.fd).to be_kind_of(Array) end it 'contains a cmd_args member and returns the expected value' do expect(@p1info).to respond_to(:cmd_args) expect(@p1info.cmd_args).to be_kind_of(Array) expect(@p1info.cmd_args).to_eql(['ruby', @p1args].flatten) expect(@p2info).to respond_to(:cmd_args) expect(@p2info.cmd_args).to be_kind_of(Array) expect(@p2info.cmd_args).to_eql(['ruby', @p2args].flatten) end it 'contains an environ member and returns the expected value' do expect(@p1info).to respond_to(:environ) expect(@p1info.environ).to be_kind_of(Hash) expect(@p1info.environ).to eql(@myenv) expect(@p2info).to respond_to(:environ) expect(@p2info.environ).to be_kind_of(Hash) expect(@p2info.environ).to eql(@myenv) end it 'contains a cmdline member and returns the expected value' do expect(@p1info).to respond_to(:cmdline) expect(@p1info.cmdline).to be_kind_of(String) end it 'contains a cwd member and returns the expected value' do expect(@p1info).to respond_to(:cwd) expect(@p1info.cwd).to be_kind_of(String) if @p1info.cwd end it 'contains a map member and returns the expected value' do expect(@p1info).to respond_to(:map) expect(@p1info.map).to be_kind_of(Array) if @p1info.map end end context 'Struct::ProcTableMapStruct' do it 'contains the expected members' do expect(@p1info.map).to be_kind_of(Array) expect(map_fields.sort).to eql(@p1info.map[0].members.sort) end it 'has members of the expected type' do expect(@p1info.map).to be_kind_of(Array) p1info_map = @p1info.map expect(p1info_map).to be_kind_of(Struct::ProcTableMapStruct) expect(p1info_map.size).to be_kind_of(Integer) expect(p1info_map.vaddr).to be_kind_of(Integer) expect(p1info_map.mapname).to be_kind_of(String) expect(p1info_map.off).to be_kind_of(Integer) expect(p1info_map.mflags).to be_kind_of(Integer) expect(p1info_map.s_mflags).to be_kind_of(String) expect(p1info_map.pathoff).to be_kind_of(Integer) expect(p1info_map.alias).to be_kind_of(Integer) expect(p1info_map.gp).to be_kind_of(Integer) expect(p1info_map.path).to be_kind_of(String) end end end sys-proctable-sys-proctable-1.3.0/spec/sys_proctable_all_spec.rb000066400000000000000000000053241435233620100250640ustar00rootroot00000000000000####################################################################### # sys_proctable_all_spec.rb # # Test suite for methods common to all platforms. Generally speaking # you should run these specs using the 'rake spec' task. ####################################################################### require 'spec_helper' RSpec.describe 'common' do let(:windows) { File::ALT_SEPARATOR } before(:all) do @pid = Process.pid end context 'constants' do it 'has a VERSION constant set to the expected value' do expect(Sys::ProcTable::VERSION).to eql('1.3.0') expect(Sys::ProcTable::VERSION).to be_frozen end it 'defines a custom error class' do expect{ Sys::ProcTable::Error }.not_to raise_error expect(Sys::ProcTable::Error.new).to be_kind_of(StandardError) end end context 'fields' do it 'has a fields singleton method' do expect(Sys::ProcTable).to respond_to(:fields) end it 'returns the expected data type for the fields singleton method' do expect(Sys::ProcTable.fields).to be_kind_of(Array) expect(Sys::ProcTable.fields.first).to be_kind_of(String) end end context 'ps' do it 'defines a ps singleton method' do expect(Sys::ProcTable).to respond_to(:ps) end it 'allows a pid option as an argument' do expect{ Sys::ProcTable.ps(:pid => 0) }.not_to raise_error end it 'allows the pid to be nil' do expect{ Sys::ProcTable.ps(:pid => nil) }.not_to raise_error expect(Sys::ProcTable.ps(:pid => nil)).to be_kind_of(Array) end it 'returns expected results with no arguments' do expect(Sys::ProcTable.ps).to be_kind_of(Array) end it 'returns expected results with a pid argument' do expect(Sys::ProcTable.ps(:pid => @pid)).to be_kind_of(Struct::ProcTableStruct) end it 'returns nil if the process does not exist' do expect(Sys::ProcTable.ps(:pid => 999999999)).to be_nil end it 'returns nil in block form whether or not a pid was provided' do expect(Sys::ProcTable.ps{}).to be_nil expect(Sys::ProcTable.ps(:pid => 999999999){}).to be_nil end it 'returns frozen structs' do expect(Sys::ProcTable.ps.first.frozen?).to be(true) end it 'expects a numeric pid argument if present' do expect{ Sys::ProcTable.ps(:pid => 'vim') }.to raise_error(TypeError) end it 'accepts keyword arguments only' do expect{ Sys::ProcTable.ps(0, 'localhost') }.to raise_error(ArgumentError) end it 'disables the traditional constructor' do expect{ Sys::ProcTable.new }.to raise_error(NoMethodError) end it 'works within a thread' do expect{ Thread.new{ Sys::ProcTable.ps }.value }.not_to raise_error end end end sys-proctable-sys-proctable-1.3.0/spec/sys_proctable_bsd_spec.rb000066400000000000000000000213711435233620100250640ustar00rootroot00000000000000################################################################ # sys_proctable_bsd_rspec.rb # # Specs for BSD related operating systems for the sys-proctable # library. You should run these tests via the 'rake spec' task. ################################################################ require 'spec_helper' require 'mkmf-lite' RSpec.describe Sys::ProcTable, :bsd do let(:fields_freebsd){ %w[ pid ppid pgid tpgid sid tsid jobc uid ruid rgid ngroups groups size rssize swrss tsize dsize ssize xstat acflag pctcpu estcpu slptime swtime runtime start flag state nice lock rqindex oncpu lastcpu wmesg login lockname comm ttynum ttydev jid priority usrpri cmdline utime stime maxrss ixrss idrss isrss minflt majflt nswap inblock oublock msgsnd msgrcv nsignals nvcsw nivcsw ] } let(:fields_dragonfly){ %w[ paddr flags stat lock acflag traceflag fd siglist sigignore sigcatch sigflag start comm uid ngroups groups ruid svuid rgid svgid pid ppid pgid jobc sid login tdev tpgid tsid exitstat nthreads nice swtime vm_map_size vm_rssize vm_swrss vm_tsize vm_dsize vm_ssize vm_prssize jailid ru cru auxflags lwp ktaddr ] } context 'fields singleton method' do it 'responds to a fields method' do expect(described_class).to respond_to(:fields) end it 'returns the expected results for the fields method' do fields = RbConfig::CONFIG['host_os'] =~ /freebsd/i ? fields_freebsd : fields_dragonfly expect(described_class.fields).to be_kind_of(Array) expect(described_class.fields).to eql(fields) end end context 'ProcTable::Struct members' do subject(:process){ described_class.ps(:pid => Process.pid) } it 'contains a pid member and returns the expected value' do expect(process).to respond_to(:pid) expect(process.pid).to be_kind_of(Numeric) expect(process.pid).to eql(Process.pid) end it 'contains a ppid member and returns the expected value' do expect(process).to respond_to(:ppid) expect(process.ppid).to be_kind_of(Integer) end it 'contains a pgid member and returns the expected value' do expect(process).to respond_to(:pgid) expect(process.pgid).to be_kind_of(Integer) end it 'contains a ruid member and returns the expected value' do expect(process).to respond_to(:ruid) expect(process.ruid).to be_kind_of(Integer) end it 'contains a rgid member and returns the expected value' do expect(process).to respond_to(:rgid) expect(process.rgid).to be_kind_of(Integer) end it 'contains a comm member and returns the expected value' do expect(process).to respond_to(:comm) expect(process.comm).to be_kind_of(String) end it 'contains a state member and returns the expected value', :freebsd do expect(process).to respond_to(:state) expect(process.state).to be_kind_of(String) end it 'contains a pctcpu member and returns the expected value', :freebsd do expect(process).to respond_to(:pctcpu) expect(process.pctcpu).to be_kind_of(Float) end it 'contains a oncpu member and returns the expected value', :freebsd do expect(process).to respond_to(:oncpu) expect(process.oncpu).to be_kind_of(Integer) end it 'contains a ttynum member and returns the expected value', :freebsd do expect(process).to respond_to(:ttynum) expect(process.ttynum).to be_kind_of(Integer) end it 'contains a ttydev member and returns the expected value', :freebsd do expect(process).to respond_to(:ttydev) expect(process.ttydev).to be_kind_of(String) end it 'contains a wmesg member and returns the expected value', :freebsd do expect(process).to respond_to(:wmesg) expect(process.wmesg).to be_kind_of(String) end it 'contains a runtime member and returns the expected value', :freebsd do expect(process).to respond_to(:runtime) expect(process.runtime).to be_kind_of(Integer) end it 'contains a priority member and returns the expected value', :freebsd do expect(process).to respond_to(:priority) expect(process.priority).to be_kind_of(Integer) end it 'contains a usrpri member and returns the expected value', :freebsd do expect(process).to respond_to(:usrpri) expect(process.usrpri).to be_kind_of(Integer) end it 'contains a nice member and returns the expected value' do expect(process).to respond_to(:nice) expect(process.nice).to be_kind_of(Integer) end it 'contains a cmdline member and returns the expected value' do expect(process).to respond_to(:cmdline) expect(process.cmdline).to be_kind_of(String) end it 'contains a start member and returns the expected value' do expect(process).to respond_to(:start) expect(process.start).to be_kind_of(Time) end it 'contains a maxrss member and returns the expected value', :freebsd do expect(process).to respond_to(:maxrss) expect(process.maxrss).to be_kind_of(Integer) end it 'contains a ixrss member and returns the expected value', :freebsd do expect(process).to respond_to(:ixrss) expect(process.ixrss).to be_kind_of(Integer) end # TODO: The value returned on PC BSD 10 does not appear to be valid. Investigate. it 'contains a idrss member and returns the expected value', :freebsd do expect(process).to respond_to(:idrss) expect(process.idrss).to be_kind_of(Numeric) end it 'contains a isrss member and returns the expected value', :freebsd do expect(process).to respond_to(:isrss) expect(process.isrss).to be_kind_of(Integer) end it 'contains a minflt member and returns the expected value', :freebsd do expect(process).to respond_to(:minflt) expect(process.minflt).to be_kind_of(Integer) end it 'contains a majflt member and returns the expected value', :freebsd do expect(process).to respond_to(:majflt) expect(process.majflt).to be_kind_of(Integer) end it 'contains a nswap member and returns the expected value', :freebsd do expect(process).to respond_to(:nswap) expect(process.nswap).to be_kind_of(Integer) end it 'contains a inblock member and returns the expected value', :freebsd do expect(process).to respond_to(:inblock) expect(process.inblock).to be_kind_of(Integer) end it 'contains a oublock member and returns the expected value', :freebsd do expect(process).to respond_to(:oublock) expect(process.oublock).to be_kind_of(Integer) end it 'contains a msgsnd member and returns the expected value', :freebsd do expect(process).to respond_to(:msgsnd) expect(process.msgsnd).to be_kind_of(Integer) end it 'contains a msgrcv member and returns the expected value', :freebsd do expect(process).to respond_to(:msgrcv) expect(process.msgrcv).to be_kind_of(Integer) end it 'contains a nsignals member and returns the expected value', :freebsd do expect(process).to respond_to(:nsignals) expect(process.nsignals).to be_kind_of(Integer) end it 'contains a nvcsw member and returns the expected value', :freebsd do expect(process).to respond_to(:nvcsw) expect(process.nvcsw).to be_kind_of(Integer) end it 'contains a nivcsw member and returns the expected value', :freebsd do expect(process).to respond_to(:nivcsw) expect(process.nivcsw).to be_kind_of(Integer) end it 'contains a utime member and returns the expected value', :freebsd do expect(process).to respond_to(:utime) expect(process.utime).to be_kind_of(Integer) end it 'contains a stime member and returns the expected value', :freebsd do expect(process).to respond_to(:stime) expect(process.stime).to be_kind_of(Integer) end end context 'C struct verification' do let(:dummy){ Class.new{ extend Mkmf::Lite } } it 'has a timeval struct of the expected size' do expect(Sys::ProcTableStructs::Timeval.size).to eq(dummy.check_sizeof('struct timeval', 'sys/time.h')) end it 'has an rtprio struct of the expected size' do expect(Sys::ProcTableStructs::RTPrio.size).to eq(dummy.check_sizeof('struct rtprio', 'sys/rtprio.h')) end it 'has an rusage struct of the expected size' do expect(Sys::ProcTableStructs::Rusage.size).to eq(dummy.check_sizeof('struct rusage', 'sys/resource.h')) end it 'has an kinfo_lwp struct of the expected size' do expect(Sys::ProcTableStructs::KInfoLWP.size).to eq(dummy.check_sizeof('struct kinfo_lwp', 'sys/kinfo.h')) end it 'has an kinfo_proc struct of the expected size' do expect(Sys::ProcTableStructs::KInfoProc.size).to eq(dummy.check_sizeof('struct kinfo_proc', 'sys/kinfo.h')) end end end sys-proctable-sys-proctable-1.3.0/spec/sys_proctable_darwin_spec.rb000066400000000000000000000131461435233620100256010ustar00rootroot00000000000000######################################################################## # sys_proctable_darwin_spec.rb # # Test suite for the Darwin version of the sys-proctable library. You # should run these tests via the 'rake test' task. ######################################################################## require 'spec_helper' RSpec.describe Sys::ProcTable, :darwin do let(:fields){ %w[ flags status xstatus pid ppid uid gid ruid rgid svuid svgid rfu1 comm name nfiles pgid pjobc tdev tpgid nice start_tvsec start_tvusec virtual_size resident_size total_user total_system threads_user threads_system policy faults pageins cow_faults messages_sent messages_received syscalls_mach syscalls_unix csw threadnum numrunning priority cmdline exe environ threadinfo ] } before(:all) do @pid1 = Process.spawn({'A' => 'B', 'Z' => nil}, 'sleep 60') @pid2 = Process.spawn('ruby', '-Ilib', '-e', "sleep \'120\'.to_i", '--', 'foo bar') sleep 1 # wait to make sure env is replaced by sleep end after(:all) do Process.kill('TERM', @pid1) Process.kill('TERM', @pid2) end context 'fields singleton method' do it 'responds to a fields method' do expect(described_class).to respond_to(:fields) end it 'returns the expected results for the fields method' do expect(described_class.fields).to be_kind_of(Array) expect(described_class.fields).to eq(fields) end end context 'ProcTable::Struct members' do subject(:process){ described_class.ps(:pid => @pid1) } it 'contains a pid member and returns the expected value' do expect(process).to respond_to(:pid) expect(process.pid).to be_kind_of(Numeric) expect(process.pid).to eq(@pid1) end it 'contains a ppid member and returns the expected value' do expect(process).to respond_to(:ppid) expect(process.ppid).to be_kind_of(Numeric) expect(process.ppid).to eq(Process.pid) end it 'contains a pgid member and returns the expected value' do expect(process).to respond_to(:pgid) expect(process.pgid).to be_kind_of(Numeric) expect(process.pgid).to eq(Process.getpgrp) end it 'contains a ruid member and returns the expected value' do expect(process).to respond_to(:ruid) expect(process.ruid).to be_kind_of(Numeric) expect(process.ruid).to eq(Process.uid) end it 'contains an rgid member and returns the expected value' do expect(process).to respond_to(:rgid) expect(process.rgid).to be_kind_of(Numeric) expect(process.rgid).to eq(Process.gid) end it 'contains an svuid member and returns the expected value' do expect(process).to respond_to(:svuid) expect(process.svuid).to be_kind_of(Numeric) expect(process.svuid).to eq(Process.uid) end it 'contains an svgid member and returns the expected value' do expect(process).to respond_to(:svgid) expect(process.svgid).to be_kind_of(Numeric) expect(process.svgid).to eq(Process.gid) end it 'contains a comm member and returns the expected value' do expect(process).to respond_to(:comm) expect(process.comm).to be_kind_of(String) expect(process.comm).to eq('sleep') end it 'contains a cmdline member and returns the expected value' do expect(process).to respond_to(:cmdline) expect(process.cmdline).to be_kind_of(String) expect(process.cmdline).to eq('sleep 60') end it 'returns a string with the expected arguments for the cmdline member', :skip => :jruby do ptable = Sys::ProcTable.ps(:pid => @pid2) expect(ptable.cmdline).to eq('ruby -Ilib -e sleep \'120\'.to_i -- foo bar') end it 'contains an exe member and returns the expected value' do expect(process).to respond_to(:exe) expect(process.exe).to be_kind_of(String) expect(process.exe).to eq(`which sleep`.chomp) end it 'contains an environ member and returns the expected value' do skip 'It appears to no longer be possible to get environ on spawned processes on Catalina or later in most cases' expect(process).to respond_to(:environ) expect(process.environ).to be_kind_of(Hash) expect(process.environ['A']).to eq('B') expect(process.environ['Z']).to be_nil end end context 'private constants' do it 'makes FFI methods private' do expect(described_class).not_to respond_to(:sysctl) expect(described_class).not_to respond_to(:proc_listallpids) expect(described_class).not_to respond_to(:proc_pidinfo) end it 'makes FFI structs private' do expect(described_class.constants).not_to include(:ProcBsdInfo) expect(described_class.constants).not_to include(:ProcThreadInfo) expect(described_class.constants).not_to include(:ProcTaskInfo) expect(described_class.constants).not_to include(:ProcTaskAllInfo) end it 'makes internal constants private' do expect(described_class.constants).not_to include(:PROC_PIDTASKALLINFO) expect(described_class.constants).not_to include(:PROC_PIDTHREADINFO) expect(described_class.constants).not_to include(:PROC_PIDLISTTHREADS) expect(described_class.constants).not_to include(:CTL_KERN) expect(described_class.constants).not_to include(:KERN_PROCARGS) expect(described_class.constants).not_to include(:KERN_PROCARGS2) expect(described_class.constants).not_to include(:MAX_COMLEN) expect(described_class.constants).not_to include(:MAX_PATHLEN) expect(described_class.constants).not_to include(:MAXTHREADNAMESIZE) expect(described_class.constants).not_to include(:PROC_PIDPATHINFO_MAXSIZE) end end end sys-proctable-sys-proctable-1.3.0/spec/sys_proctable_linux_spec.rb000066400000000000000000000275561435233620100254660ustar00rootroot00000000000000# frozen_string_literal: true ####################################################################### # sys_proctable_linux_spec.rb # # Test suite for the Linux version of the sys-proctable library. You # should run these tests via the 'rake spec' task. ####################################################################### require 'spec_helper' RSpec.describe Sys::ProcTable, :linux do let(:fields){ %w[ cmdline cwd environ exe fd root pid name uid euid gid egid comm state ppid pgrp session tty_nr tpgid flags minflt cminflt majflt cmajflt utime stime cutime cstime priority nice num_threads itrealvalue starttime vsize rss rlim rsslim startcode endcode startstack kstkesp kstkeip signal blocked sigignore sigcatch wchan nswap cnswap exit_signal processor rt_priority policy delayacct_blkio_ticks guest_time cguest_time pctcpu pctmem nlwp cgroup smaps ] } before(:context) do @subject ||= described_class.ps.last end context 'struct members' do it 'contains a cmdline member and returns the expected value' do expect(@subject).to respond_to(:cmdline) expect(@subject.cmdline).to be_kind_of(String) end it 'contains a cwd member and returns the expected value' do expect(@subject).to respond_to(:cwd) expect(@subject.cwd).to be_kind_of(String) if @subject.cwd end it 'contains a environ member and returns the expected value' do expect(@subject).to respond_to(:environ) expect(@subject.environ).to be_kind_of(Hash) end it 'contains an exe member and returns the expected value' do expect(@subject).to respond_to(:exe) expect(@subject.exe).to be_kind_of(String) if @subject.exe end it 'contains an fd member and returns the expected value' do expect(@subject).to respond_to(:fd) expect(@subject.fd).to be_kind_of(Hash) end it 'contains a root member and returns the expected value' do expect(@subject).to respond_to(:root) expect(@subject.root).to be_kind_of(String) if @subject.root end it 'contains a pid member and returns the expected value' do expect(@subject).to respond_to(:pid) expect(@subject.pid).to be_kind_of(Integer) end it 'contains a comm member and returns the expected value' do expect(@subject).to respond_to(:comm) expect(@subject.comm).to be_kind_of(String) end it 'contains a state member and returns the expected value' do expect(@subject).to respond_to(:state) expect(@subject.state).to be_kind_of(String) end it 'contains a ppid member and returns the expected value' do expect(@subject).to respond_to(:ppid) expect(@subject.ppid).to be_kind_of(Integer) end it 'contains a pgrp member and returns the expected value' do expect(@subject).to respond_to(:pgrp) expect(@subject.pgrp).to be_kind_of(Integer) end it 'contains a session member and returns the expected value' do expect(@subject).to respond_to(:session) expect(@subject.session).to be_kind_of(Integer) end it 'contains a tty_nr member and returns the expected value' do expect(@subject).to respond_to(:tty_nr) expect(@subject.tty_nr).to be_kind_of(Integer) end it 'contains a tpgid member and returns the expected value' do expect(@subject).to respond_to(:tpgid) expect(@subject.tpgid).to be_kind_of(Integer) end it 'contains a flags member and returns the expected value' do expect(@subject).to respond_to(:flags) expect(@subject.flags).to be_kind_of(Numeric) end it 'contains a minflt member and returns the expected value' do expect(@subject).to respond_to(:minflt) expect(@subject.minflt).to be_kind_of(Numeric) end it 'contains a cminflt member and returns the expected value' do expect(@subject).to respond_to(:cminflt) expect(@subject.cminflt).to be_kind_of(Numeric) end it 'contains a majflt member and returns the expected value' do expect(@subject).to respond_to(:majflt) expect(@subject.majflt).to be_kind_of(Numeric) end it 'contains a cmajflt member and returns the expected value' do expect(@subject).to respond_to(:cmajflt) expect(@subject.cmajflt).to be_kind_of(Numeric) end it 'contains a utime member and returns the expected value' do expect(@subject).to respond_to(:utime) expect(@subject.utime).to be_kind_of(Numeric) end it 'contains a stime member and returns the expected value' do expect(@subject).to respond_to(:stime) expect(@subject.stime).to be_kind_of(Numeric) end it 'contains a cutime member and returns the expected value' do expect(@subject).to respond_to(:cutime) expect(@subject.cutime).to be_kind_of(Numeric) end it 'contains a cstime member and returns the expected value' do expect(@subject).to respond_to(:cstime) expect(@subject.cstime).to be_kind_of(Numeric) end it 'contains a priority member and returns the expected value' do expect(@subject).to respond_to(:priority) expect(@subject.priority).to be_kind_of(Numeric) end it 'contains a nice member and returns the expected value' do expect(@subject).to respond_to(:nice) expect(@subject.nice).to be_kind_of(Numeric) end it 'contains a num_threads member and returns the expected value' do expect(@subject).to respond_to(:num_threads) expect(@subject.num_threads).to be_kind_of(Numeric) end it 'contains a itrealvalue member and returns the expected value' do expect(@subject).to respond_to(:itrealvalue) expect(@subject.itrealvalue).to be_kind_of(Numeric) end it 'contains a starttime member and returns the expected value' do expect(@subject).to respond_to(:starttime) expect(@subject.starttime).to be_kind_of(Numeric) end it 'contains a vsize member and returns the expected value' do expect(@subject).to respond_to(:vsize) expect(@subject.vsize).to be_kind_of(Numeric) end it 'contains a rss member and returns the expected value' do expect(@subject).to respond_to(:rss) expect(@subject.rss).to be_kind_of(Numeric) end it 'contains an rsslim member and returns the expected value' do expect(@subject).to respond_to(:rsslim) expect(@subject.rsslim).to be_kind_of(Numeric) expect(@subject.rsslim).to eq(@subject.rlim) end it 'contains an startcode member and returns the expected value' do expect(@subject).to respond_to(:startcode) expect(@subject.startcode).to be_kind_of(Numeric) end it 'contains an endcode member and returns the expected value' do expect(@subject).to respond_to(:endcode) expect(@subject.endcode).to be_kind_of(Numeric) end it 'contains a startstack member and returns the expected value' do expect(@subject).to respond_to(:startstack) expect(@subject.startstack).to be_kind_of(Integer) end it 'contains a kstkesp member and returns the expected value' do expect(@subject).to respond_to(:kstkesp) expect(@subject.kstkesp).to be_kind_of(Integer) end it 'contains a kstkeip member and returns the expected value' do expect(@subject).to respond_to(:kstkeip) expect(@subject.kstkeip).to be_kind_of(Integer) end it 'contains a signal member and returns the expected value' do expect(@subject).to respond_to(:signal) expect(@subject.signal).to be_kind_of(Integer) end it 'contains a blocked member and returns the expected value' do expect(@subject).to respond_to(:blocked) expect(@subject.blocked).to be_kind_of(Integer) end it 'contains a sigignore member and returns the expected value' do expect(@subject).to respond_to(:sigignore) expect(@subject.sigignore).to be_kind_of(Integer) end it 'contains a sigcatch member and returns the expected value' do expect(@subject).to respond_to(:sigcatch) expect(@subject.sigcatch).to be_kind_of(Integer) end it 'contains a wchan member and returns the expected value' do expect(@subject).to respond_to(:wchan) expect(@subject.wchan).to be_kind_of(Integer) end it 'contains a nswap member and returns the expected value' do expect(@subject).to respond_to(:nswap) expect(@subject.nswap).to be_kind_of(Integer) end it 'contains a cnswap member and returns the expected value' do expect(@subject).to respond_to(:cnswap) expect(@subject.cnswap).to be_kind_of(Integer) end it 'contains a exit_signal member and returns the expected value' do expect(@subject).to respond_to(:exit_signal) expect(@subject.exit_signal).to be_kind_of(Integer) end it 'contains a processor member and returns the expected value' do expect(@subject).to respond_to(:processor) expect(@subject.processor).to be_kind_of(Integer) end it 'contains a rt_priority member and returns the expected value' do expect(@subject).to respond_to(:rt_priority) expect(@subject.rt_priority).to be_kind_of(Integer) end it 'contains a policy member and returns the expected value' do expect(@subject).to respond_to(:policy) expect(@subject.policy).to be_kind_of(Integer) end it 'contains a delayacct_blkio_ticks member and returns the expected value' do expect(@subject).to respond_to(:delayacct_blkio_ticks) expect(@subject.delayacct_blkio_ticks).to be_kind_of(Integer) end it 'contains a guest_time member and returns the expected value' do expect(@subject).to respond_to(:guest_time) expect(@subject.guest_time).to be_kind_of(Integer) end it 'contains a cguest_time member and returns the expected value' do expect(@subject).to respond_to(:cguest_time) expect(@subject.cguest_time).to be_kind_of(Integer) end it 'contains a name member and returns the expected value' do expect(@subject).to respond_to(:name) expect(@subject.name).to be_kind_of(String) end it 'contains a uid member and returns the expected value' do expect(@subject).to respond_to(:uid) expect(@subject.uid).to be_kind_of(Integer) end it 'contains a euid member and returns the expected value' do expect(@subject).to respond_to(:euid) expect(@subject.euid).to be_kind_of(Integer) end it 'contains a gid member and returns the expected value' do expect(@subject).to respond_to(:gid) expect(@subject.gid).to be_kind_of(Integer) end it 'contains a egid member and returns the expected value' do expect(@subject).to respond_to(:egid) expect(@subject.egid).to be_kind_of(Integer) end it 'contains a pctmem member and returns the expected value' do expect(@subject).to respond_to(:pctmem) expect(@subject.pctmem).to be_kind_of(Float) end it 'contains a pctcpu member and returns the expected value' do expect(@subject).to respond_to(:pctcpu) expect(@subject.pctcpu).to be_kind_of(Float) end it 'contains a nlwp member and returns the expected value' do expect(@subject).to respond_to(:nlwp) expect(@subject.nlwp).to be_kind_of(Integer) end end context 'custom structs' do it 'contains a cgroup member and returns the expected value' do expect(@subject).to respond_to(:cgroup) expect(@subject.cgroup).to be_kind_of(Array) expect(@subject.cgroup.first).to be_kind_of(Sys::ProcTable::CgroupEntry) end it 'contains a smaps member and returns the expected value' do expect(@subject).to respond_to(:cgroup) expect(@subject.smaps).to be_kind_of(Sys::ProcTable::Smaps) end end context 'fields' do it 'has a fields method that returns the expected results' do expect(described_class).to respond_to(:fields) expect(described_class.fields).to be_kind_of(Array) expect(described_class.fields).to match_array(fields) end end end sys-proctable-sys-proctable-1.3.0/spec/sys_proctable_sunos_spec.rb000066400000000000000000000252121435233620100254610ustar00rootroot00000000000000####################################################################### # sys_proctable_sunos_spec.rb # # Test suite for sys-proctable for SunOS/Solaris. This should be run # run via the 'rake spec' task. ####################################################################### require 'spec_helper' RSpec.describe Sys::ProcTable, :sunos do let(:fields){ %w[ flag nlwp pid ppid pgid sid uid euid gid egid addr size rssize ttydev pctcpu pctmem start time ctime fname psargs wstat argc argv envp dmodel taskid projid nzomb poolid zoneid contract lwpid wchan stype state sname nice syscall pri clname name onpro bindpro bindpset count tstamp create term rtime utime stime ttime tftime dftime kftime ltime slptime wtime stoptime minf majf nswap inblk oublk msnd mrcv sigs vctx ictx sysc ioch path contracts fd cmd_args environ cmdline ] } context 'fields singleton method' do it 'responds to a fields method' do expect(described_class).to respond_to(:fields) end it 'returns the expected results for the fields method' do expect(described_class.fields).to be_kind_of(Array) expect(described_class.fields).to eql(fields) end end context 'ProcTable::Struct members' do subject(:process){ described_class.ps(:pid => Process.pid) } it 'contains a pid member and returns the expected value' do expect(process).to respond_to(:pid) expect(process.pid).to be_kind_of(Numeric) expect(process.pid).to eql(Process.pid) end it 'contains a ppid member and returns the expected value' do expect(process).to respond_to(:ppid) expect(process.ppid).to be_kind_of(Numeric) expect(process.ppid).to eql(Process.ppid) end it 'contains a pgid member and returns the expected value' do expect(process).to respond_to(:pgid) expect(process.pgid).to be_kind_of(Numeric) expect(process.pgid).to eql(Process.getpgrp) end it 'has a flag member that returns the expected value' do expect(process).to respond_to(:flag) expect(process.flag).to be_kind_of(Integer) end it 'has an nlwp member that returns the expected value' do expect(process).to respond_to(:nlwp) expect(process.nlwp).to be_kind_of(Integer) expect(process.nlwp).to be >= 0 end it 'has a sid member that returns the expected value' do expect(process).to respond_to(:sid) expect(process.sid).to be_kind_of(Integer) expect(process.sid).to be >= 0 end it 'has a uid member that returns the expected value' do expect(process).to respond_to(:uid) expect(process.uid).to be_kind_of(Integer) expect(process.uid).to eql(Process.uid) end it 'has a euid member that returns the expected value' do expect(process).to respond_to(:euid) expect(process.euid).to be_kind_of(Integer) expect(process.euid).to eql(Process.euid) end it 'has a gid member that returns the expected value' do expect(process).to respond_to(:gid) expect(process.gid).to be_kind_of(Integer) expect(process.gid).to eql(Process.gid) end it 'has a egid member that returns the expected value' do expect(process).to respond_to(:egid) expect(process.egid).to be_kind_of(Integer) expect(process.egid).to eql(Process.egid) end it 'has an addr member that returns the expected value' do expect(process).to respond_to(:addr) expect(process.addr).to be_kind_of(Integer) expect(process.addr).to be >= 0 end it 'has a size member that returns the expected value' do expect(process).to respond_to(:size) expect(process.size).to be_kind_of(Integer) expect(process.size).to be >= 0 end it 'has a rssize member that returns the expected value' do expect(process).to respond_to(:rssize) expect(process.rssize).to be_kind_of(Integer) expect(process.rssize).to be >= 0 end it 'has a ttydev member that returns the expected value' do expect(process).to respond_to(:ttydev) expect(process.ttydev).to be_kind_of(Integer) expect(process.ttydev).to be >= -1 end it 'has a pctcpu member that returns the expected value' do expect(process).to respond_to(:pctcpu) expect(process.pctcpu).to be_kind_of(Float) expect(process.pctcpu).to be >= 0.0 end it 'has a pctmem member that returns the expected value' do expect(process).to respond_to(:pctmem) expect(process.pctmem).to be_kind_of(Float) expect(process.pctmem).to be >= 0.0 end it 'has a start member that returns the expected value' do expect(process).to respond_to(:start) expect(process.start).to be_kind_of(Time) end it 'has a time member that returns the expected value' do expect(process).to respond_to(:time) expect(process.time).to be_kind_of(Integer) expect(process.time).to be >= 0 end it 'has a ctime member that returns the expected value' do expect(process).to respond_to(:ctime) expect(process.ctime).to be_kind_of(Integer) expect(process.ctime).to be >= 0 end it 'has a fname member that returns the expected value' do expect(process).to respond_to(:fname) expect(process.fname).to be_kind_of(String) expect(process.fname.size).to be > 0 end it 'has a comm alias member' do expect(process.method(:comm)).to eql(process.method(:fname)) end it 'has a psargs member that returns the expected value' do expect(process).to respond_to(:psargs) expect(process.psargs).to be_kind_of(String) expect(process.psargs.size).to be > 0 end it 'has a wstat member that returns the expected value' do expect(process).to respond_to(:wstat) expect(process.wstat).to be_kind_of(Integer) expect(process.wstat).to be >= 0 end it 'has an args member that returns the expected value' do expect(process).to respond_to(:argc) expect(process.argc).to be_kind_of(Integer) expect(process.argc).to be >= 0 end it 'has an argv member that returns the expected value' do expect(process).to respond_to(:argv) expect(process.argv).to be_kind_of(Integer) expect(process.argv).to be >= 0 end it 'has a envp member that returns the expected value' do expect(process).to respond_to(:envp) expect(process.envp).to be_kind_of(Integer) expect(process.envp).to be >= 0 end it 'has a dmodel member that returns the expected value' do expect(process).to respond_to(:dmodel) expect(process.dmodel).to be_kind_of(Integer) expect(process.dmodel).to be >= 0 end it 'has a taskid member that returns the expected value' do expect(process).to respond_to(:taskid) expect(process.taskid).to be_kind_of(Integer) expect(process.taskid).to be >= 0 end it 'has a projid member that returns the expected value' do expect(process).to respond_to(:projid) expect(process.projid).to be_kind_of(Integer) expect(process.projid).to be >= 0 end it 'has a nzomb member that returns the expected value' do expect(process).to respond_to(:nzomb) expect(process.nzomb).to be_kind_of(Integer) expect(process.nzomb).to be >= 0 end it 'has a poolid member that returns the expected value' do expect(process).to respond_to(:poolid) expect(process.poolid).to be_kind_of(Integer) expect(process.poolid).to be >= 0 end it 'has a zoneid member that returns the expected value' do expect(process).to respond_to(:zoneid) expect(process.zoneid).to be_kind_of(Integer) expect(process.zoneid).to be >= 0 end it 'has a contract member that returns the expected value' do expect(process).to respond_to(:contract) expect(process.contract).to be_kind_of(Integer) expect(process.contract).to be >= 0 end end context 'lwpsinfo struct' do process { described_class.ps(:pid => Process.pid) } it 'has a lwpid member that returns the expected value' do expect(process).to respond_to(:lwpid) expect(process.lwpid).to be_kind_of(Integer) expect(process.lwpid).to be >= 0 end it 'has a wchan member that returns the expected value' do expect(process).to respond_to(:wchan) expect(process.wchan).to be_kind_of(Integer) expect(process.wchan).to be >= 0 end it 'has a stype member that returns the expected value' do expect(process).to respond_to(:stype) expect(process.stype).to be_kind_of(Integer) expect(process.stype).to be >= 0 end it 'has a state member that returns the expected value' do expect(process).to respond_to(:state) expect(process.state).to be_kind_of(Integer) expect(process.state).to be >= 0 end it 'has a sname member that returns the expected value' do expect(process).to respond_to(:sname) expect(process.sname).to be_kind_of(String) expect(%w[S R Z T I O]).to include(process.sname) end it 'has a nice member that returns the expected value' do expect(process).to respond_to(:nice) expect(process.nice).to be_kind_of(Integer) expect(process.nice).to be >= 0 end it 'has a syscall member that returns the expected value' do expect(process).to respond_to(:syscall) expect(process.syscall).to be_kind_of(Integer) expect(process.syscall).to be >= 0 end it 'has a pri member that returns the expected value' do expect(process).to respond_to(:pri) expect(process.pri).to be_kind_of(Integer) expect(process.pri).to be >= 0 end it 'has a clname member that returns the expected value' do expect(process).to respond_to(:clname) expect(process.clname).to be_kind_of(String) expect(process.clname.size).to be_between(0, 8) end it 'has a name member that returns the expected value' do expect(process).to respond_to(:name) expect(process.name).to be_kind_of(String) expect(process.name.size).to be_between(0, 16) end it 'has an onpro member that returns the expected value' do expect(process).to respond_to(:onpro) expect(process.onpro).to be_kind_of(Integer) expect(process.onpro).to be >= 0 end it 'has a bindpro member that returns the expected value' do expect(process).to respond_to(:bindpro) expect(process.bindpro).to be_kind_of(Integer) expect(process.bindpro).to be >= -1 end it 'has a bindpset member that returns the expected value' do expect(process).to respond_to(:bindpset) expect(process.bindpset).to be_kind_of(Integer) expect(process.bindpset).to be >= -1 end end end sys-proctable-sys-proctable-1.3.0/spec/sys_proctable_windows_spec.rb000066400000000000000000000265561435233620100260200ustar00rootroot00000000000000# frozen_string_literal: true ############################################################################ # sys_proctable_windows_spec.rb # # Test suite for the sys-proctable library for MS Windows. This should be # run via the 'rake spec' task. ############################################################################ require 'spec_helper' require 'socket' RSpec.describe Sys::ProcTable, :windows do let(:hostname) { Socket.gethostname } let(:fields) { %w[ caption cmdline comm creation_class_name creation_date cs_creation_class_name cs_name description executable_path execution_state handle handle_count install_date kernel_mode_time maximum_working_set_size minimum_working_set_size name os_creation_class_name os_name other_operation_count other_transfer_count page_faults page_file_usage ppid peak_page_file_usage peak_virtual_size peak_working_set_size priority private_page_count pid quota_non_paged_pool_usage quota_paged_pool_usage quota_peak_non_paged_pool_usage quota_peak_paged_pool_usage read_operation_count read_transfer_count session_id status termination_date thread_count user_mode_time virtual_size windows_version working_set_size write_operation_count write_transfer_count ] } context 'fields' do it 'responds to a fields method' do expect(described_class).to respond_to(:fields) end it 'returns the expected results for the fields method' do expect(described_class.fields).to be_kind_of(Array) expect(described_class.fields).to eql(fields) end end context 'ps' do it 'accepts an optional host' do expect{ described_class.ps(:host => hostname) }.not_to raise_error end it 'ignores unused options' do expect{ described_class.ps(:smaps => false) }.not_to raise_error end end context 'ProcTable::Struct members' do subject(:process){ described_class.ps.first } it 'has a write_transfer_count struct member with the expected data type' do expect(process).to respond_to(:write_transfer_count) expect(process.write_transfer_count).to be_kind_of(Integer) end it 'has a write_operation_count struct member with the expected data type' do expect(process).to respond_to(:write_operation_count) expect(process.write_operation_count).to be_kind_of(Integer) end it 'has a working_set_size struct member with the expected data type' do expect(process).to respond_to(:working_set_size) expect(process.working_set_size).to be_kind_of(Integer) end it 'has a windows_version struct member with the expected data type' do expect(process).to respond_to(:windows_version) expect(process.windows_version).to be_kind_of(String) end it 'has a virtual_size struct member with the expected data type' do expect(process).to respond_to(:virtual_size) expect(process.virtual_size).to be_kind_of(Integer) end it 'has a user_mode_time struct member with the expected data type' do expect(process).to respond_to(:user_mode_time) expect(process.user_mode_time).to be_kind_of(Integer) end it 'has a thread_count struct member with the expected data type' do expect(process).to respond_to(:thread_count) expect(process.thread_count).to be_kind_of(Integer) end it 'has a termination_date struct member with the expected data type' do expect(process).to respond_to(:termination_date) expect(process.termination_date).to be_kind_of(Date) if process.termination_date end it 'has a status struct member with the expected data type' do expect(process).to respond_to(:status) expect(process.status).to be_nil # Always nil according to MSDN end it 'has a session_id struct member with the expected data type' do expect(process).to respond_to(:session_id) expect(process.session_id).to be_kind_of(Integer) end it 'has a read_transfer_count struct member with the expected data type' do expect(process).to respond_to(:read_transfer_count) expect(process.read_transfer_count).to be_kind_of(Integer) end it 'has a read_operation_count struct member with the expected data type' do expect(process).to respond_to(:read_operation_count) expect(process.read_operation_count).to be_kind_of(Integer) end it 'has a quota_peak_paged_pool_usage struct member with the expected data type' do expect(process).to respond_to(:quota_peak_paged_pool_usage) expect(process.quota_peak_paged_pool_usage).to be_kind_of(Integer) end it 'has a quota_peak_non_paged_pool_usage struct member with the expected data type' do expect(process).to respond_to(:quota_peak_non_paged_pool_usage) expect(process.quota_peak_non_paged_pool_usage).to be_kind_of(Integer) end it 'has a quota_paged_pool_usage struct member with the expected data type' do expect(process).to respond_to(:quota_paged_pool_usage) expect(process.quota_paged_pool_usage).to be_kind_of(Integer) end it 'has a quota_non_paged_pool_usage struct member with the expected data type' do expect(process).to respond_to(:quota_non_paged_pool_usage) expect(process.quota_non_paged_pool_usage).to be_kind_of(Integer) end it 'has a pid struct member with the expected data type' do expect(process).to respond_to(:pid) expect(process.pid).to be_kind_of(Integer) end it 'has a private_page_count struct member with the expected data type' do expect(process).to respond_to(:private_page_count) expect(process.private_page_count).to be_kind_of(Integer) end it 'has a priority struct member with the expected data type' do expect(process).to respond_to(:priority) expect(process.priority).to be_kind_of(Integer) end it 'has a peak_working_set_size struct member with the expected data type' do expect(process).to respond_to(:peak_working_set_size) expect(process.peak_working_set_size).to be_kind_of(Integer) end it 'has a peak_virtual_size struct member with the expected data type' do expect(process).to respond_to(:peak_virtual_size) expect(process.peak_virtual_size).to be_kind_of(Integer) end it 'has a peak_page_file_usage struct member with the expected data type' do expect(process).to respond_to(:peak_page_file_usage) expect(process.peak_page_file_usage).to be_kind_of(Integer) end it 'has a ppid struct member with the expected data type' do expect(process).to respond_to(:ppid) expect(process.ppid).to be_kind_of(Integer) end it 'has a page_file_usage struct member with the expected data type' do expect(process).to respond_to(:page_file_usage) expect(process.page_file_usage).to be_kind_of(Integer) end it 'has a page_faults struct member with the expected data type' do expect(process).to respond_to(:page_faults) expect(process.page_faults).to be_kind_of(Integer) end it 'has a other_transfer_count struct member with the expected data type' do expect(process).to respond_to(:other_transfer_count) expect(process.other_transfer_count).to be_kind_of(Integer) end it 'has a other_operation_count struct member with the expected data type' do expect(process).to respond_to(:other_operation_count) expect(process.other_operation_count).to be_kind_of(Integer) end it 'has a os_name struct member with the expected data type' do expect(process).to respond_to(:os_name) expect(process.os_name).to be_kind_of(String) end it 'has a os_creation_class_name struct member with the expected data type' do expect(process).to respond_to(:os_creation_class_name) expect(process.os_creation_class_name).to be_kind_of(String) end it 'has a name struct member with the expected data type' do expect(process).to respond_to(:name) expect(process.name).to be_kind_of(String) end it 'has a minimum_working_set_size struct member with the expected data type' do expect(process).to respond_to(:minimum_working_set_size) expect(process.minimum_working_set_size).to be_kind_of(Integer) if process.minimum_working_set_size end it 'has a maximum_working_set_size struct member with the expected data type' do expect(process).to respond_to(:maximum_working_set_size) expect(process.maximum_working_set_size).to be_kind_of(Integer) if process.maximum_working_set_size end it 'has a kernel_mode_time struct member with the expected data type' do expect(process).to respond_to(:kernel_mode_time) expect(process.kernel_mode_time).to be_kind_of(Integer) end it 'has a install_date struct member with the expected data type' do expect(process).to respond_to(:install_date) expect(process.install_date).to be_kind_of(Date) if process.install_date end it 'has a handle_count struct member with the expected data type' do expect(process).to respond_to(:handle_count) expect(process.handle_count).to be_kind_of(Integer) end it 'has a handle struct member with the expected data type' do expect(process).to respond_to(:handle) expect(process.handle).to be_kind_of(String) end it 'has a execution_state struct member with the expected data type' do expect(process).to respond_to(:execution_state) expect(process.execution_state).to be_nil end it 'has a executable_path struct member with the expected data type' do expect(process).to respond_to(:executable_path) expect(process.executable_path).to be_kind_of(String) if process.executable_path end it 'has a description struct member with the expected data type' do expect(process).to respond_to(:description) expect(process.description).to be_kind_of(String) end it 'has a cs_name struct member with the expected data type' do expect(process).to respond_to(:cs_name) expect(process.cs_name).to be_kind_of(String) end it 'has a cs_creation_class_name struct member with the expected data type' do expect(process).to respond_to(:cs_creation_class_name) expect(process.cs_creation_class_name).to be_kind_of(String) end it 'has a creation_date struct member with the expected data type' do expect(process).to respond_to(:creation_date) expect(process.creation_date).to be_kind_of(Date) if process.creation_date end it 'has a creation_class_name struct member with the expected data type' do expect(process).to respond_to(:creation_class_name) expect(process.creation_class_name).to be_kind_of(String) end it 'has a comm struct member with the expected data type' do expect(process).to respond_to(:comm) expect(process.comm).to be_kind_of(String) end it 'has a cmdline struct member with the expected data type' do expect(process).to respond_to(:cmdline) expect(process.cmdline).to be_kind_of(String) if process.cmdline end it 'has a caption struct member with the expected data type' do expect(process).to respond_to(:caption) expect(process.caption).to be_kind_of(String) end end end sys-proctable-sys-proctable-1.3.0/spec/sys_top_spec.rb000066400000000000000000000027701435233620100230650ustar00rootroot00000000000000############################################################################## # sys_top_spec.rb # # Test suite for the sys-top library that is included with this distribution. ############################################################################## require 'spec_helper' RSpec.describe Sys::Top do context 'constants' do it 'sets the version to the expected value' do expect(Sys::Top::VERSION).to eql('1.0.5') end end context 'top' do it 'defines a top method' do expect(described_class).to respond_to(:top) end it 'returns an array' do expect(described_class.top).to be_kind_of(Array) end it 'works with no arguments' do expect{ described_class.top }.not_to raise_error end it 'accepts a maximum of two arguments' do expect{ described_class.top(1, 'foo', 2) }.to raise_error(ArgumentError) end it 'accepts optional arguments' do expect{ described_class.top(5) }.not_to raise_error expect{ described_class.top(5, 'cmdline') }.not_to raise_error end it 'returns the expected results with no arguments' do expect(described_class.top.size).to be(10) expect(described_class.top.first).to be_kind_of(Struct::ProcTableStruct) end it 'returns the expected result with a size argument' do expect(described_class.top(5).size).to be(5) end it 'returns the expected result with a size and sort_by argument' do expect(described_class.top(5, :cmdline).size).to be(5) end end end sys-proctable-sys-proctable-1.3.0/sys-proctable.gemspec000066400000000000000000000033361435233620100232270ustar00rootroot00000000000000require 'rubygems' require_relative 'lib/sys/proctable/version' Gem::Specification.new do |spec| spec.name = 'sys-proctable' spec.version = Sys::ProcTable::VERSION spec.author = 'Daniel J. Berger' spec.license = 'Apache-2.0' spec.email = 'djberg96@gmail.com' spec.homepage = 'http://github.com/djberg96/sys-proctable' spec.summary = 'An interface for providing process table information' spec.files = Dir['**/*'].reject{ |f| f.include?('git') } spec.test_files = Dir['spec/*.rb'] spec.cert_chain = ['certs/djberg96_pub.pem'] spec.add_dependency('ffi', '~> 1.1') spec.add_development_dependency('rspec', '~> 3.9') spec.add_development_dependency('rake') spec.add_development_dependency('rubocop') spec.add_development_dependency('rubocop-rspec') spec.add_development_dependency('mkmf-lite') spec.metadata = { 'homepage_uri' => 'https://github.com/djberg96/sys-proctable', 'bug_tracker_uri' => 'https://github.com/djberg96/sys-proctable/issues', 'changelog_uri' => 'https://github.com/djberg96/sys-proctable/blob/main/CHANGES.md', 'documentation_uri' => 'https://github.com/djberg96/sys-proctable/wiki', 'source_code_uri' => 'https://github.com/djberg96/sys-proctable', 'wiki_uri' => 'https://github.com/djberg96/sys-proctable/wiki', 'rubygems_mfa_required' => 'true' } spec.description = <<-EOF The sys-proctable library provides an interface for gathering information about processes on your system, i.e. the process table. Most major platforms are supported and, while different platforms may return different information, the external interface is identical across platforms. EOF end