зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset 99809c2e06ae since it wasn't supposed to get pushed. r=me
This commit is contained in:
Родитель
8368d36a52
Коммит
b6b0f69f65
|
@ -337,7 +337,7 @@ class DesktopUnittest(TestingMixin, MercurialScript, BlobUploadMixin, MozbaseMix
|
||||||
dirs = self.query_abs_dirs()
|
dirs = self.query_abs_dirs()
|
||||||
|
|
||||||
self.register_virtualenv_module(name='pip>=1.5')
|
self.register_virtualenv_module(name='pip>=1.5')
|
||||||
self.register_virtualenv_module('psutil==3.1.1', method='pip')
|
self.register_virtualenv_module('psutil==5.4.3', method='pip')
|
||||||
self.register_virtualenv_module(name='mock')
|
self.register_virtualenv_module(name='mock')
|
||||||
self.register_virtualenv_module(name='simplejson')
|
self.register_virtualenv_module(name='simplejson')
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ twisted==10.2.0
|
||||||
# websocket adapter for twisted, might be built into twisted someday
|
# websocket adapter for twisted, might be built into twisted someday
|
||||||
txws==0.9.1
|
txws==0.9.1
|
||||||
|
|
||||||
psutil==3.1.1
|
psutil==5.4.3
|
||||||
|
|
||||||
# needed by txws, but pypi doesn't know about it
|
# needed by txws, but pypi doesn't know about it
|
||||||
six==1.10.0
|
six==1.10.0
|
||||||
|
|
|
@ -20,6 +20,32 @@ C: Italy
|
||||||
E: g.rodola@gmail.com
|
E: g.rodola@gmail.com
|
||||||
W: http://grodola.blogspot.com/
|
W: http://grodola.blogspot.com/
|
||||||
|
|
||||||
|
Experts
|
||||||
|
=======
|
||||||
|
|
||||||
|
Github usernames of people to CC on github when in need of help.
|
||||||
|
|
||||||
|
- NetBSD:
|
||||||
|
- 0-wiz-0, Thomas Klausner
|
||||||
|
- ryoqun, Ryo Onodera
|
||||||
|
- OpenBSD:
|
||||||
|
- landryb, Landry Breuil
|
||||||
|
- FreeBSD:
|
||||||
|
- glebius, Gleb Smirnoff (#1013)
|
||||||
|
- sunpoet, Po-Chuan Hsieh (pkg maintainer, #1105)
|
||||||
|
- kostikbel, Konstantin Belousov (#1105)
|
||||||
|
- OSX:
|
||||||
|
- whitlockjc, Jeremy Whitlock
|
||||||
|
- Windows:
|
||||||
|
- mrjefftang, Jeff Tang
|
||||||
|
- wj32, Wen Jia Liu
|
||||||
|
- fbenkstein, Frank Benkstein
|
||||||
|
- SunOS:
|
||||||
|
- wiggin15, Arnon Yaari
|
||||||
|
- alxchk, Oleksii Shevchuk
|
||||||
|
- AIX:
|
||||||
|
- wiggin15, Arnon Yaari (maintainer)
|
||||||
|
|
||||||
Contributors
|
Contributors
|
||||||
============
|
============
|
||||||
|
|
||||||
|
@ -29,11 +55,24 @@ E: jloden@gmail.com
|
||||||
D: original co-author, initial design/bootstrap and occasional bug fixes
|
D: original co-author, initial design/bootstrap and occasional bug fixes
|
||||||
W: http://www.jayloden.com
|
W: http://www.jayloden.com
|
||||||
|
|
||||||
|
N: Arnon Yaari (wiggin15)
|
||||||
|
W: https://github.com/wiggin15
|
||||||
|
I: 517, 607, 610, 1131, 1123, 1130, 1154, 1164, 1174, 1177
|
||||||
|
|
||||||
|
N: Jeff Tang
|
||||||
|
W: https://github.com/mrjefftang
|
||||||
|
I: 340, 529, 616, 653, 654, 648, 641
|
||||||
|
|
||||||
N: Jeremy Whitlock
|
N: Jeremy Whitlock
|
||||||
E: jcscoobyrs@gmail.com
|
E: jcscoobyrs@gmail.com
|
||||||
D: great help with OSX C development.
|
D: great help with OSX C development.
|
||||||
I: 125, 150, 174, 206
|
I: 125, 150, 174, 206
|
||||||
|
|
||||||
|
N: Landry Breuil
|
||||||
|
W: https://github.com/landryb
|
||||||
|
D: OpenBSD implementation.
|
||||||
|
I: 615
|
||||||
|
|
||||||
N: wj32
|
N: wj32
|
||||||
E: wj32.64@gmail.com
|
E: wj32.64@gmail.com
|
||||||
D: process username() and get_connections() on Windows
|
D: process username() and get_connections() on Windows
|
||||||
|
@ -56,6 +95,14 @@ W: http://daviddaeschler.com
|
||||||
D: some contributions to initial design/bootstrap plus occasional bug fixing
|
D: some contributions to initial design/bootstrap plus occasional bug fixing
|
||||||
I: 522, 536
|
I: 522, 536
|
||||||
|
|
||||||
|
N: Thomas Klausner
|
||||||
|
W: https://github.com/0-wiz-0
|
||||||
|
I: #557
|
||||||
|
|
||||||
|
N: Ryo Onodera
|
||||||
|
W: https://github.com/ryoon
|
||||||
|
I: #557
|
||||||
|
|
||||||
N: cjgohlke
|
N: cjgohlke
|
||||||
E: cjgohlke@gmail.com
|
E: cjgohlke@gmail.com
|
||||||
D: Windows 64 bit support
|
D: Windows 64 bit support
|
||||||
|
@ -253,10 +300,6 @@ N: msabramo
|
||||||
E: msabramo@gmail.com
|
E: msabramo@gmail.com
|
||||||
I: 492
|
I: 492
|
||||||
|
|
||||||
N: Jeff Tang
|
|
||||||
W: https://github.com/mrjefftang
|
|
||||||
I: 340, 529, 616, 653, 654
|
|
||||||
|
|
||||||
N: Yaolong Huang
|
N: Yaolong Huang
|
||||||
E: airekans@gmail.com
|
E: airekans@gmail.com
|
||||||
W: http://airekans.github.io/
|
W: http://airekans.github.io/
|
||||||
|
@ -267,8 +310,9 @@ W: https://github.com/anders-chrigstrom
|
||||||
I: 496
|
I: 496
|
||||||
|
|
||||||
N: spacewander
|
N: spacewander
|
||||||
|
W: https://github.com/spacewander
|
||||||
E: spacewanderlzx@gmail.com
|
E: spacewanderlzx@gmail.com
|
||||||
I: 561
|
I: 561, 603
|
||||||
|
|
||||||
N: Sylvain Mouquet
|
N: Sylvain Mouquet
|
||||||
E: sylvain.mouquet@gmail.com
|
E: sylvain.mouquet@gmail.com
|
||||||
|
@ -308,3 +352,166 @@ N: Árni Már Jónsson
|
||||||
E: Reykjavik, Iceland
|
E: Reykjavik, Iceland
|
||||||
E: https://github.com/arnimarj
|
E: https://github.com/arnimarj
|
||||||
I: 634
|
I: 634
|
||||||
|
|
||||||
|
N: Bart van Kleef
|
||||||
|
W: https://github.com/bkleef
|
||||||
|
I: 664
|
||||||
|
|
||||||
|
N: Steven Winfield
|
||||||
|
W: https://github.com/stevenwinfield
|
||||||
|
I: 672
|
||||||
|
|
||||||
|
N: sk6249
|
||||||
|
W: https://github.com/sk6249
|
||||||
|
I: 670
|
||||||
|
|
||||||
|
N: maozguttman
|
||||||
|
W: https://github.com/maozguttman
|
||||||
|
I: 659
|
||||||
|
|
||||||
|
N: dasumin
|
||||||
|
W: https://github.com/dasumin
|
||||||
|
I: 541
|
||||||
|
|
||||||
|
N: Mike Sarahan
|
||||||
|
W: https://github.com/msarahan
|
||||||
|
I: 688
|
||||||
|
|
||||||
|
N: Syohei YOSHIDA
|
||||||
|
W: https://github.com/syohex
|
||||||
|
I: 730
|
||||||
|
|
||||||
|
N: Frank Benkstein
|
||||||
|
W: https://github.com/fbenkstein
|
||||||
|
I: 732, 733
|
||||||
|
|
||||||
|
N: Visa Hankala
|
||||||
|
E: visa@openbsd.org
|
||||||
|
I: 741
|
||||||
|
|
||||||
|
N: Sebastian-Gabriel Brestin
|
||||||
|
C: Romania
|
||||||
|
E: sebastianbrestin@gmail.com
|
||||||
|
I: 704
|
||||||
|
|
||||||
|
N: Timmy Konick
|
||||||
|
W: https://github.com/tijko
|
||||||
|
I: 751
|
||||||
|
|
||||||
|
N: mpderbec
|
||||||
|
W: https://github.com/mpderbec
|
||||||
|
I: 660
|
||||||
|
|
||||||
|
N: Mozilla Foundation
|
||||||
|
D: sample code for process USS memory.
|
||||||
|
|
||||||
|
N: wxwright
|
||||||
|
W: https://github.com/wxwright
|
||||||
|
I: 776
|
||||||
|
|
||||||
|
N: Farhan Khan
|
||||||
|
E: khanzf@gmail.com
|
||||||
|
I: 823
|
||||||
|
|
||||||
|
N: Jake Omann
|
||||||
|
E: https://github.com/jomann09
|
||||||
|
I: 816, 775
|
||||||
|
|
||||||
|
N: Jeremy Humble
|
||||||
|
W: https://github.com/jhumble
|
||||||
|
I: 863
|
||||||
|
|
||||||
|
N: Ilya Georgievsky
|
||||||
|
W: https://github.com/xBeAsTx
|
||||||
|
I: 870
|
||||||
|
|
||||||
|
N: Yago Jesus
|
||||||
|
W: https://github.com/YJesus
|
||||||
|
I: 798
|
||||||
|
|
||||||
|
N: Andre Caron
|
||||||
|
C: Montreal, QC, Canada
|
||||||
|
E: andre.l.caron@gmail.com
|
||||||
|
W: https://github.com/AndreLouisCaron
|
||||||
|
I: 880
|
||||||
|
|
||||||
|
N: ewedlund
|
||||||
|
W: https://github.com/ewedlund
|
||||||
|
I: 874
|
||||||
|
|
||||||
|
N: Arcadiy Ivanov
|
||||||
|
W: https://github.com/arcivanov
|
||||||
|
I: 919
|
||||||
|
|
||||||
|
N: Max Bélanger
|
||||||
|
W: https://github.com/maxbelanger
|
||||||
|
I: 936, 1133
|
||||||
|
|
||||||
|
N: Pierre Fersing
|
||||||
|
C: France
|
||||||
|
E: pierre.fersing@bleemeo.com
|
||||||
|
I: 950
|
||||||
|
|
||||||
|
N: Thiago Borges Abdnur
|
||||||
|
W: https://github.com/bolaum
|
||||||
|
I: 959
|
||||||
|
|
||||||
|
N: Nicolas Hennion
|
||||||
|
W: https://github.com/nicolargo
|
||||||
|
I: 974
|
||||||
|
|
||||||
|
N: Baruch Siach
|
||||||
|
W: https://github.com/baruchsiach
|
||||||
|
I: 872
|
||||||
|
|
||||||
|
N: Danek Duvall
|
||||||
|
W: https://github.com/dhduvall
|
||||||
|
I: 1002
|
||||||
|
|
||||||
|
N: Alexander Hasselhuhn
|
||||||
|
C: Germany
|
||||||
|
W: https://github.com/alexanha
|
||||||
|
|
||||||
|
N: Himanshu Shekhar
|
||||||
|
W: https://github.com/himanshub16
|
||||||
|
I: 1036
|
||||||
|
|
||||||
|
N: Yannick Gingras
|
||||||
|
W: https://github.com/ygingras
|
||||||
|
I: 1057
|
||||||
|
|
||||||
|
N: Gleb Smirnoff
|
||||||
|
W: https://github.com/glebius
|
||||||
|
I: 1042, 1079
|
||||||
|
|
||||||
|
N: Oleksii Shevchuk
|
||||||
|
W: https://github.com/alxchk
|
||||||
|
I: 1077, 1093, 1091
|
||||||
|
|
||||||
|
N: Prodesire
|
||||||
|
W: https://github.com/Prodesire
|
||||||
|
I: 1138
|
||||||
|
|
||||||
|
N: Sebastian Saip
|
||||||
|
W: https://github.com/ssaip
|
||||||
|
I: 1141
|
||||||
|
|
||||||
|
N: Jakub Bacic
|
||||||
|
W: https://github.com/jakub-bacic
|
||||||
|
I: 1127
|
||||||
|
|
||||||
|
N: Akos Kiss
|
||||||
|
W: https://github.com/akosthekiss
|
||||||
|
I: 1150
|
||||||
|
|
||||||
|
N: Adrian Page
|
||||||
|
W: https://github.com/adpag
|
||||||
|
I: 1159, 1160, 1161
|
||||||
|
|
||||||
|
N: Matthew Long
|
||||||
|
W: https://github.com/matray
|
||||||
|
I: 1167
|
||||||
|
|
||||||
|
N: janderbrain
|
||||||
|
W: https://github.com/janderbrain
|
||||||
|
I: 1169
|
||||||
|
|
|
@ -0,0 +1,209 @@
|
||||||
|
=======================
|
||||||
|
Setup and running tests
|
||||||
|
=======================
|
||||||
|
|
||||||
|
If you plan on hacking on psutil this is what you're supposed to do first:
|
||||||
|
|
||||||
|
- clone the GIT repository:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
$ git clone git@github.com:giampaolo/psutil.git
|
||||||
|
|
||||||
|
- install test deps and GIT hooks:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
make setup-dev-env
|
||||||
|
|
||||||
|
- run tests:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
make test
|
||||||
|
|
||||||
|
- bear in mind that ``make``
|
||||||
|
(see `Makefile <https://github.com/giampaolo/psutil/blob/master/Makefile>`_)
|
||||||
|
is the designated tool to run tests, build, install etc. and that it is also
|
||||||
|
available on Windows
|
||||||
|
(see `make.bat <https://github.com/giampaolo/psutil/blob/master/make.bat>`_).
|
||||||
|
- do not use ``sudo``; ``make install`` installs psutil as a limited user in
|
||||||
|
"edit" mode; also ``make setup-dev-env`` installs deps as a limited user.
|
||||||
|
- use `make help` to see the list of available commands.
|
||||||
|
|
||||||
|
============
|
||||||
|
Coding style
|
||||||
|
============
|
||||||
|
|
||||||
|
- python code strictly follows `PEP 8 <https://www.python.org/dev/peps/pep-0008/>`_
|
||||||
|
styling guides and this is enforced by ``make install-git-hooks``.
|
||||||
|
- C code strictly follows `PEP 7 <https://www.python.org/dev/peps/pep-0007/>`_
|
||||||
|
styling guides.
|
||||||
|
|
||||||
|
========
|
||||||
|
Makefile
|
||||||
|
========
|
||||||
|
|
||||||
|
Some useful make commands:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
make install # install
|
||||||
|
make setup-dev-env # install useful dev libs (pyflakes, unittest2, etc.)
|
||||||
|
make test # run unit tests
|
||||||
|
make test-memleaks # run memory leak tests
|
||||||
|
make test-coverage # run test coverage
|
||||||
|
make flake8 # run PEP8 linter
|
||||||
|
|
||||||
|
There are some differences between ``make`` on UNIX and Windows.
|
||||||
|
For instance, to run a specific Python version. On UNIX:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
make test PYTHON=python3.5
|
||||||
|
|
||||||
|
On Windows:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
set PYTHON=C:\python35\python.exe && make test
|
||||||
|
|
||||||
|
...or:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
make -p 35 test
|
||||||
|
|
||||||
|
If you want to modify psutil and run a script on the fly which uses it do
|
||||||
|
(on UNIX):
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
make test TSCRIPT=foo.py
|
||||||
|
|
||||||
|
On Windows:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
set TSCRIPT=foo.py && make test
|
||||||
|
|
||||||
|
====================
|
||||||
|
Adding a new feature
|
||||||
|
====================
|
||||||
|
|
||||||
|
Usually the files involved when adding a new functionality are:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
psutil/__init__.py # main psutil namespace
|
||||||
|
psutil/_ps{platform}.py # python platform wrapper
|
||||||
|
psutil/_psutil_{platform}.c # C platform extension
|
||||||
|
psutil/_psutil_{platform}.h # C header file
|
||||||
|
psutil/tests/test_process|system.py # main test suite
|
||||||
|
psutil/tests/test_{platform}.py # platform specific test suite
|
||||||
|
|
||||||
|
Typical process occurring when adding a new functionality (API):
|
||||||
|
|
||||||
|
- define the new function in ``psutil/__init__.py``.
|
||||||
|
- write the platform specific implementation in ``psutil/_ps{platform}.py``
|
||||||
|
(e.g. ``psutil/_pslinux.py``).
|
||||||
|
- if the change requires C, write the C implementation in
|
||||||
|
``psutil/_psutil_{platform}.c`` (e.g. ``psutil/_psutil_linux.c``).
|
||||||
|
- write a generic test in ``psutil/tests/test_system.py`` or
|
||||||
|
``psutil/tests/test_process.py``.
|
||||||
|
- if possible, write a platform specific test in
|
||||||
|
``psutil/tests/test_{platform}.py`` (e.g. ``test_linux.py``).
|
||||||
|
This usually means testing the return value of the new feature against
|
||||||
|
a system CLI tool.
|
||||||
|
- update doc in ``doc/index.py``.
|
||||||
|
- update ``HISTORY.rst``.
|
||||||
|
- update ``README.rst`` (if necessary).
|
||||||
|
- make a pull request.
|
||||||
|
|
||||||
|
===================
|
||||||
|
Make a pull request
|
||||||
|
===================
|
||||||
|
|
||||||
|
- fork psutil
|
||||||
|
- create your feature branch (``git checkout -b my-new-feature``)
|
||||||
|
- commit your changes (``git commit -am 'add some feature'``)
|
||||||
|
- push to the branch (``git push origin my-new-feature``)
|
||||||
|
- create a new pull request
|
||||||
|
|
||||||
|
======================
|
||||||
|
Continuous integration
|
||||||
|
======================
|
||||||
|
|
||||||
|
All of the services listed below are automatically run on ``git push``.
|
||||||
|
|
||||||
|
Unit tests
|
||||||
|
----------
|
||||||
|
|
||||||
|
Tests are automatically run for every GIT push on **Linux**, **OSX** and
|
||||||
|
**Windows** by using:
|
||||||
|
|
||||||
|
- `Travis <https://travis-ci.org/giampaolo/psutil>`_ (Linux, OSX)
|
||||||
|
- `Appveyor <https://ci.appveyor.com/project/giampaolo/psutil>`_ (Windows)
|
||||||
|
|
||||||
|
Test files controlling these are
|
||||||
|
`.travis.yml <https://github.com/giampaolo/psutil/blob/master/.travis.yml>`_
|
||||||
|
and
|
||||||
|
`appveyor.yml <https://github.com/giampaolo/psutil/blob/master/appveyor.yml>`_.
|
||||||
|
Both services run psutil test suite against all supported python version
|
||||||
|
(2.6 - 3.6).
|
||||||
|
Two icons in the home page (README) always show the build status:
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/travis/giampaolo/psutil/master.svg?maxAge=3600&label=Linux%20/%20OSX
|
||||||
|
:target: https://travis-ci.org/giampaolo/psutil
|
||||||
|
:alt: Linux tests (Travis)
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/appveyor/ci/giampaolo/psutil/master.svg?maxAge=3600&label=Windows
|
||||||
|
:target: https://ci.appveyor.com/project/giampaolo/psutil
|
||||||
|
:alt: Windows tests (Appveyor)
|
||||||
|
|
||||||
|
OSX, BSD, AIX and Solaris are currently tested manually (sigh!).
|
||||||
|
|
||||||
|
Test coverage
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Test coverage is provided by `coveralls.io <https://coveralls.io/github/giampaolo/psutil>`_,
|
||||||
|
it is controlled via `.travis.yml <https://github.com/giampaolo/psutil/blob/master/.travis.yml>`_
|
||||||
|
and it is updated on every git push.
|
||||||
|
An icon in the home page (README) always shows the last coverage percentage:
|
||||||
|
|
||||||
|
.. image:: https://coveralls.io/repos/giampaolo/psutil/badge.svg?branch=master&service=github
|
||||||
|
:target: https://coveralls.io/github/giampaolo/psutil?branch=master
|
||||||
|
:alt: Test coverage (coverall.io)
|
||||||
|
|
||||||
|
=============
|
||||||
|
Documentation
|
||||||
|
=============
|
||||||
|
|
||||||
|
- doc source code is written in a single file: `/docs/index.rst <https://raw.githubusercontent.com/giampaolo/psutil/master/docs/index.rst>`_.
|
||||||
|
- it uses `RsT syntax <http://docutils.sourceforge.net/docs/user/rst/quickref.html>`_
|
||||||
|
and it's built with `sphinx <http://sphinx-doc.org/>`_.
|
||||||
|
- doc can be built with ``make setup-dev-env; cd docs; make html``.
|
||||||
|
- public doc is hosted on http://psutil.readthedocs.io/
|
||||||
|
|
||||||
|
=======================
|
||||||
|
Releasing a new version
|
||||||
|
=======================
|
||||||
|
|
||||||
|
These are notes for myself (Giampaolo):
|
||||||
|
|
||||||
|
- ``make release``
|
||||||
|
- post announce (``make print-announce``) on psutil and python-announce mailing
|
||||||
|
lists, twitter, g+, blog.
|
||||||
|
|
||||||
|
=============
|
||||||
|
FreeBSD notes
|
||||||
|
=============
|
||||||
|
|
||||||
|
- setup:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
pkg install python python3 gcc git vim screen bash
|
||||||
|
chsh -s /usr/local/bin/bash user # set bash as default shell
|
||||||
|
|
||||||
|
- ``/usr/src`` contains the source codes for all installed CLI tools (grep in it).
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,165 @@
|
||||||
|
TODO
|
||||||
|
====
|
||||||
|
|
||||||
|
A collection of ideas and notes about stuff to implement in future versions.
|
||||||
|
"#NNN" occurrences refer to bug tracker issues at:
|
||||||
|
https://github.com/giampaolo/psutil/issues
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
=========
|
||||||
|
|
||||||
|
- #355: Android (with patch)
|
||||||
|
- #82: Cygwin (PR at #998)
|
||||||
|
- #276: GNU/Hurd
|
||||||
|
- #693: Windows Nano
|
||||||
|
- DragonFlyBSD
|
||||||
|
- HP-UX
|
||||||
|
|
||||||
|
FEATURES
|
||||||
|
========
|
||||||
|
|
||||||
|
- #371: sensors_temperatures() at least for OSX.
|
||||||
|
|
||||||
|
- #669: Windows / net_if_addrs(): return broadcast addr.
|
||||||
|
|
||||||
|
- #550: CPU info (frequency, architecture, threads per core, cores per socket,
|
||||||
|
sockets, ...)
|
||||||
|
|
||||||
|
- #772: extended net_io_counters() metrics.
|
||||||
|
|
||||||
|
- #900: wheels for OSX and Linux.
|
||||||
|
|
||||||
|
- #922: extended net_io_stats() info.
|
||||||
|
|
||||||
|
- #914: extended platform specific process info.
|
||||||
|
|
||||||
|
- #898: wifi stats
|
||||||
|
|
||||||
|
- #893: (BSD) process environ
|
||||||
|
|
||||||
|
- #809: (BSD) per-process resource limits (rlimit()).
|
||||||
|
|
||||||
|
- (UNIX) process root (different from cwd)
|
||||||
|
|
||||||
|
- #782: (UNIX) process num of signals received.
|
||||||
|
|
||||||
|
- (Linux) locked files via /proc/locks:
|
||||||
|
https://www.centos.org/docs/5/html/5.2/Deployment_Guide/s2-proc-locks.html
|
||||||
|
|
||||||
|
- #269: NIC rx/tx queue. This should probably go into net_if_stats().
|
||||||
|
Figure out on what platforms this is supported:
|
||||||
|
Linux: yes
|
||||||
|
Others: ?
|
||||||
|
|
||||||
|
- Process.threads(): thread names; patch for OSX available at:
|
||||||
|
https://code.google.com/p/plcrashreporter/issues/detail?id=65
|
||||||
|
Sample code:
|
||||||
|
https://github.com/janmojzis/pstree/blob/master/proc_kvm.c
|
||||||
|
|
||||||
|
- Asynchronous psutil.Popen (see http://bugs.python.org/issue1191964)
|
||||||
|
|
||||||
|
- (Windows) fall back on using WMIC for Process methods returning AccessDenied
|
||||||
|
|
||||||
|
- #613: thread names.
|
||||||
|
|
||||||
|
- #604: emulate os.getloadavg() on Windows
|
||||||
|
|
||||||
|
- scripts/taskmgr-gui.py (using tk).
|
||||||
|
|
||||||
|
- system-wide number of open file descriptors:
|
||||||
|
- https://jira.hyperic.com/browse/SIGAR-30
|
||||||
|
|
||||||
|
- Number of system threads.
|
||||||
|
- Windows: http://msdn.microsoft.com/en-us/library/windows/desktop/ms684824(v=vs.85).aspx
|
||||||
|
|
||||||
|
- Doc / wiki which compares similarities between UNIX cli tools and psutil.
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
df -a -> psutil.disk_partitions
|
||||||
|
lsof -> psutil.Process.open_files() and psutil.Process.open_connections()
|
||||||
|
killall-> (actual script)
|
||||||
|
tty -> psutil.Process.terminal()
|
||||||
|
who -> psutil.users()
|
||||||
|
```
|
||||||
|
|
||||||
|
- psutil.proc_tree() something which obtains a {pid:ppid, ...} dict for
|
||||||
|
all running processes in one shot. This can be factored out from
|
||||||
|
Process.children() and exposed as a first class function.
|
||||||
|
PROS: on Windows we can take advantage of _psutil_windows.ppid_map()
|
||||||
|
which is faster than iterating over all pids and calling ppid().
|
||||||
|
CONS: scripts/pstree.py shows this can be easily done in the user code
|
||||||
|
so maybe it's not worth the addition.
|
||||||
|
|
||||||
|
- advanced cmdline interface exposing the whole API and providing different
|
||||||
|
kind of outputs (e.g. pprinted, colorized, json).
|
||||||
|
|
||||||
|
- [Linux]: process cgroups (http://en.wikipedia.org/wiki/Cgroups). They look
|
||||||
|
similar to prlimit() in terms of functionality but uglier (they should allow
|
||||||
|
limiting per-process network IO resources though, which is great). Needs
|
||||||
|
further reading.
|
||||||
|
|
||||||
|
- Python 3.3. exposed different sched.h functions:
|
||||||
|
http://docs.python.org/dev/whatsnew/3.3.html#os
|
||||||
|
http://bugs.python.org/issue12655
|
||||||
|
http://docs.python.org/dev/library/os.html#interface-to-the-scheduler
|
||||||
|
It might be worth to take a look and figure out whether we can include some
|
||||||
|
of those in psutil.
|
||||||
|
Also, we can probably reimplement wait_pid() on POSIX which is currently
|
||||||
|
implemented as a busy-loop.
|
||||||
|
|
||||||
|
- os.times() provides 'elapsed' times (cpu_times() might).
|
||||||
|
|
||||||
|
- ...also guest_time and cguest_time on Linux.
|
||||||
|
|
||||||
|
- Enrich exception classes hierarchy on Python >= 3.3 / post PEP-3151 so that:
|
||||||
|
- NoSuchProcess inherits from ProcessLookupError
|
||||||
|
- AccessDenied inherits from PermissionError
|
||||||
|
- TimeoutExpired inherits from TimeoutError (debatable)
|
||||||
|
See: http://docs.python.org/3/library/exceptions.html#os-exceptions
|
||||||
|
|
||||||
|
- Process.threads() might grow an extra "id" parameter so that it can be
|
||||||
|
used as such:
|
||||||
|
```
|
||||||
|
>>> p = psutil.Process(os.getpid())
|
||||||
|
>>> p.threads(id=psutil.current_thread_id())
|
||||||
|
thread(id=2539, user_time=0.03, system_time=0.02)
|
||||||
|
>>>
|
||||||
|
```
|
||||||
|
Note: this leads to questions such as "should we have a custom NoSuchThread
|
||||||
|
exception? Also see issue #418.
|
||||||
|
Note #2: this would work with os.getpid() only.
|
||||||
|
psutil.current_thread_id() might be desirable as per issue #418 though.
|
||||||
|
|
||||||
|
- should psutil.TimeoutExpired exception have a 'msg' kwarg similar to
|
||||||
|
NoSuchProcess and AccessDenied? Not that we need it, but currently we
|
||||||
|
cannot raise a TimeoutExpired exception with a specific error string.
|
||||||
|
|
||||||
|
- process_iter() might grow an "attrs" parameter similar to Process.as_dict()
|
||||||
|
invoke the necessary methods and include the results into a "cache"
|
||||||
|
attribute attached to the returned Process instances so that one can avoid
|
||||||
|
catching NSP and AccessDenied:
|
||||||
|
for p in process_iter(attrs=['cpu_percent']):
|
||||||
|
print(p.cache['cpu_percent'])
|
||||||
|
This also leads questions as whether we should introduce a sorting order.
|
||||||
|
|
||||||
|
- round Process.memory_percent() result?
|
||||||
|
|
||||||
|
- #550: number of threads per core.
|
||||||
|
|
||||||
|
BUGFIXES
|
||||||
|
========
|
||||||
|
|
||||||
|
- #600: windows / open_files(): support network file handles.
|
||||||
|
|
||||||
|
REJECTED
|
||||||
|
========
|
||||||
|
|
||||||
|
- #550: threads per core
|
||||||
|
|
||||||
|
RESOURCES
|
||||||
|
=========
|
||||||
|
|
||||||
|
- sigar: https://github.com/hyperic/sigar (Java)
|
||||||
|
- zabbix: https://zabbix.org/wiki/Get_Zabbix
|
||||||
|
- libstatgrab: http://www.i-scream.org/libstatgrab/
|
||||||
|
- top: http://www.unixtop.org/
|
|
@ -1,116 +1,160 @@
|
||||||
============================
|
Install pip
|
||||||
Installing using pip on UNIX
|
===========
|
||||||
============================
|
|
||||||
|
|
||||||
The easiest way to install psutil on UNIX is by using pip (but first you might
|
pip is the easiest way to install psutil.
|
||||||
need to install python header files; see later).
|
It is shipped by default with Python 2.7.9+ and 3.4+. For other Python versions
|
||||||
First install pip::
|
you can install it manually.
|
||||||
|
On Linux or via wget:
|
||||||
|
|
||||||
$ wget https://bootstrap.pypa.io/get-pip.py
|
.. code-block:: bash
|
||||||
$ python get-pip.py
|
|
||||||
|
|
||||||
...then run::
|
wget https://bootstrap.pypa.io/get-pip.py -O - | python
|
||||||
|
|
||||||
$ pip install psutil
|
On OSX or via curl:
|
||||||
|
|
||||||
You may need to install gcc and python header files first (see later).
|
.. code-block:: bash
|
||||||
|
|
||||||
|
python < <(curl -s https://bootstrap.pypa.io/get-pip.py)
|
||||||
|
|
||||||
|
On Windows, `download pip <https://pip.pypa.io/en/latest/installing/>`__, open
|
||||||
|
cmd.exe and install it:
|
||||||
|
|
||||||
|
.. code-block:: bat
|
||||||
|
|
||||||
|
C:\Python27\python.exe get-pip.py
|
||||||
|
|
||||||
|
Permission issues (UNIX)
|
||||||
|
========================
|
||||||
|
|
||||||
|
The commands below assume you're running as root.
|
||||||
|
If you're not or you bump into permission errors you can either:
|
||||||
|
|
||||||
|
* prepend ``sudo``, e.g.:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
sudo pip install psutil
|
||||||
|
|
||||||
|
* install psutil for your user only (not at system level):
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
pip install --user psutil
|
||||||
|
|
||||||
|
Linux
|
||||||
|
=====
|
||||||
|
|
||||||
|
Ubuntu / Debian:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
sudo apt-get install gcc python-dev python-pip
|
||||||
|
pip install psutil
|
||||||
|
|
||||||
|
RedHat / CentOS:
|
||||||
|
|
||||||
|
|
||||||
=====================
|
.. code-block:: bash
|
||||||
Installing on Windows
|
|
||||||
=====================
|
|
||||||
|
|
||||||
Just get the right installer for your Python version and architecture from:
|
sudo yum install gcc python-devel python-pip
|
||||||
https://pypi.python.org/pypi/psutil/#downloads
|
pip install psutil
|
||||||
Since wheels installers are also available you may also use pip.
|
|
||||||
|
|
||||||
|
If you're on Python 3 use ``python3-dev`` and ``python3-pip`` instead.
|
||||||
|
|
||||||
========================================
|
OSX
|
||||||
Compiling on Windows using Visual Studio
|
===
|
||||||
========================================
|
|
||||||
|
|
||||||
In order to compile psutil on Windows you'll need Visual Studio (Mingw32 is
|
Install `Xcode <https://developer.apple.com/downloads/?name=Xcode>`__
|
||||||
no longer supported). You must have the same version of Visual Studio used to compile
|
first, then:
|
||||||
your installation of Python, that is::
|
|
||||||
|
|
||||||
* Python 2.6: VS 2008
|
.. code-block:: bash
|
||||||
* Python 2.7: VS 2008
|
|
||||||
* Python 3.3, 3.4: VS 2010 (you can download it from `MS website <http://www.visualstudio.com/downloads/download-visual-studio-vs#d-2010-express>`_)
|
|
||||||
* Python 3.5: `VS 2015 UP <http://www.visualstudio.com/en-au/news/vs2015-preview-vs>`_
|
|
||||||
|
|
||||||
...then run::
|
pip install psutil
|
||||||
|
|
||||||
setup.py build
|
Windows
|
||||||
|
=======
|
||||||
|
|
||||||
...or::
|
The easiest way to install psutil on Windows is to just use the pre-compiled
|
||||||
|
exe/wheel installers hosted on
|
||||||
|
`PYPI <https://pypi.python.org/pypi/psutil/#downloads>`__ via pip:
|
||||||
|
|
||||||
make.bat build
|
.. code-block:: bat
|
||||||
|
|
||||||
|
C:\Python27\python.exe -m pip install psutil
|
||||||
|
|
||||||
|
If you want to compile psutil from sources you'll need **Visual Studio**
|
||||||
|
(Mingw32 is no longer supported):
|
||||||
|
|
||||||
|
* Python 2.6, 2.7: `VS-2008 <http://www.microsoft.com/en-us/download/details.aspx?id=44266>`__
|
||||||
|
* Python 3.3, 3.4: `VS-2010 <http://www.visualstudio.com/downloads/download-visual-studio-vs#d-2010-express>`__
|
||||||
|
* Python 3.5+: `VS-2015 <http://www.visualstudio.com/en-au/news/vs2015-preview-vs>`__
|
||||||
|
|
||||||
Compiling 64 bit versions of Python 2.6 and 2.7 with VS 2008 requires
|
Compiling 64 bit versions of Python 2.6 and 2.7 with VS 2008 requires
|
||||||
Windows SDK and .NET Framework 3.5 SP1 to be installed first.
|
`Windows SDK and .NET Framework 3.5 SP1 <https://www.microsoft.com/en-us/download/details.aspx?id=3138>`__.
|
||||||
Once you have those run vcvars64.bat, then compile:
|
Once installed run vcvars64.bat, then you can finally compile (see
|
||||||
http://stackoverflow.com/questions/11072521/
|
`here <http://stackoverflow.com/questions/11072521/>`__).
|
||||||
|
To compile / install psutil from sources on Windows run:
|
||||||
|
|
||||||
===================
|
.. code-block:: bat
|
||||||
Installing on Linux
|
|
||||||
===================
|
|
||||||
|
|
||||||
gcc is required and so the python headers. They can easily be installed by
|
make.bat build
|
||||||
using the distro package manager. For example, on Debian and Ubuntu::
|
make.bat install
|
||||||
|
|
||||||
$ sudo apt-get install gcc python-dev
|
FreeBSD
|
||||||
|
=======
|
||||||
|
|
||||||
...on Redhat and CentOS::
|
.. code-block:: bash
|
||||||
|
|
||||||
$ sudo yum install gcc python-devel
|
pkg install python gcc
|
||||||
|
python -m pip install psutil
|
||||||
|
|
||||||
Once done, you can build/install psutil with::
|
OpenBSD
|
||||||
|
=======
|
||||||
|
|
||||||
$ python setup.py install
|
.. code-block:: bash
|
||||||
|
|
||||||
|
export PKG_PATH="http://ftp.openbsd.org/pub/OpenBSD/`uname -r`/packages/`arch -s`/"
|
||||||
|
pkg_add -v python gcc
|
||||||
|
python -m pip install psutil
|
||||||
|
|
||||||
|
NetBSD
|
||||||
|
======
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
export PKG_PATH="ftp.netbsd.org/pub/pkgsrc/packages/NetBSD/`uname -m`/`uname -r`/All"
|
||||||
|
pkg_add -v pkgin
|
||||||
|
pkgin install python gcc
|
||||||
|
python -m pip install psutil
|
||||||
|
|
||||||
|
Solaris
|
||||||
|
=======
|
||||||
|
|
||||||
|
If ``cc`` compiler is not installed create a symlink to ``gcc``:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
sudo ln -s /usr/bin/gcc /usr/local/bin/cc
|
||||||
|
|
||||||
|
Install:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
pkg install gcc
|
||||||
|
python -m pip install psutil
|
||||||
|
|
||||||
|
Install from sources
|
||||||
|
====================
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
git clone https://github.com/giampaolo/psutil.git
|
||||||
|
cd psutil
|
||||||
|
python setup.py install
|
||||||
|
|
||||||
|
|
||||||
==================
|
Dev Guide
|
||||||
Installing on OS X
|
=========
|
||||||
==================
|
|
||||||
|
|
||||||
OS X installation from source will require gcc which you can obtain as part of
|
If you plan on hacking on psutil you may want to take a look at the
|
||||||
the 'XcodeTools' installer from Apple. Then you can run the standard distutils
|
`dev guide <https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst>`__.
|
||||||
commands.
|
|
||||||
To build only::
|
|
||||||
|
|
||||||
$ python setup.py build
|
|
||||||
|
|
||||||
To install and build::
|
|
||||||
|
|
||||||
$ python setup.py install
|
|
||||||
|
|
||||||
|
|
||||||
=====================
|
|
||||||
Installing on FreeBSD
|
|
||||||
=====================
|
|
||||||
|
|
||||||
The same compiler used to install Python must be present on the system in order
|
|
||||||
to build modules using distutils. Assuming it is installed, you can build using
|
|
||||||
the standard distutils commands.
|
|
||||||
|
|
||||||
Build only::
|
|
||||||
|
|
||||||
$ python setup.py build
|
|
||||||
|
|
||||||
Install and build::
|
|
||||||
|
|
||||||
$ python setup.py install
|
|
||||||
|
|
||||||
|
|
||||||
========
|
|
||||||
Makefile
|
|
||||||
========
|
|
||||||
|
|
||||||
A makefile is available for both UNIX and Windows (make.bat). It provides
|
|
||||||
some automations for the tasks described above and might be preferred over
|
|
||||||
using setup.py. With it you can::
|
|
||||||
|
|
||||||
$ make install # just install (in --user mode)
|
|
||||||
$ make uninstall # uninstall (needs pip)
|
|
||||||
$ make test # run tests
|
|
||||||
$ make clean # remove installation files
|
|
||||||
|
|
|
@ -1,22 +1,131 @@
|
||||||
include .coveragerc
|
include .coveragerc
|
||||||
include .git-pre-commit
|
include .git-pre-commit
|
||||||
include .git-pre-commit
|
|
||||||
include .gitignore
|
include .gitignore
|
||||||
include .travis.yml
|
|
||||||
include CREDITS
|
include CREDITS
|
||||||
|
include DEVGUIDE.rst
|
||||||
include HISTORY.rst
|
include HISTORY.rst
|
||||||
|
include IDEAS
|
||||||
include INSTALL.rst
|
include INSTALL.rst
|
||||||
include LICENSE
|
include LICENSE
|
||||||
include make.bat
|
|
||||||
include Makefile
|
|
||||||
include MANIFEST.in
|
include MANIFEST.in
|
||||||
|
include Makefile
|
||||||
include README.rst
|
include README.rst
|
||||||
|
include docs/Makefile
|
||||||
|
include docs/README
|
||||||
|
include docs/_static/copybutton.js
|
||||||
|
include docs/_static/css/custom.css
|
||||||
|
include docs/_static/favicon.ico
|
||||||
|
include docs/_static/sidebar.js
|
||||||
|
include docs/conf.py
|
||||||
|
include docs/index.rst
|
||||||
|
include docs/make.bat
|
||||||
|
include make.bat
|
||||||
|
include psutil/DEVNOTES
|
||||||
|
include psutil/__init__.py
|
||||||
|
include psutil/_common.py
|
||||||
|
include psutil/_compat.py
|
||||||
|
include psutil/_exceptions.py
|
||||||
|
include psutil/_psaix.py
|
||||||
|
include psutil/_psbsd.py
|
||||||
|
include psutil/_pslinux.py
|
||||||
|
include psutil/_psosx.py
|
||||||
|
include psutil/_psposix.py
|
||||||
|
include psutil/_pssunos.py
|
||||||
|
include psutil/_psutil_aix.c
|
||||||
|
include psutil/_psutil_bsd.c
|
||||||
|
include psutil/_psutil_common.c
|
||||||
|
include psutil/_psutil_common.h
|
||||||
|
include psutil/_psutil_linux.c
|
||||||
|
include psutil/_psutil_osx.c
|
||||||
|
include psutil/_psutil_posix.c
|
||||||
|
include psutil/_psutil_posix.h
|
||||||
|
include psutil/_psutil_sunos.c
|
||||||
|
include psutil/_psutil_windows.c
|
||||||
|
include psutil/_pswindows.py
|
||||||
|
include psutil/arch/aix/common.c
|
||||||
|
include psutil/arch/aix/common.h
|
||||||
|
include psutil/arch/aix/ifaddrs.c
|
||||||
|
include psutil/arch/aix/ifaddrs.h
|
||||||
|
include psutil/arch/aix/net_connections.c
|
||||||
|
include psutil/arch/aix/net_connections.h
|
||||||
|
include psutil/arch/aix/net_kernel_structs.h
|
||||||
|
include psutil/arch/freebsd/proc_socks.c
|
||||||
|
include psutil/arch/freebsd/proc_socks.h
|
||||||
|
include psutil/arch/freebsd/specific.c
|
||||||
|
include psutil/arch/freebsd/specific.h
|
||||||
|
include psutil/arch/freebsd/sys_socks.c
|
||||||
|
include psutil/arch/freebsd/sys_socks.h
|
||||||
|
include psutil/arch/netbsd/socks.c
|
||||||
|
include psutil/arch/netbsd/socks.h
|
||||||
|
include psutil/arch/netbsd/specific.c
|
||||||
|
include psutil/arch/netbsd/specific.h
|
||||||
|
include psutil/arch/openbsd/specific.c
|
||||||
|
include psutil/arch/openbsd/specific.h
|
||||||
|
include psutil/arch/osx/process_info.c
|
||||||
|
include psutil/arch/osx/process_info.h
|
||||||
|
include psutil/arch/solaris/environ.c
|
||||||
|
include psutil/arch/solaris/environ.h
|
||||||
|
include psutil/arch/solaris/v10/ifaddrs.c
|
||||||
|
include psutil/arch/solaris/v10/ifaddrs.h
|
||||||
|
include psutil/arch/windows/glpi.h
|
||||||
|
include psutil/arch/windows/inet_ntop.c
|
||||||
|
include psutil/arch/windows/inet_ntop.h
|
||||||
|
include psutil/arch/windows/ntextapi.h
|
||||||
|
include psutil/arch/windows/process_handles.c
|
||||||
|
include psutil/arch/windows/process_handles.h
|
||||||
|
include psutil/arch/windows/process_info.c
|
||||||
|
include psutil/arch/windows/process_info.h
|
||||||
|
include psutil/arch/windows/security.c
|
||||||
|
include psutil/arch/windows/security.h
|
||||||
|
include psutil/arch/windows/services.c
|
||||||
|
include psutil/arch/windows/services.h
|
||||||
|
include psutil/tests/README.rst
|
||||||
|
include psutil/tests/__init__.py
|
||||||
|
include psutil/tests/__main__.py
|
||||||
|
include psutil/tests/test_aix.py
|
||||||
|
include psutil/tests/test_bsd.py
|
||||||
|
include psutil/tests/test_connections.py
|
||||||
|
include psutil/tests/test_contracts.py
|
||||||
|
include psutil/tests/test_linux.py
|
||||||
|
include psutil/tests/test_memory_leaks.py
|
||||||
|
include psutil/tests/test_misc.py
|
||||||
|
include psutil/tests/test_osx.py
|
||||||
|
include psutil/tests/test_posix.py
|
||||||
|
include psutil/tests/test_process.py
|
||||||
|
include psutil/tests/test_sunos.py
|
||||||
|
include psutil/tests/test_system.py
|
||||||
|
include psutil/tests/test_unicode.py
|
||||||
|
include psutil/tests/test_windows.py
|
||||||
|
include scripts/battery.py
|
||||||
|
include scripts/cpu_distribution.py
|
||||||
|
include scripts/disk_usage.py
|
||||||
|
include scripts/fans.py
|
||||||
|
include scripts/free.py
|
||||||
|
include scripts/ifconfig.py
|
||||||
|
include scripts/internal/README
|
||||||
|
include scripts/internal/bench_oneshot.py
|
||||||
|
include scripts/internal/bench_oneshot_2.py
|
||||||
|
include scripts/internal/check_broken_links.py
|
||||||
|
include scripts/internal/download_exes.py
|
||||||
|
include scripts/internal/generate_manifest.py
|
||||||
|
include scripts/internal/print_announce.py
|
||||||
|
include scripts/internal/print_timeline.py
|
||||||
|
include scripts/internal/winmake.py
|
||||||
|
include scripts/iotop.py
|
||||||
|
include scripts/killall.py
|
||||||
|
include scripts/meminfo.py
|
||||||
|
include scripts/netstat.py
|
||||||
|
include scripts/nettop.py
|
||||||
|
include scripts/pidof.py
|
||||||
|
include scripts/pmap.py
|
||||||
|
include scripts/procinfo.py
|
||||||
|
include scripts/procsmem.py
|
||||||
|
include scripts/ps.py
|
||||||
|
include scripts/pstree.py
|
||||||
|
include scripts/sensors.py
|
||||||
|
include scripts/temperatures.py
|
||||||
|
include scripts/top.py
|
||||||
|
include scripts/who.py
|
||||||
|
include scripts/winservices.py
|
||||||
include setup.py
|
include setup.py
|
||||||
include TODO
|
|
||||||
include tox.ini
|
include tox.ini
|
||||||
recursive-exclude docs/_build *
|
|
||||||
recursive-include .appveyor/*
|
|
||||||
recursive-include docs *
|
|
||||||
recursive-include examples *.py
|
|
||||||
recursive-include psutil *.py *.c *.h
|
|
||||||
recursive-include test *.py README*
|
|
||||||
|
|
|
@ -1,122 +1,269 @@
|
||||||
# Shortcuts for various tasks (UNIX only).
|
# Shortcuts for various tasks (UNIX only).
|
||||||
# To use a specific Python version run:
|
# To use a specific Python version run: "make install PYTHON=python3.3"
|
||||||
# $ make install PYTHON=python3.3
|
# You can set the variables below from the command line.
|
||||||
|
|
||||||
# You can set these variables from the command line.
|
PYTHON = python
|
||||||
PYTHON = python
|
TSCRIPT = psutil/tests/__main__.py
|
||||||
TSCRIPT = test/test_psutil.py
|
ARGS =
|
||||||
|
# List of nice-to-have dev libs.
|
||||||
|
DEPS = \
|
||||||
|
argparse \
|
||||||
|
check-manifest \
|
||||||
|
coverage \
|
||||||
|
flake8 \
|
||||||
|
futures \
|
||||||
|
ipaddress \
|
||||||
|
mock==1.0.1 \
|
||||||
|
pep8 \
|
||||||
|
perf \
|
||||||
|
pyflakes \
|
||||||
|
requests \
|
||||||
|
setuptools \
|
||||||
|
sphinx \
|
||||||
|
twine \
|
||||||
|
unittest2 \
|
||||||
|
wheel
|
||||||
|
|
||||||
|
# In not in a virtualenv, add --user options for install commands.
|
||||||
|
INSTALL_OPTS = `$(PYTHON) -c "import sys; print('' if hasattr(sys, 'real_prefix') else '--user')"`
|
||||||
|
TEST_PREFIX = PYTHONWARNINGS=all PSUTIL_TESTING=1 PSUTIL_DEBUG=1
|
||||||
|
|
||||||
all: test
|
all: test
|
||||||
|
|
||||||
clean:
|
# ===================================================================
|
||||||
rm -f `find . -type f -name \*.py[co]`
|
# Install
|
||||||
rm -f `find . -type f -name \*.so`
|
# ===================================================================
|
||||||
rm -f `find . -type f -name .\*~`
|
|
||||||
rm -f `find . -type f -name \*.orig`
|
|
||||||
rm -f `find . -type f -name \*.bak`
|
|
||||||
rm -f `find . -type f -name \*.rej`
|
|
||||||
rm -rf `find . -type d -name __pycache__`
|
|
||||||
rm -rf *.core
|
|
||||||
rm -rf *.egg-info
|
|
||||||
rm -rf *\$testfile*
|
|
||||||
rm -rf .coverage
|
|
||||||
rm -rf .tox
|
|
||||||
rm -rf build
|
|
||||||
rm -rf dist
|
|
||||||
rm -rf docs/_build
|
|
||||||
rm -rf htmlcov
|
|
||||||
|
|
||||||
build: clean
|
clean: ## Remove all build files.
|
||||||
$(PYTHON) setup.py build
|
rm -rf `find . -type d -name __pycache__ \
|
||||||
@# copies *.so files in ./psutil directory in order to allow
|
-o -type f -name \*.bak \
|
||||||
|
-o -type f -name \*.orig \
|
||||||
|
-o -type f -name \*.pyc \
|
||||||
|
-o -type f -name \*.pyd \
|
||||||
|
-o -type f -name \*.pyo \
|
||||||
|
-o -type f -name \*.rej \
|
||||||
|
-o -type f -name \*.so \
|
||||||
|
-o -type f -name \*.~ \
|
||||||
|
-o -type f -name \*\$testfn`
|
||||||
|
rm -rf \
|
||||||
|
*.core \
|
||||||
|
*.egg-info \
|
||||||
|
*\$testfn* \
|
||||||
|
.coverage \
|
||||||
|
.tox \
|
||||||
|
build/ \
|
||||||
|
dist/ \
|
||||||
|
docs/_build/ \
|
||||||
|
htmlcov/ \
|
||||||
|
tmp/
|
||||||
|
|
||||||
|
_:
|
||||||
|
|
||||||
|
build: _ ## Compile without installing.
|
||||||
|
# make sure setuptools is installed (needed for 'develop' / edit mode)
|
||||||
|
$(PYTHON) -c "import setuptools"
|
||||||
|
PYTHONWARNINGS=all $(PYTHON) setup.py build
|
||||||
|
@# copies compiled *.so files in ./psutil directory in order to allow
|
||||||
@# "import psutil" when using the interactive interpreter from within
|
@# "import psutil" when using the interactive interpreter from within
|
||||||
@# this directory.
|
@# this directory.
|
||||||
$(PYTHON) setup.py build_ext -i
|
PYTHONWARNINGS=all $(PYTHON) setup.py build_ext -i
|
||||||
|
rm -rf tmp
|
||||||
|
$(PYTHON) -c "import psutil" # make sure it actually worked
|
||||||
|
|
||||||
# useful deps which are nice to have while developing / testing
|
install: ## Install this package as current user in "edit" mode.
|
||||||
setup-dev-env:
|
${MAKE} build
|
||||||
python -c "import urllib2; \
|
PYTHONWARNINGS=all $(PYTHON) setup.py develop $(INSTALL_OPTS)
|
||||||
r = urllib2.urlopen('https://bootstrap.pypa.io/get-pip.py'); \
|
rm -rf tmp
|
||||||
open('/tmp/get-pip.py', 'w').write(r.read());"
|
|
||||||
$(PYTHON) /tmp/get-pip.py --user
|
|
||||||
rm /tmp/get-pip.py
|
|
||||||
$(PYTHON) -m pip install --user --upgrade pip
|
|
||||||
$(PYTHON) -m pip install --user --upgrade \
|
|
||||||
coverage \
|
|
||||||
flake8 \
|
|
||||||
ipaddress \
|
|
||||||
ipdb \
|
|
||||||
mock==1.0.1 \
|
|
||||||
nose \
|
|
||||||
pep8 \
|
|
||||||
pyflakes \
|
|
||||||
sphinx \
|
|
||||||
sphinx-pypi-upload \
|
|
||||||
unittest2 \
|
|
||||||
|
|
||||||
install: build
|
uninstall: ## Uninstall this package via pip.
|
||||||
$(PYTHON) setup.py install --user
|
|
||||||
|
|
||||||
uninstall:
|
|
||||||
cd ..; $(PYTHON) -m pip uninstall -y -v psutil
|
cd ..; $(PYTHON) -m pip uninstall -y -v psutil
|
||||||
|
|
||||||
test: install
|
install-pip: ## Install pip (no-op if already installed).
|
||||||
$(PYTHON) $(TSCRIPT)
|
$(PYTHON) -c \
|
||||||
|
"import sys, ssl, os, pkgutil, tempfile, atexit; \
|
||||||
|
sys.exit(0) if pkgutil.find_loader('pip') else None; \
|
||||||
|
pyexc = 'from urllib.request import urlopen' if sys.version_info[0] == 3 else 'from urllib2 import urlopen'; \
|
||||||
|
exec(pyexc); \
|
||||||
|
ctx = ssl._create_unverified_context() if hasattr(ssl, '_create_unverified_context') else None; \
|
||||||
|
kw = dict(context=ctx) if ctx else {}; \
|
||||||
|
req = urlopen('https://bootstrap.pypa.io/get-pip.py', **kw); \
|
||||||
|
data = req.read(); \
|
||||||
|
f = tempfile.NamedTemporaryFile(suffix='.py'); \
|
||||||
|
atexit.register(f.close); \
|
||||||
|
f.write(data); \
|
||||||
|
f.flush(); \
|
||||||
|
print('downloaded %s' % f.name); \
|
||||||
|
code = os.system('%s %s --user' % (sys.executable, f.name)); \
|
||||||
|
f.close(); \
|
||||||
|
sys.exit(code);"
|
||||||
|
|
||||||
test-process: install
|
setup-dev-env: ## Install GIT hooks, pip, test deps (also upgrades them).
|
||||||
$(PYTHON) -m unittest -v test.test_psutil.TestProcess
|
${MAKE} install-git-hooks
|
||||||
|
${MAKE} install-pip
|
||||||
|
$(PYTHON) -m pip install $(INSTALL_OPTS) --upgrade pip
|
||||||
|
$(PYTHON) -m pip install $(INSTALL_OPTS) --upgrade $(DEPS)
|
||||||
|
|
||||||
test-system: install
|
# ===================================================================
|
||||||
$(PYTHON) -m unittest -v test.test_psutil.TestSystemAPIs
|
# Tests
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
test-memleaks: install
|
test: ## Run all tests.
|
||||||
$(PYTHON) test/test_memory_leaks.py
|
${MAKE} install
|
||||||
|
$(TEST_PREFIX) $(PYTHON) $(TSCRIPT)
|
||||||
|
|
||||||
# Run a specific test by name; e.g. "make test-by-name disk_" will run
|
test-process: ## Run process-related API tests.
|
||||||
# all test methods containing "disk_" in their name.
|
${MAKE} install
|
||||||
# Requires "pip install nose".
|
$(TEST_PREFIX) $(PYTHON) -m unittest -v psutil.tests.test_process
|
||||||
test-by-name: install
|
|
||||||
@$(PYTHON) -m nose test/test_psutil.py test/_* --nocapture -v -m $(filter-out $@,$(MAKECMDGOALS))
|
|
||||||
|
|
||||||
# Same as above but for test_memory_leaks.py script.
|
test-system: ## Run system-related API tests.
|
||||||
test-memleaks-by-name: install
|
${MAKE} install
|
||||||
@$(PYTHON) -m nose test/test_memory_leaks.py --nocapture -v -m $(filter-out $@,$(MAKECMDGOALS))
|
$(TEST_PREFIX) $(PYTHON) -m unittest -v psutil.tests.test_system
|
||||||
|
|
||||||
coverage: install
|
test-misc: ## Run miscellaneous tests.
|
||||||
|
${MAKE} install
|
||||||
|
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_misc.py
|
||||||
|
|
||||||
|
test-unicode: ## Test APIs dealing with strings.
|
||||||
|
${MAKE} install
|
||||||
|
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_unicode.py
|
||||||
|
|
||||||
|
test-contracts: ## APIs sanity tests.
|
||||||
|
${MAKE} install
|
||||||
|
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_contracts.py
|
||||||
|
|
||||||
|
test-connections: ## Test net_connections() and Process.connections().
|
||||||
|
${MAKE} install
|
||||||
|
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_connections.py
|
||||||
|
|
||||||
|
test-posix: ## POSIX specific tests.
|
||||||
|
${MAKE} install
|
||||||
|
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_posix.py
|
||||||
|
|
||||||
|
test-platform: ## Run specific platform tests only.
|
||||||
|
${MAKE} install
|
||||||
|
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_`$(PYTHON) -c 'import psutil; print([x.lower() for x in ("LINUX", "BSD", "OSX", "SUNOS", "WINDOWS", "AIX") if getattr(psutil, x)][0])'`.py
|
||||||
|
|
||||||
|
test-memleaks: ## Memory leak tests.
|
||||||
|
${MAKE} install
|
||||||
|
$(TEST_PREFIX) $(PYTHON) psutil/tests/test_memory_leaks.py
|
||||||
|
|
||||||
|
test-by-name: ## e.g. make test-by-name ARGS=psutil.tests.test_system.TestSystemAPIs
|
||||||
|
${MAKE} install
|
||||||
|
@$(TEST_PREFIX) $(PYTHON) -m unittest -v $(ARGS)
|
||||||
|
|
||||||
|
test-coverage: ## Run test coverage.
|
||||||
|
${MAKE} install
|
||||||
# Note: coverage options are controlled by .coveragerc file
|
# Note: coverage options are controlled by .coveragerc file
|
||||||
rm -rf .coverage htmlcov
|
rm -rf .coverage htmlcov
|
||||||
$(PYTHON) -m coverage run $(TSCRIPT)
|
$(TEST_PREFIX) $(PYTHON) -m coverage run $(TSCRIPT)
|
||||||
$(PYTHON) -m coverage report
|
$(PYTHON) -m coverage report
|
||||||
@echo "writing results to htmlcov/index.html"
|
@echo "writing results to htmlcov/index.html"
|
||||||
$(PYTHON) -m coverage html
|
$(PYTHON) -m coverage html
|
||||||
$(PYTHON) -m webbrowser -t htmlcov/index.html
|
$(PYTHON) -m webbrowser -t htmlcov/index.html
|
||||||
|
|
||||||
pep8:
|
# ===================================================================
|
||||||
|
# Linters
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
pep8: ## PEP8 linter.
|
||||||
@git ls-files | grep \\.py$ | xargs $(PYTHON) -m pep8
|
@git ls-files | grep \\.py$ | xargs $(PYTHON) -m pep8
|
||||||
|
|
||||||
pyflakes:
|
pyflakes: ## Pyflakes linter.
|
||||||
@export PYFLAKES_NODOCTEST=1 && \
|
@export PYFLAKES_NODOCTEST=1 && \
|
||||||
git ls-files | grep \\.py$ | xargs $(PYTHON) -m pyflakes
|
git ls-files | grep \\.py$ | xargs $(PYTHON) -m pyflakes
|
||||||
|
|
||||||
flake8:
|
flake8: ## flake8 linter.
|
||||||
@git ls-files | grep \\.py$ | xargs $(PYTHON) -m flake8
|
@git ls-files | grep \\.py$ | xargs $(PYTHON) -m flake8
|
||||||
|
|
||||||
# Upload source tarball on https://pypi.python.org/pypi/psutil.
|
# ===================================================================
|
||||||
upload-src: clean
|
# GIT
|
||||||
$(PYTHON) setup.py sdist upload
|
# ===================================================================
|
||||||
|
|
||||||
# Build and upload doc on https://pythonhosted.org/psutil/.
|
git-tag-release: ## Git-tag a new release.
|
||||||
# Requires "pip install sphinx-pypi-upload".
|
|
||||||
upload-doc:
|
|
||||||
cd docs; make html
|
|
||||||
$(PYTHON) setup.py upload_sphinx --upload-dir=docs/_build/html
|
|
||||||
|
|
||||||
# git-tag a new release
|
|
||||||
git-tag-release:
|
|
||||||
git tag -a release-`python -c "import setup; print(setup.get_version())"` -m `git rev-list HEAD --count`:`git rev-parse --short HEAD`
|
git tag -a release-`python -c "import setup; print(setup.get_version())"` -m `git rev-list HEAD --count`:`git rev-parse --short HEAD`
|
||||||
echo "done; now run 'git push --follow-tags' to push the new tag on the remote repo"
|
git push --follow-tags
|
||||||
|
|
||||||
# install GIT pre-commit hook
|
install-git-hooks: ## Install GIT pre-commit hook.
|
||||||
install-git-hooks:
|
|
||||||
ln -sf ../../.git-pre-commit .git/hooks/pre-commit
|
ln -sf ../../.git-pre-commit .git/hooks/pre-commit
|
||||||
chmod +x .git/hooks/pre-commit
|
chmod +x .git/hooks/pre-commit
|
||||||
|
|
||||||
|
# ===================================================================
|
||||||
|
# Distribution
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
# --- create
|
||||||
|
|
||||||
|
sdist: ## Create tar.gz source distribution.
|
||||||
|
${MAKE} generate-manifest
|
||||||
|
$(PYTHON) setup.py sdist
|
||||||
|
|
||||||
|
wheel: ## Generate wheel.
|
||||||
|
$(PYTHON) setup.py bdist_wheel
|
||||||
|
|
||||||
|
win-download-wheels: ## Download wheels hosted on appveyor.
|
||||||
|
$(TEST_PREFIX) $(PYTHON) scripts/internal/download_exes.py --user giampaolo --project psutil
|
||||||
|
|
||||||
|
# --- upload
|
||||||
|
|
||||||
|
upload-src: ## Upload source tarball on https://pypi.python.org/pypi/psutil.
|
||||||
|
${MAKE} sdist
|
||||||
|
$(PYTHON) setup.py sdist upload
|
||||||
|
|
||||||
|
upload-win-wheels: ## Upload wheels in dist/* directory on PYPI.
|
||||||
|
$(PYTHON) -m twine upload dist/*.whl
|
||||||
|
|
||||||
|
# --- others
|
||||||
|
|
||||||
|
pre-release: ## Check if we're ready to produce a new release.
|
||||||
|
rm -rf dist
|
||||||
|
${MAKE} install
|
||||||
|
${MAKE} generate-manifest
|
||||||
|
git diff MANIFEST.in > /dev/null # ...otherwise 'git diff-index HEAD' will complain
|
||||||
|
${MAKE} win-download-wheels
|
||||||
|
${MAKE} sdist
|
||||||
|
$(PYTHON) -c \
|
||||||
|
"from psutil import __version__ as ver; \
|
||||||
|
doc = open('docs/index.rst').read(); \
|
||||||
|
history = open('HISTORY.rst').read(); \
|
||||||
|
assert ver in doc, '%r not in docs/index.rst' % ver; \
|
||||||
|
assert ver in history, '%r not in HISTORY.rst' % ver; \
|
||||||
|
assert 'XXXX' not in history, 'XXXX in HISTORY.rst';"
|
||||||
|
$(PYTHON) -c "import subprocess, sys; out = subprocess.check_output('git diff --quiet && git diff --cached --quiet', shell=True).strip(); sys.exit('there are uncommitted changes:\n%s' % out) if out else 0 ;"
|
||||||
|
|
||||||
|
release: ## Create a release (down/uploads tar.gz, wheels, git tag release).
|
||||||
|
${MAKE} pre-release
|
||||||
|
$(PYTHON) -m twine upload dist/* # upload tar.gz and Windows wheels on PYPI
|
||||||
|
${MAKE} git-tag-release
|
||||||
|
|
||||||
|
print-announce: ## Print announce of new release.
|
||||||
|
@$(TEST_PREFIX) $(PYTHON) scripts/internal/print_announce.py
|
||||||
|
|
||||||
|
print-timeline: ## Print releases' timeline.
|
||||||
|
@$(TEST_PREFIX) $(PYTHON) scripts/internal/print_timeline.py
|
||||||
|
|
||||||
|
check-manifest: ## Inspect MANIFEST.in file.
|
||||||
|
$(PYTHON) -m check_manifest -v $(ARGS)
|
||||||
|
|
||||||
|
generate-manifest: ## Generates MANIFEST.in file.
|
||||||
|
$(PYTHON) scripts/internal/generate_manifest.py > MANIFEST.in
|
||||||
|
|
||||||
|
# ===================================================================
|
||||||
|
# Misc
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
grep-todos: ## Look for TODOs in the source files.
|
||||||
|
git grep -EIn "TODO|FIXME|XXX"
|
||||||
|
|
||||||
|
bench-oneshot: ## Benchmarks for oneshot() ctx manager (see #799).
|
||||||
|
${MAKE} install
|
||||||
|
$(TEST_PREFIX) $(PYTHON) scripts/internal/bench_oneshot.py
|
||||||
|
|
||||||
|
bench-oneshot-2: ## Same as above but using perf module (supposed to be more precise)
|
||||||
|
${MAKE} install
|
||||||
|
$(TEST_PREFIX) $(PYTHON) scripts/internal/bench_oneshot_2.py
|
||||||
|
|
||||||
|
check-broken-links: ## Look for broken links in source files.
|
||||||
|
git ls-files | xargs $(PYTHON) -Wa scripts/internal/check_broken_links.py
|
||||||
|
|
||||||
|
help: ## Display callable targets.
|
||||||
|
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
|
||||||
|
|
|
@ -1,28 +1,29 @@
|
||||||
Metadata-Version: 1.1
|
Metadata-Version: 1.1
|
||||||
Name: psutil
|
Name: psutil
|
||||||
Version: 3.1.1
|
Version: 5.4.3
|
||||||
Summary: psutil is a cross-platform library for retrieving information onrunning processes and system utilization (CPU, memory, disks, network)in Python.
|
Summary: Cross-platform lib for process and system monitoring in Python.
|
||||||
Home-page: https://github.com/giampaolo/psutil
|
Home-page: https://github.com/giampaolo/psutil
|
||||||
Author: Giampaolo Rodola
|
Author: Giampaolo Rodola
|
||||||
Author-email: g.rodola <at> gmail <dot> com
|
Author-email: g.rodola@gmail.com
|
||||||
License: BSD
|
License: BSD
|
||||||
Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
Description-Content-Type: UNKNOWN
|
||||||
:target: https://pypi.python.org/pypi/psutil#downloads
|
Description: .. image:: https://img.shields.io/travis/giampaolo/psutil/master.svg?maxAge=3600&label=Linux%20/%20OSX
|
||||||
:alt: Downloads this month
|
|
||||||
|
|
||||||
.. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master
|
|
||||||
:target: https://travis-ci.org/giampaolo/psutil
|
:target: https://travis-ci.org/giampaolo/psutil
|
||||||
:alt: Linux tests (Travis)
|
:alt: Linux tests (Travis)
|
||||||
|
|
||||||
.. image:: https://ci.appveyor.com/api/projects/status/qdwvw7v1t915ywr5/branch/master?svg=true
|
.. image:: https://img.shields.io/appveyor/ci/giampaolo/psutil/master.svg?maxAge=3600&label=Windows
|
||||||
:target: https://ci.appveyor.com/project/giampaolo/psutil
|
:target: https://ci.appveyor.com/project/giampaolo/psutil
|
||||||
:alt: Windows tests (Appveyor)
|
:alt: Windows tests (Appveyor)
|
||||||
|
|
||||||
.. image:: https://coveralls.io/repos/giampaolo/psutil/badge.svg?branch=master&service=github
|
.. image:: https://coveralls.io/repos/github/giampaolo/psutil/badge.svg?branch=master
|
||||||
:target: https://coveralls.io/github/giampaolo/psutil?branch=master
|
:target: https://coveralls.io/github/giampaolo/psutil?branch=master
|
||||||
:alt: Test coverage (coverall.io)
|
:alt: Test coverage (coverall.io)
|
||||||
|
|
||||||
.. image:: https://img.shields.io/pypi/v/psutil.svg
|
.. image:: https://readthedocs.org/projects/psutil/badge/?version=latest
|
||||||
|
:target: http://psutil.readthedocs.io/en/latest/?badge=latest
|
||||||
|
:alt: Documentation Status
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/pypi/v/psutil.svg?label=pypi
|
||||||
:target: https://pypi.python.org/pypi/psutil/
|
:target: https://pypi.python.org/pypi/psutil/
|
||||||
:alt: Latest version
|
:alt: Latest version
|
||||||
|
|
||||||
|
@ -30,10 +31,6 @@ Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||||
:target: https://github.com/giampaolo/psutil/
|
:target: https://github.com/giampaolo/psutil/
|
||||||
:alt: Github stars
|
:alt: Github stars
|
||||||
|
|
||||||
.. image:: https://img.shields.io/scrutinizer/g/giampaolo/psutil.svg
|
|
||||||
:target: https://scrutinizer-ci.com/g/giampaolo/psutil/
|
|
||||||
:alt: Code quality (scrutinizer-ci.com)
|
|
||||||
|
|
||||||
.. image:: https://img.shields.io/pypi/l/psutil.svg
|
.. image:: https://img.shields.io/pypi/l/psutil.svg
|
||||||
:target: https://pypi.python.org/pypi/psutil/
|
:target: https://pypi.python.org/pypi/psutil/
|
||||||
:alt: License
|
:alt: License
|
||||||
|
@ -43,8 +40,8 @@ Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||||
===========
|
===========
|
||||||
|
|
||||||
- `Home page <https://github.com/giampaolo/psutil>`_
|
- `Home page <https://github.com/giampaolo/psutil>`_
|
||||||
- `Documentation <http://pythonhosted.org/psutil/>`_
|
- `Install <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
|
||||||
- `Installation <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
|
- `Documentation <http://psutil.readthedocs.io>`_
|
||||||
- `Download <https://pypi.python.org/pypi?:action=display&name=psutil#downloads>`_
|
- `Download <https://pypi.python.org/pypi?:action=display&name=psutil#downloads>`_
|
||||||
- `Forum <http://groups.google.com/group/psutil/topics>`_
|
- `Forum <http://groups.google.com/group/psutil/topics>`_
|
||||||
- `Blog <http://grodola.blogspot.com/search/label/psutil>`_
|
- `Blog <http://grodola.blogspot.com/search/label/psutil>`_
|
||||||
|
@ -55,39 +52,70 @@ Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||||
Summary
|
Summary
|
||||||
=======
|
=======
|
||||||
|
|
||||||
psutil (python system and process utilities) is a cross-platform library for
|
psutil (process and system utilities) is a cross-platform library for
|
||||||
retrieving information on **running processes** and **system utilization**
|
retrieving information on **running processes** and **system utilization**
|
||||||
(CPU, memory, disks, network) in Python. It is useful mainly for **system
|
(CPU, memory, disks, network, sensors) in Python.
|
||||||
monitoring**, **profiling and limiting process resources** and **management of
|
It is useful mainly for **system monitoring**, **profiling and limiting process
|
||||||
running processes**. It implements many functionalities offered by command line
|
resources** and **management of running processes**.
|
||||||
tools such as: ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice,
|
It implements many functionalities offered by UNIX command line tools such as:
|
||||||
ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap. It currently supports
|
ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice, ionice, iostat,
|
||||||
**Linux, Windows, OSX, FreeBSD** and **Sun Solaris**, both **32-bit** and
|
iotop, uptime, pidof, tty, taskset, pmap.
|
||||||
**64-bit** architectures, with Python versions from **2.6 to 3.5** (users of
|
psutil currently supports the following platforms:
|
||||||
Python 2.4 and 2.5 may use `2.1.3 <https://pypi.python.org/pypi?name=psutil&version=2.1.3&:action=files>`__ version).
|
|
||||||
|
- **Linux**
|
||||||
|
- **Windows**
|
||||||
|
- **OSX**,
|
||||||
|
- **FreeBSD, OpenBSD**, **NetBSD**
|
||||||
|
- **Sun Solaris**
|
||||||
|
- **AIX**
|
||||||
|
|
||||||
|
...both **32-bit** and **64-bit** architectures, with Python
|
||||||
|
versions from **2.6 to 3.6**.
|
||||||
`PyPy <http://pypy.org/>`__ is also known to work.
|
`PyPy <http://pypy.org/>`__ is also known to work.
|
||||||
|
|
||||||
====================
|
====================
|
||||||
Example applications
|
Example applications
|
||||||
====================
|
====================
|
||||||
|
|
||||||
.. image:: http://psutil.googlecode.com/svn/wiki/images/top-thumb.png
|
+------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
|
||||||
:target: http://psutil.googlecode.com/svn/wiki/images/top.png
|
| .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/procinfo-small.png | .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/top-small.png |
|
||||||
:alt: top
|
| :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/procinfo.png | :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/top.png |
|
||||||
|
+------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
|
||||||
|
| .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/procsmem-small.png | .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/pmap-small.png |
|
||||||
|
| :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/procsmem.png | :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/pmap.png |
|
||||||
|
+------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
|
||||||
|
|
||||||
.. image:: http://psutil.googlecode.com/svn/wiki/images/nettop-thumb.png
|
Also see `scripts directory <https://github.com/giampaolo/psutil/tree/master/scripts>`__
|
||||||
:target: http://psutil.googlecode.com/svn/wiki/images/nettop.png
|
and `doc recipes <http://psutil.readthedocs.io/#recipes/>`__.
|
||||||
:alt: nettop
|
|
||||||
|
|
||||||
.. image:: http://psutil.googlecode.com/svn/wiki/images/iotop-thumb.png
|
=====================
|
||||||
:target: http://psutil.googlecode.com/svn/wiki/images/iotop.png
|
Projects using psutil
|
||||||
:alt: iotop
|
=====================
|
||||||
|
|
||||||
See also:
|
At the time of writing psutil has roughly
|
||||||
|
`2.9 milion downloads <https://github.com/giampaolo/psutil/issues/1053#issuecomment-340166262>`__
|
||||||
|
per month and there are over
|
||||||
|
`6000 open source projects <https://libraries.io/pypi/psutil/dependent_repositories?page=1>`__
|
||||||
|
on github which depend from psutil.
|
||||||
|
Here's some I find particularly interesting:
|
||||||
|
|
||||||
* https://github.com/nicolargo/glances
|
- https://github.com/facebook/osquery/
|
||||||
* https://github.com/google/grr
|
- https://github.com/nicolargo/glances
|
||||||
* https://github.com/Jahaja/psdash
|
- https://github.com/google/grr
|
||||||
|
- https://github.com/Jahaja/psdash
|
||||||
|
- https://github.com/ajenti/ajenti
|
||||||
|
- https://github.com/home-assistant/home-assistant/
|
||||||
|
|
||||||
|
========
|
||||||
|
Portings
|
||||||
|
========
|
||||||
|
|
||||||
|
- Go: https://github.com/shirou/gopsutil
|
||||||
|
- C: https://github.com/hamon-in/cpslib
|
||||||
|
- Node: https://github.com/christkv/node-psutil
|
||||||
|
- Rust: https://github.com/borntyping/rust-psutil
|
||||||
|
- Ruby: https://github.com/spacewander/posixpsutil
|
||||||
|
- Nim: https://github.com/johnscillieri/psutil-nim
|
||||||
|
|
||||||
==============
|
==============
|
||||||
Example usages
|
Example usages
|
||||||
|
@ -116,7 +144,6 @@ Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||||
[7.0, 8.5, 2.4, 2.1]
|
[7.0, 8.5, 2.4, 2.1]
|
||||||
[1.2, 9.0, 9.9, 7.2]
|
[1.2, 9.0, 9.9, 7.2]
|
||||||
>>>
|
>>>
|
||||||
>>>
|
|
||||||
>>> for x in range(3):
|
>>> for x in range(3):
|
||||||
... psutil.cpu_times_percent(interval=1, percpu=False)
|
... psutil.cpu_times_percent(interval=1, percpu=False)
|
||||||
...
|
...
|
||||||
|
@ -129,14 +156,21 @@ Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||||
>>> psutil.cpu_count(logical=False)
|
>>> psutil.cpu_count(logical=False)
|
||||||
2
|
2
|
||||||
>>>
|
>>>
|
||||||
|
>>> psutil.cpu_stats()
|
||||||
|
scpustats(ctx_switches=20455687, interrupts=6598984, soft_interrupts=2134212, syscalls=0)
|
||||||
|
>>>
|
||||||
|
>>> psutil.cpu_freq()
|
||||||
|
scpufreq(current=931.42925, min=800.0, max=3500.0)
|
||||||
|
>>>
|
||||||
|
|
||||||
Memory
|
Memory
|
||||||
======
|
======
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> import psutil
|
||||||
>>> psutil.virtual_memory()
|
>>> psutil.virtual_memory()
|
||||||
svmem(total=8374149120, available=2081050624, percent=75.1, used=8074080256, free=300068864, active=3294920704, inactive=1361616896, buffers=529895424, cached=1251086336)
|
svmem(total=10367352832, available=6472179712, percent=37.6, used=8186245120, free=2181107712, active=4748992512, inactive=2758115328, buffers=790724608, cached=3500347392, shared=787554304)
|
||||||
>>> psutil.swap_memory()
|
>>> psutil.swap_memory()
|
||||||
sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)
|
sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)
|
||||||
>>>
|
>>>
|
||||||
|
@ -146,6 +180,7 @@ Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> import psutil
|
||||||
>>> psutil.disk_partitions()
|
>>> psutil.disk_partitions()
|
||||||
[sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
|
[sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
|
||||||
sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
|
sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
|
||||||
|
@ -154,7 +189,7 @@ Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||||
sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
|
sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
|
||||||
>>>
|
>>>
|
||||||
>>> psutil.disk_io_counters(perdisk=False)
|
>>> psutil.disk_io_counters(perdisk=False)
|
||||||
sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568)
|
sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568, read_merged_count=619166, write_merged_count=812396, busy_time=4523412)
|
||||||
>>>
|
>>>
|
||||||
|
|
||||||
Network
|
Network
|
||||||
|
@ -162,37 +197,62 @@ Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> import psutil
|
||||||
>>> psutil.net_io_counters(pernic=True)
|
>>> psutil.net_io_counters(pernic=True)
|
||||||
{'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0),
|
{'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0),
|
||||||
'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)}
|
'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)}
|
||||||
>>>
|
>>>
|
||||||
>>> psutil.net_connections()
|
>>> psutil.net_connections()
|
||||||
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254),
|
[sconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED', pid=1254),
|
||||||
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987),
|
sconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING', pid=2987),
|
||||||
pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None),
|
sconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=60759), raddr=addr(ip='72.14.234.104', port=80), status='ESTABLISHED', pid=None),
|
||||||
pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None)
|
sconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=51314), raddr=addr(ip='72.14.234.83', port=443), status='SYN_SENT', pid=None)
|
||||||
...]
|
...]
|
||||||
>>>
|
>>>
|
||||||
>>> psutil.net_if_addrs()
|
>>> psutil.net_if_addrs()
|
||||||
{'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1'),
|
{'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None),
|
||||||
snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None),
|
snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),
|
||||||
snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00')],
|
snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)],
|
||||||
'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255'),
|
'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
|
||||||
snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None),
|
snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),
|
||||||
snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff')]}
|
snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}
|
||||||
>>>
|
>>>
|
||||||
>>> psutil.net_if_stats()
|
>>> psutil.net_if_stats()
|
||||||
{'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
|
{'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
|
||||||
'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
|
'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
|
||||||
|
>>>
|
||||||
|
|
||||||
|
Sensors
|
||||||
|
=======
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> import psutil
|
||||||
|
>>> psutil.sensors_temperatures()
|
||||||
|
{'acpitz': [shwtemp(label='', current=47.0, high=103.0, critical=103.0)],
|
||||||
|
'asus': [shwtemp(label='', current=47.0, high=None, critical=None)],
|
||||||
|
'coretemp': [shwtemp(label='Physical id 0', current=52.0, high=100.0, critical=100.0),
|
||||||
|
shwtemp(label='Core 0', current=45.0, high=100.0, critical=100.0),
|
||||||
|
shwtemp(label='Core 1', current=52.0, high=100.0, critical=100.0),
|
||||||
|
shwtemp(label='Core 2', current=45.0, high=100.0, critical=100.0),
|
||||||
|
shwtemp(label='Core 3', current=47.0, high=100.0, critical=100.0)]}
|
||||||
|
>>>
|
||||||
|
>>> psutil.sensors_fans()
|
||||||
|
{'asus': [sfan(label='cpu_fan', current=3200)]}
|
||||||
|
>>>
|
||||||
|
>>> psutil.sensors_battery()
|
||||||
|
sbattery(percent=93, secsleft=16628, power_plugged=False)
|
||||||
|
>>>
|
||||||
|
|
||||||
Other system info
|
Other system info
|
||||||
=================
|
=================
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> import psutil
|
||||||
>>> psutil.users()
|
>>> psutil.users()
|
||||||
[user(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0),
|
[suser(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0, pid=1352),
|
||||||
user(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)]
|
suser(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0, pid=1788)]
|
||||||
>>>
|
>>>
|
||||||
>>> psutil.boot_time()
|
>>> psutil.boot_time()
|
||||||
1365519115.0
|
1365519115.0
|
||||||
|
@ -205,12 +265,10 @@ Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||||
|
|
||||||
>>> import psutil
|
>>> import psutil
|
||||||
>>> psutil.pids()
|
>>> psutil.pids()
|
||||||
[1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224,
|
[1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224, 268, 1215, 1216, 1220, 1221, 1243, 1244,
|
||||||
268, 1215, 1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355,
|
1301, 1601, 2237, 2355, 2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245, 4263, 4282,
|
||||||
2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245,
|
4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358, 4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446,
|
||||||
4263, 4282, 4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358,
|
5167, 5234, 5235, 5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
|
||||||
4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446, 5167, 5234, 5235,
|
|
||||||
5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
|
|
||||||
>>>
|
>>>
|
||||||
>>> p = psutil.Process(7055)
|
>>> p = psutil.Process(7055)
|
||||||
>>> p.name()
|
>>> p.name()
|
||||||
|
@ -222,6 +280,16 @@ Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||||
>>> p.cmdline()
|
>>> p.cmdline()
|
||||||
['/usr/bin/python', 'main.py']
|
['/usr/bin/python', 'main.py']
|
||||||
>>>
|
>>>
|
||||||
|
>>> p.pid
|
||||||
|
7055
|
||||||
|
>>> p.ppid()
|
||||||
|
7054
|
||||||
|
>>> p.parent()
|
||||||
|
<psutil.Process(pid=7054, name='bash') at 140008329539408>
|
||||||
|
>>> p.children()
|
||||||
|
[<psutil.Process(pid=8031, name='python') at 14020832451977>,
|
||||||
|
<psutil.Process(pid=8044, name='python') at 19229444921932>]
|
||||||
|
>>>
|
||||||
>>> p.status()
|
>>> p.status()
|
||||||
'running'
|
'running'
|
||||||
>>> p.username()
|
>>> p.username()
|
||||||
|
@ -237,39 +305,41 @@ Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||||
pgids(real=1000, effective=1000, saved=1000)
|
pgids(real=1000, effective=1000, saved=1000)
|
||||||
>>>
|
>>>
|
||||||
>>> p.cpu_times()
|
>>> p.cpu_times()
|
||||||
pcputimes(user=1.02, system=0.31)
|
pcputimes(user=1.02, system=0.31, children_user=0.32, children_system=0.1)
|
||||||
>>> p.cpu_percent(interval=1.0)
|
>>> p.cpu_percent(interval=1.0)
|
||||||
12.1
|
12.1
|
||||||
>>> p.cpu_affinity()
|
>>> p.cpu_affinity()
|
||||||
[0, 1, 2, 3]
|
[0, 1, 2, 3]
|
||||||
>>> p.cpu_affinity([0]) # set
|
>>> p.cpu_affinity([0, 1]) # set
|
||||||
>>>
|
>>> p.cpu_num()
|
||||||
>>> p.memory_percent()
|
1
|
||||||
0.63423
|
|
||||||
>>>
|
>>>
|
||||||
>>> p.memory_info()
|
>>> p.memory_info()
|
||||||
pmem(rss=7471104, vms=68513792)
|
pmem(rss=10915840, vms=67608576, shared=3313664, text=2310144, lib=0, data=7262208, dirty=0)
|
||||||
>>> p.memory_info_ex()
|
>>> p.memory_full_info() # "real" USS memory usage (Linux, OSX, Win only)
|
||||||
extmem(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0)
|
pfullmem(rss=10199040, vms=52133888, shared=3887104, text=2867200, lib=0, data=5967872, dirty=0, uss=6545408, pss=6872064, swap=0)
|
||||||
|
>>> p.memory_percent()
|
||||||
|
0.7823
|
||||||
>>> p.memory_maps()
|
>>> p.memory_maps()
|
||||||
[pmmap_grouped(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0),
|
[pmmap_grouped(path='/lib/x8664-linux-gnu/libutil-2.15.so', rss=32768, size=2125824, pss=32768, shared_clean=0, shared_dirty=0, private_clean=20480, private_dirty=12288, referenced=32768, anonymous=12288, swap=0),
|
||||||
pmmap_grouped(path='/lib/x86_64-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0),
|
pmmap_grouped(path='/lib/x8664-linux-gnu/libc-2.15.so', rss=3821568, size=3842048, pss=3821568, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=3821568, referenced=3575808, anonymous=3821568, swap=0),
|
||||||
pmmap_grouped(path='/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', rss=34124, anonymous=1245, swap=0),
|
pmmap_grouped(path='/lib/x8664-linux-gnu/libcrypto.so.0.1', rss=34124, rss=32768, size=2134016, pss=15360, shared_clean=24576, shared_dirty=0, private_clean=0, private_dirty=8192, referenced=24576, anonymous=8192, swap=0),
|
||||||
pmmap_grouped(path='[heap]', rss=54653, anonymous=8192, swap=0),
|
pmmap_grouped(path='[heap]', rss=32768, size=139264, pss=32768, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=32768, referenced=32768, anonymous=32768, swap=0),
|
||||||
pmmap_grouped(path='[stack]', rss=1542, anonymous=166, swap=0),
|
pmmap_grouped(path='[stack]', rss=2465792, size=2494464, pss=2465792, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=2465792, referenced=2277376, anonymous=2465792, swap=0),
|
||||||
...]
|
...]
|
||||||
>>>
|
>>>
|
||||||
>>> p.io_counters()
|
>>> p.io_counters()
|
||||||
pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632)
|
pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632, read_chars=456232, write_chars=517543)
|
||||||
>>>
|
>>>
|
||||||
>>> p.open_files()
|
>>> p.open_files()
|
||||||
[popenfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)]
|
[popenfile(path='/home/giampaolo/svn/psutil/setup.py', fd=3, position=0, mode='r', flags=32768),
|
||||||
|
popenfile(path='/var/log/monitd', fd=4, position=235542, mode='a', flags=33793)]
|
||||||
>>>
|
>>>
|
||||||
>>> p.connections()
|
>>> p.connections()
|
||||||
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'),
|
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED'),
|
||||||
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'),
|
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING'),
|
||||||
pconn(fd=119, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'),
|
pconn(fd=119, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=60759), raddr=addr(ip='72.14.234.104', port=80), status='ESTABLISHED'),
|
||||||
pconn(fd=123, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')]
|
pconn(fd=123, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=51314), raddr=addr(ip='72.14.234.83', port=443), status='SYN_SENT')]
|
||||||
>>>
|
>>>
|
||||||
>>> p.num_threads()
|
>>> p.num_threads()
|
||||||
4
|
4
|
||||||
|
@ -296,6 +366,15 @@ Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||||
>>> p.rlimit(psutil.RLIMIT_NOFILE)
|
>>> p.rlimit(psutil.RLIMIT_NOFILE)
|
||||||
(5, 5)
|
(5, 5)
|
||||||
>>>
|
>>>
|
||||||
|
>>> p.environ()
|
||||||
|
{'LC_PAPER': 'it_IT.UTF-8', 'SHELL': '/bin/bash', 'GREP_OPTIONS': '--color=auto',
|
||||||
|
'XDG_CONFIG_DIRS': '/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg', 'COLORTERM': 'gnome-terminal',
|
||||||
|
...}
|
||||||
|
>>>
|
||||||
|
>>> p.as_dict()
|
||||||
|
{'status': 'running', 'num_ctx_switches': pctxsw(voluntary=63, involuntary=1), 'pid': 5457, ...}
|
||||||
|
>>> p.is_running()
|
||||||
|
True
|
||||||
>>> p.suspend()
|
>>> p.suspend()
|
||||||
>>> p.resume()
|
>>> p.resume()
|
||||||
>>>
|
>>>
|
||||||
|
@ -319,81 +398,87 @@ Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
>>> for p in psutil.process_iter():
|
>>> import psutil
|
||||||
... print(p)
|
>>> for proc in psutil.process_iter(attrs=['pid', 'name']):
|
||||||
|
... print(proc.info)
|
||||||
...
|
...
|
||||||
psutil.Process(pid=1, name='init')
|
{'pid': 1, 'name': 'systemd'}
|
||||||
psutil.Process(pid=2, name='kthreadd')
|
{'pid': 2, 'name': 'kthreadd'}
|
||||||
psutil.Process(pid=3, name='ksoftirqd/0')
|
{'pid': 3, 'name': 'ksoftirqd/0'}
|
||||||
...
|
...
|
||||||
>>>
|
>>>
|
||||||
|
>>> psutil.pid_exists(3)
|
||||||
|
True
|
||||||
|
>>>
|
||||||
>>> def on_terminate(proc):
|
>>> def on_terminate(proc):
|
||||||
... print("process {} terminated".format(proc))
|
... print("process {} terminated".format(proc))
|
||||||
...
|
...
|
||||||
>>> # waits for multiple processes to terminate
|
>>> # waits for multiple processes to terminate
|
||||||
>>> gone, alive = psutil.wait_procs(procs_list, 3, callback=on_terminate)
|
>>> gone, alive = psutil.wait_procs(procs_list, timeout=3, callback=on_terminate)
|
||||||
>>>
|
>>>
|
||||||
|
|
||||||
|
Popen wrapper:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> import psutil
|
||||||
|
>>> from subprocess import PIPE
|
||||||
|
>>> p = psutil.Popen(["/usr/bin/python", "-c", "print('hello')"], stdout=PIPE)
|
||||||
|
>>> p.name()
|
||||||
|
'python'
|
||||||
|
>>> p.username()
|
||||||
|
'giampaolo'
|
||||||
|
>>> p.communicate()
|
||||||
|
('hello\n', None)
|
||||||
|
>>> p.wait(timeout=2)
|
||||||
|
0
|
||||||
|
>>>
|
||||||
|
|
||||||
|
Windows services
|
||||||
|
================
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> list(psutil.win_service_iter())
|
||||||
|
[<WindowsService(name='AeLookupSvc', display_name='Application Experience') at 38850096>,
|
||||||
|
<WindowsService(name='ALG', display_name='Application Layer Gateway Service') at 38850128>,
|
||||||
|
<WindowsService(name='APNMCP', display_name='Ask Update Service') at 38850160>,
|
||||||
|
<WindowsService(name='AppIDSvc', display_name='Application Identity') at 38850192>,
|
||||||
|
...]
|
||||||
|
>>> s = psutil.win_service_get('alg')
|
||||||
|
>>> s.as_dict()
|
||||||
|
{'binpath': 'C:\\Windows\\System32\\alg.exe',
|
||||||
|
'description': 'Provides support for 3rd party protocol plug-ins for Internet Connection Sharing',
|
||||||
|
'display_name': 'Application Layer Gateway Service',
|
||||||
|
'name': 'alg',
|
||||||
|
'pid': None,
|
||||||
|
'start_type': 'manual',
|
||||||
|
'status': 'stopped',
|
||||||
|
'username': 'NT AUTHORITY\\LocalService'}
|
||||||
|
|
||||||
|
Other samples
|
||||||
|
=============
|
||||||
|
|
||||||
|
See `doc recipes <http://psutil.readthedocs.io/#recipes>`__.
|
||||||
|
|
||||||
======
|
======
|
||||||
Donate
|
Author
|
||||||
======
|
======
|
||||||
|
|
||||||
|
psutil was created and is maintained by
|
||||||
|
`Giampaolo Rodola' <http://grodola.blogspot.com/p/about.html>`__.
|
||||||
A lot of time and effort went into making psutil as it is right now.
|
A lot of time and effort went into making psutil as it is right now.
|
||||||
If you feel psutil is useful to you or your business and want to support its future development please consider donating me (`Giampaolo Rodola' <http://grodola.blogspot.com/p/about.html>`_) some money.
|
If you feel psutil is useful to you or your business and want to support its
|
||||||
I only ask for a small donation, but of course I appreciate any amount.
|
future development please consider donating me
|
||||||
|
(`Giampaolo <http://grodola.blogspot.com/p/about.html>`__) some money.
|
||||||
|
|
||||||
.. image:: http://www.paypal.com/en_US/i/btn/x-click-but04.gif
|
.. image:: http://www.paypal.com/en_US/i/btn/x-click-but04.gif
|
||||||
:target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
|
:target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
|
||||||
:alt: Donate via PayPal
|
:alt: Donate via PayPal
|
||||||
|
|
||||||
Don't want to donate money? Then maybe you could `write me a recommendation on Linkedin <http://www.linkedin.com/in/grodola>`_.
|
Don't want to donate money? Then maybe you could `write me a recommendation on Linkedin <https://www.linkedin.com/in/grodola>`_.
|
||||||
|
|
||||||
============
|
Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,pstree,monitoring,ulimit,prlimit,smem
|
||||||
Mailing list
|
|
||||||
============
|
|
||||||
|
|
||||||
http://groups.google.com/group/psutil/
|
|
||||||
|
|
||||||
========
|
|
||||||
Timeline
|
|
||||||
========
|
|
||||||
|
|
||||||
- 2015-07-15: `psutil-3.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.1.1.tar.gz>`_
|
|
||||||
- 2015-07-15: `psutil-3.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.1.0.tar.gz>`_
|
|
||||||
- 2015-06-18: `psutil-3.0.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.0.1.tar.gz>`_
|
|
||||||
- 2015-06-13: `psutil-3.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.0.0.tar.gz>`_
|
|
||||||
- 2015-02-02: `psutil-2.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.2.1.tar.gz>`_
|
|
||||||
- 2015-01-06: `psutil-2.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.2.0.tar.gz>`_
|
|
||||||
- 2014-09-26: `psutil-2.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.3.tar.gz>`_
|
|
||||||
- 2014-09-21: `psutil-2.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.2.tar.gz>`_
|
|
||||||
- 2014-04-30: `psutil-2.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.1.tar.gz>`_
|
|
||||||
- 2014-04-08: `psutil-2.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.0.tar.gz>`_
|
|
||||||
- 2014-03-10: `psutil-2.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.0.0.tar.gz>`_
|
|
||||||
- 2013-11-25: `psutil-1.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.2.1.tar.gz>`_
|
|
||||||
- 2013-11-20: `psutil-1.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.2.0.tar.gz>`_
|
|
||||||
- 2013-11-07: `psutil-1.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.3.tar.gz>`_
|
|
||||||
- 2013-10-22: `psutil-1.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.2.tar.gz>`_
|
|
||||||
- 2013-10-08: `psutil-1.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.1.tar.gz>`_
|
|
||||||
- 2013-09-28: `psutil-1.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.0.tar.gz>`_
|
|
||||||
- 2013-07-12: `psutil-1.0.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.0.1.tar.gz>`_
|
|
||||||
- 2013-07-10: `psutil-1.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.0.0.tar.gz>`_
|
|
||||||
- 2013-05-03: `psutil-0.7.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.7.1.tar.gz>`_
|
|
||||||
- 2013-04-12: `psutil-0.7.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.7.0.tar.gz>`_
|
|
||||||
- 2012-08-16: `psutil-0.6.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.6.1.tar.gz>`_
|
|
||||||
- 2012-08-13: `psutil-0.6.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.6.0.tar.gz>`_
|
|
||||||
- 2012-06-29: `psutil-0.5.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.5.1.tar.gz>`_
|
|
||||||
- 2012-06-27: `psutil-0.5.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.5.0.tar.gz>`_
|
|
||||||
- 2011-12-14: `psutil-0.4.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.4.1.tar.gz>`_
|
|
||||||
- 2011-10-29: `psutil-0.4.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.4.0.tar.gz>`_
|
|
||||||
- 2011-07-08: `psutil-0.3.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.3.0.tar.gz>`_
|
|
||||||
- 2011-03-20: `psutil-0.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.2.1.tar.gz>`_
|
|
||||||
- 2010-11-13: `psutil-0.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.2.0.tar.gz>`_
|
|
||||||
- 2010-03-02: `psutil-0.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.3.tar.gz>`_
|
|
||||||
- 2009-05-06: `psutil-0.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.2.tar.gz>`_
|
|
||||||
- 2009-03-06: `psutil-0.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.1.tar.gz>`_
|
|
||||||
- 2009-01-27: `psutil-0.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.0.tar.gz>`_
|
|
||||||
|
|
||||||
Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,pstree,monitoring,ulimit,prlimit
|
|
||||||
Platform: Platform Independent
|
Platform: Platform Independent
|
||||||
Classifier: Development Status :: 5 - Production/Stable
|
Classifier: Development Status :: 5 - Production/Stable
|
||||||
Classifier: Environment :: Console
|
Classifier: Environment :: Console
|
||||||
|
@ -407,6 +492,9 @@ Classifier: Operating System :: Microsoft :: Windows :: Windows NT/2000
|
||||||
Classifier: Operating System :: Microsoft
|
Classifier: Operating System :: Microsoft
|
||||||
Classifier: Operating System :: OS Independent
|
Classifier: Operating System :: OS Independent
|
||||||
Classifier: Operating System :: POSIX :: BSD :: FreeBSD
|
Classifier: Operating System :: POSIX :: BSD :: FreeBSD
|
||||||
|
Classifier: Operating System :: POSIX :: BSD :: NetBSD
|
||||||
|
Classifier: Operating System :: POSIX :: BSD :: OpenBSD
|
||||||
|
Classifier: Operating System :: POSIX :: BSD
|
||||||
Classifier: Operating System :: POSIX :: Linux
|
Classifier: Operating System :: POSIX :: Linux
|
||||||
Classifier: Operating System :: POSIX :: SunOS/Solaris
|
Classifier: Operating System :: POSIX :: SunOS/Solaris
|
||||||
Classifier: Operating System :: POSIX
|
Classifier: Operating System :: POSIX
|
||||||
|
@ -415,11 +503,9 @@ Classifier: Programming Language :: Python :: 2
|
||||||
Classifier: Programming Language :: Python :: 2.6
|
Classifier: Programming Language :: Python :: 2.6
|
||||||
Classifier: Programming Language :: Python :: 2.7
|
Classifier: Programming Language :: Python :: 2.7
|
||||||
Classifier: Programming Language :: Python :: 3
|
Classifier: Programming Language :: Python :: 3
|
||||||
Classifier: Programming Language :: Python :: 3.0
|
|
||||||
Classifier: Programming Language :: Python :: 3.1
|
|
||||||
Classifier: Programming Language :: Python :: 3.2
|
|
||||||
Classifier: Programming Language :: Python :: 3.3
|
|
||||||
Classifier: Programming Language :: Python :: 3.4
|
Classifier: Programming Language :: Python :: 3.4
|
||||||
|
Classifier: Programming Language :: Python :: 3.5
|
||||||
|
Classifier: Programming Language :: Python :: 3.6
|
||||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||||
Classifier: Programming Language :: Python
|
Classifier: Programming Language :: Python
|
||||||
|
@ -430,5 +516,6 @@ Classifier: Topic :: System :: Hardware
|
||||||
Classifier: Topic :: System :: Monitoring
|
Classifier: Topic :: System :: Monitoring
|
||||||
Classifier: Topic :: System :: Networking :: Monitoring
|
Classifier: Topic :: System :: Networking :: Monitoring
|
||||||
Classifier: Topic :: System :: Networking
|
Classifier: Topic :: System :: Networking
|
||||||
|
Classifier: Topic :: System :: Operating System
|
||||||
Classifier: Topic :: System :: Systems Administration
|
Classifier: Topic :: System :: Systems Administration
|
||||||
Classifier: Topic :: Utilities
|
Classifier: Topic :: Utilities
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
.. image:: https://img.shields.io/pypi/dm/psutil.svg
|
.. image:: https://img.shields.io/travis/giampaolo/psutil/master.svg?maxAge=3600&label=Linux%20/%20OSX
|
||||||
:target: https://pypi.python.org/pypi/psutil#downloads
|
|
||||||
:alt: Downloads this month
|
|
||||||
|
|
||||||
.. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master
|
|
||||||
:target: https://travis-ci.org/giampaolo/psutil
|
:target: https://travis-ci.org/giampaolo/psutil
|
||||||
:alt: Linux tests (Travis)
|
:alt: Linux tests (Travis)
|
||||||
|
|
||||||
.. image:: https://ci.appveyor.com/api/projects/status/qdwvw7v1t915ywr5/branch/master?svg=true
|
.. image:: https://img.shields.io/appveyor/ci/giampaolo/psutil/master.svg?maxAge=3600&label=Windows
|
||||||
:target: https://ci.appveyor.com/project/giampaolo/psutil
|
:target: https://ci.appveyor.com/project/giampaolo/psutil
|
||||||
:alt: Windows tests (Appveyor)
|
:alt: Windows tests (Appveyor)
|
||||||
|
|
||||||
.. image:: https://coveralls.io/repos/giampaolo/psutil/badge.svg?branch=master&service=github
|
.. image:: https://coveralls.io/repos/github/giampaolo/psutil/badge.svg?branch=master
|
||||||
:target: https://coveralls.io/github/giampaolo/psutil?branch=master
|
:target: https://coveralls.io/github/giampaolo/psutil?branch=master
|
||||||
:alt: Test coverage (coverall.io)
|
:alt: Test coverage (coverall.io)
|
||||||
|
|
||||||
.. image:: https://img.shields.io/pypi/v/psutil.svg
|
.. image:: https://readthedocs.org/projects/psutil/badge/?version=latest
|
||||||
|
:target: http://psutil.readthedocs.io/en/latest/?badge=latest
|
||||||
|
:alt: Documentation Status
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/pypi/v/psutil.svg?label=pypi
|
||||||
:target: https://pypi.python.org/pypi/psutil/
|
:target: https://pypi.python.org/pypi/psutil/
|
||||||
:alt: Latest version
|
:alt: Latest version
|
||||||
|
|
||||||
|
@ -22,10 +22,6 @@
|
||||||
:target: https://github.com/giampaolo/psutil/
|
:target: https://github.com/giampaolo/psutil/
|
||||||
:alt: Github stars
|
:alt: Github stars
|
||||||
|
|
||||||
.. image:: https://img.shields.io/scrutinizer/g/giampaolo/psutil.svg
|
|
||||||
:target: https://scrutinizer-ci.com/g/giampaolo/psutil/
|
|
||||||
:alt: Code quality (scrutinizer-ci.com)
|
|
||||||
|
|
||||||
.. image:: https://img.shields.io/pypi/l/psutil.svg
|
.. image:: https://img.shields.io/pypi/l/psutil.svg
|
||||||
:target: https://pypi.python.org/pypi/psutil/
|
:target: https://pypi.python.org/pypi/psutil/
|
||||||
:alt: License
|
:alt: License
|
||||||
|
@ -35,8 +31,8 @@ Quick links
|
||||||
===========
|
===========
|
||||||
|
|
||||||
- `Home page <https://github.com/giampaolo/psutil>`_
|
- `Home page <https://github.com/giampaolo/psutil>`_
|
||||||
- `Documentation <http://pythonhosted.org/psutil/>`_
|
- `Install <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
|
||||||
- `Installation <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
|
- `Documentation <http://psutil.readthedocs.io>`_
|
||||||
- `Download <https://pypi.python.org/pypi?:action=display&name=psutil#downloads>`_
|
- `Download <https://pypi.python.org/pypi?:action=display&name=psutil#downloads>`_
|
||||||
- `Forum <http://groups.google.com/group/psutil/topics>`_
|
- `Forum <http://groups.google.com/group/psutil/topics>`_
|
||||||
- `Blog <http://grodola.blogspot.com/search/label/psutil>`_
|
- `Blog <http://grodola.blogspot.com/search/label/psutil>`_
|
||||||
|
@ -47,39 +43,70 @@ Quick links
|
||||||
Summary
|
Summary
|
||||||
=======
|
=======
|
||||||
|
|
||||||
psutil (python system and process utilities) is a cross-platform library for
|
psutil (process and system utilities) is a cross-platform library for
|
||||||
retrieving information on **running processes** and **system utilization**
|
retrieving information on **running processes** and **system utilization**
|
||||||
(CPU, memory, disks, network) in Python. It is useful mainly for **system
|
(CPU, memory, disks, network, sensors) in Python.
|
||||||
monitoring**, **profiling and limiting process resources** and **management of
|
It is useful mainly for **system monitoring**, **profiling and limiting process
|
||||||
running processes**. It implements many functionalities offered by command line
|
resources** and **management of running processes**.
|
||||||
tools such as: ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice,
|
It implements many functionalities offered by UNIX command line tools such as:
|
||||||
ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap. It currently supports
|
ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice, ionice, iostat,
|
||||||
**Linux, Windows, OSX, FreeBSD** and **Sun Solaris**, both **32-bit** and
|
iotop, uptime, pidof, tty, taskset, pmap.
|
||||||
**64-bit** architectures, with Python versions from **2.6 to 3.5** (users of
|
psutil currently supports the following platforms:
|
||||||
Python 2.4 and 2.5 may use `2.1.3 <https://pypi.python.org/pypi?name=psutil&version=2.1.3&:action=files>`__ version).
|
|
||||||
|
- **Linux**
|
||||||
|
- **Windows**
|
||||||
|
- **OSX**,
|
||||||
|
- **FreeBSD, OpenBSD**, **NetBSD**
|
||||||
|
- **Sun Solaris**
|
||||||
|
- **AIX**
|
||||||
|
|
||||||
|
...both **32-bit** and **64-bit** architectures, with Python
|
||||||
|
versions from **2.6 to 3.6**.
|
||||||
`PyPy <http://pypy.org/>`__ is also known to work.
|
`PyPy <http://pypy.org/>`__ is also known to work.
|
||||||
|
|
||||||
====================
|
====================
|
||||||
Example applications
|
Example applications
|
||||||
====================
|
====================
|
||||||
|
|
||||||
.. image:: http://psutil.googlecode.com/svn/wiki/images/top-thumb.png
|
+------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
|
||||||
:target: http://psutil.googlecode.com/svn/wiki/images/top.png
|
| .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/procinfo-small.png | .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/top-small.png |
|
||||||
:alt: top
|
| :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/procinfo.png | :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/top.png |
|
||||||
|
+------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
|
||||||
|
| .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/procsmem-small.png | .. image:: https://github.com/giampaolo/psutil/blob/master/docs/_static/pmap-small.png |
|
||||||
|
| :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/procsmem.png | :target: https://github.com/giampaolo/psutil/blob/master/docs/_static/pmap.png |
|
||||||
|
+------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------------------+
|
||||||
|
|
||||||
.. image:: http://psutil.googlecode.com/svn/wiki/images/nettop-thumb.png
|
Also see `scripts directory <https://github.com/giampaolo/psutil/tree/master/scripts>`__
|
||||||
:target: http://psutil.googlecode.com/svn/wiki/images/nettop.png
|
and `doc recipes <http://psutil.readthedocs.io/#recipes/>`__.
|
||||||
:alt: nettop
|
|
||||||
|
|
||||||
.. image:: http://psutil.googlecode.com/svn/wiki/images/iotop-thumb.png
|
=====================
|
||||||
:target: http://psutil.googlecode.com/svn/wiki/images/iotop.png
|
Projects using psutil
|
||||||
:alt: iotop
|
=====================
|
||||||
|
|
||||||
See also:
|
At the time of writing psutil has roughly
|
||||||
|
`2.9 milion downloads <https://github.com/giampaolo/psutil/issues/1053#issuecomment-340166262>`__
|
||||||
|
per month and there are over
|
||||||
|
`6000 open source projects <https://libraries.io/pypi/psutil/dependent_repositories?page=1>`__
|
||||||
|
on github which depend from psutil.
|
||||||
|
Here's some I find particularly interesting:
|
||||||
|
|
||||||
* https://github.com/nicolargo/glances
|
- https://github.com/facebook/osquery/
|
||||||
* https://github.com/google/grr
|
- https://github.com/nicolargo/glances
|
||||||
* https://github.com/Jahaja/psdash
|
- https://github.com/google/grr
|
||||||
|
- https://github.com/Jahaja/psdash
|
||||||
|
- https://github.com/ajenti/ajenti
|
||||||
|
- https://github.com/home-assistant/home-assistant/
|
||||||
|
|
||||||
|
========
|
||||||
|
Portings
|
||||||
|
========
|
||||||
|
|
||||||
|
- Go: https://github.com/shirou/gopsutil
|
||||||
|
- C: https://github.com/hamon-in/cpslib
|
||||||
|
- Node: https://github.com/christkv/node-psutil
|
||||||
|
- Rust: https://github.com/borntyping/rust-psutil
|
||||||
|
- Ruby: https://github.com/spacewander/posixpsutil
|
||||||
|
- Nim: https://github.com/johnscillieri/psutil-nim
|
||||||
|
|
||||||
==============
|
==============
|
||||||
Example usages
|
Example usages
|
||||||
|
@ -108,7 +135,6 @@ CPU
|
||||||
[7.0, 8.5, 2.4, 2.1]
|
[7.0, 8.5, 2.4, 2.1]
|
||||||
[1.2, 9.0, 9.9, 7.2]
|
[1.2, 9.0, 9.9, 7.2]
|
||||||
>>>
|
>>>
|
||||||
>>>
|
|
||||||
>>> for x in range(3):
|
>>> for x in range(3):
|
||||||
... psutil.cpu_times_percent(interval=1, percpu=False)
|
... psutil.cpu_times_percent(interval=1, percpu=False)
|
||||||
...
|
...
|
||||||
|
@ -121,14 +147,21 @@ CPU
|
||||||
>>> psutil.cpu_count(logical=False)
|
>>> psutil.cpu_count(logical=False)
|
||||||
2
|
2
|
||||||
>>>
|
>>>
|
||||||
|
>>> psutil.cpu_stats()
|
||||||
|
scpustats(ctx_switches=20455687, interrupts=6598984, soft_interrupts=2134212, syscalls=0)
|
||||||
|
>>>
|
||||||
|
>>> psutil.cpu_freq()
|
||||||
|
scpufreq(current=931.42925, min=800.0, max=3500.0)
|
||||||
|
>>>
|
||||||
|
|
||||||
Memory
|
Memory
|
||||||
======
|
======
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> import psutil
|
||||||
>>> psutil.virtual_memory()
|
>>> psutil.virtual_memory()
|
||||||
svmem(total=8374149120, available=2081050624, percent=75.1, used=8074080256, free=300068864, active=3294920704, inactive=1361616896, buffers=529895424, cached=1251086336)
|
svmem(total=10367352832, available=6472179712, percent=37.6, used=8186245120, free=2181107712, active=4748992512, inactive=2758115328, buffers=790724608, cached=3500347392, shared=787554304)
|
||||||
>>> psutil.swap_memory()
|
>>> psutil.swap_memory()
|
||||||
sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)
|
sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)
|
||||||
>>>
|
>>>
|
||||||
|
@ -138,6 +171,7 @@ Disks
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> import psutil
|
||||||
>>> psutil.disk_partitions()
|
>>> psutil.disk_partitions()
|
||||||
[sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
|
[sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
|
||||||
sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
|
sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
|
||||||
|
@ -146,7 +180,7 @@ Disks
|
||||||
sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
|
sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
|
||||||
>>>
|
>>>
|
||||||
>>> psutil.disk_io_counters(perdisk=False)
|
>>> psutil.disk_io_counters(perdisk=False)
|
||||||
sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568)
|
sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568, read_merged_count=619166, write_merged_count=812396, busy_time=4523412)
|
||||||
>>>
|
>>>
|
||||||
|
|
||||||
Network
|
Network
|
||||||
|
@ -154,37 +188,62 @@ Network
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> import psutil
|
||||||
>>> psutil.net_io_counters(pernic=True)
|
>>> psutil.net_io_counters(pernic=True)
|
||||||
{'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0),
|
{'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0),
|
||||||
'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)}
|
'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)}
|
||||||
>>>
|
>>>
|
||||||
>>> psutil.net_connections()
|
>>> psutil.net_connections()
|
||||||
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254),
|
[sconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED', pid=1254),
|
||||||
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987),
|
sconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING', pid=2987),
|
||||||
pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None),
|
sconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=60759), raddr=addr(ip='72.14.234.104', port=80), status='ESTABLISHED', pid=None),
|
||||||
pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None)
|
sconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=51314), raddr=addr(ip='72.14.234.83', port=443), status='SYN_SENT', pid=None)
|
||||||
...]
|
...]
|
||||||
>>>
|
>>>
|
||||||
>>> psutil.net_if_addrs()
|
>>> psutil.net_if_addrs()
|
||||||
{'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1'),
|
{'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1', ptp=None),
|
||||||
snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None),
|
snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None, ptp=None),
|
||||||
snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00')],
|
snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00', ptp=None)],
|
||||||
'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255'),
|
'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255', ptp=None),
|
||||||
snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None),
|
snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None, ptp=None),
|
||||||
snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff')]}
|
snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff', ptp=None)]}
|
||||||
>>>
|
>>>
|
||||||
>>> psutil.net_if_stats()
|
>>> psutil.net_if_stats()
|
||||||
{'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
|
{'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
|
||||||
'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
|
'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
|
||||||
|
>>>
|
||||||
|
|
||||||
|
Sensors
|
||||||
|
=======
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> import psutil
|
||||||
|
>>> psutil.sensors_temperatures()
|
||||||
|
{'acpitz': [shwtemp(label='', current=47.0, high=103.0, critical=103.0)],
|
||||||
|
'asus': [shwtemp(label='', current=47.0, high=None, critical=None)],
|
||||||
|
'coretemp': [shwtemp(label='Physical id 0', current=52.0, high=100.0, critical=100.0),
|
||||||
|
shwtemp(label='Core 0', current=45.0, high=100.0, critical=100.0),
|
||||||
|
shwtemp(label='Core 1', current=52.0, high=100.0, critical=100.0),
|
||||||
|
shwtemp(label='Core 2', current=45.0, high=100.0, critical=100.0),
|
||||||
|
shwtemp(label='Core 3', current=47.0, high=100.0, critical=100.0)]}
|
||||||
|
>>>
|
||||||
|
>>> psutil.sensors_fans()
|
||||||
|
{'asus': [sfan(label='cpu_fan', current=3200)]}
|
||||||
|
>>>
|
||||||
|
>>> psutil.sensors_battery()
|
||||||
|
sbattery(percent=93, secsleft=16628, power_plugged=False)
|
||||||
|
>>>
|
||||||
|
|
||||||
Other system info
|
Other system info
|
||||||
=================
|
=================
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> import psutil
|
||||||
>>> psutil.users()
|
>>> psutil.users()
|
||||||
[user(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0),
|
[suser(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0, pid=1352),
|
||||||
user(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)]
|
suser(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0, pid=1788)]
|
||||||
>>>
|
>>>
|
||||||
>>> psutil.boot_time()
|
>>> psutil.boot_time()
|
||||||
1365519115.0
|
1365519115.0
|
||||||
|
@ -197,12 +256,10 @@ Process management
|
||||||
|
|
||||||
>>> import psutil
|
>>> import psutil
|
||||||
>>> psutil.pids()
|
>>> psutil.pids()
|
||||||
[1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224,
|
[1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224, 268, 1215, 1216, 1220, 1221, 1243, 1244,
|
||||||
268, 1215, 1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355,
|
1301, 1601, 2237, 2355, 2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245, 4263, 4282,
|
||||||
2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245,
|
4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358, 4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446,
|
||||||
4263, 4282, 4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358,
|
5167, 5234, 5235, 5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
|
||||||
4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446, 5167, 5234, 5235,
|
|
||||||
5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
|
|
||||||
>>>
|
>>>
|
||||||
>>> p = psutil.Process(7055)
|
>>> p = psutil.Process(7055)
|
||||||
>>> p.name()
|
>>> p.name()
|
||||||
|
@ -214,6 +271,16 @@ Process management
|
||||||
>>> p.cmdline()
|
>>> p.cmdline()
|
||||||
['/usr/bin/python', 'main.py']
|
['/usr/bin/python', 'main.py']
|
||||||
>>>
|
>>>
|
||||||
|
>>> p.pid
|
||||||
|
7055
|
||||||
|
>>> p.ppid()
|
||||||
|
7054
|
||||||
|
>>> p.parent()
|
||||||
|
<psutil.Process(pid=7054, name='bash') at 140008329539408>
|
||||||
|
>>> p.children()
|
||||||
|
[<psutil.Process(pid=8031, name='python') at 14020832451977>,
|
||||||
|
<psutil.Process(pid=8044, name='python') at 19229444921932>]
|
||||||
|
>>>
|
||||||
>>> p.status()
|
>>> p.status()
|
||||||
'running'
|
'running'
|
||||||
>>> p.username()
|
>>> p.username()
|
||||||
|
@ -229,39 +296,41 @@ Process management
|
||||||
pgids(real=1000, effective=1000, saved=1000)
|
pgids(real=1000, effective=1000, saved=1000)
|
||||||
>>>
|
>>>
|
||||||
>>> p.cpu_times()
|
>>> p.cpu_times()
|
||||||
pcputimes(user=1.02, system=0.31)
|
pcputimes(user=1.02, system=0.31, children_user=0.32, children_system=0.1)
|
||||||
>>> p.cpu_percent(interval=1.0)
|
>>> p.cpu_percent(interval=1.0)
|
||||||
12.1
|
12.1
|
||||||
>>> p.cpu_affinity()
|
>>> p.cpu_affinity()
|
||||||
[0, 1, 2, 3]
|
[0, 1, 2, 3]
|
||||||
>>> p.cpu_affinity([0]) # set
|
>>> p.cpu_affinity([0, 1]) # set
|
||||||
>>>
|
>>> p.cpu_num()
|
||||||
>>> p.memory_percent()
|
1
|
||||||
0.63423
|
|
||||||
>>>
|
>>>
|
||||||
>>> p.memory_info()
|
>>> p.memory_info()
|
||||||
pmem(rss=7471104, vms=68513792)
|
pmem(rss=10915840, vms=67608576, shared=3313664, text=2310144, lib=0, data=7262208, dirty=0)
|
||||||
>>> p.memory_info_ex()
|
>>> p.memory_full_info() # "real" USS memory usage (Linux, OSX, Win only)
|
||||||
extmem(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0)
|
pfullmem(rss=10199040, vms=52133888, shared=3887104, text=2867200, lib=0, data=5967872, dirty=0, uss=6545408, pss=6872064, swap=0)
|
||||||
|
>>> p.memory_percent()
|
||||||
|
0.7823
|
||||||
>>> p.memory_maps()
|
>>> p.memory_maps()
|
||||||
[pmmap_grouped(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0),
|
[pmmap_grouped(path='/lib/x8664-linux-gnu/libutil-2.15.so', rss=32768, size=2125824, pss=32768, shared_clean=0, shared_dirty=0, private_clean=20480, private_dirty=12288, referenced=32768, anonymous=12288, swap=0),
|
||||||
pmmap_grouped(path='/lib/x86_64-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0),
|
pmmap_grouped(path='/lib/x8664-linux-gnu/libc-2.15.so', rss=3821568, size=3842048, pss=3821568, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=3821568, referenced=3575808, anonymous=3821568, swap=0),
|
||||||
pmmap_grouped(path='/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', rss=34124, anonymous=1245, swap=0),
|
pmmap_grouped(path='/lib/x8664-linux-gnu/libcrypto.so.0.1', rss=34124, rss=32768, size=2134016, pss=15360, shared_clean=24576, shared_dirty=0, private_clean=0, private_dirty=8192, referenced=24576, anonymous=8192, swap=0),
|
||||||
pmmap_grouped(path='[heap]', rss=54653, anonymous=8192, swap=0),
|
pmmap_grouped(path='[heap]', rss=32768, size=139264, pss=32768, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=32768, referenced=32768, anonymous=32768, swap=0),
|
||||||
pmmap_grouped(path='[stack]', rss=1542, anonymous=166, swap=0),
|
pmmap_grouped(path='[stack]', rss=2465792, size=2494464, pss=2465792, shared_clean=0, shared_dirty=0, private_clean=0, private_dirty=2465792, referenced=2277376, anonymous=2465792, swap=0),
|
||||||
...]
|
...]
|
||||||
>>>
|
>>>
|
||||||
>>> p.io_counters()
|
>>> p.io_counters()
|
||||||
pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632)
|
pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632, read_chars=456232, write_chars=517543)
|
||||||
>>>
|
>>>
|
||||||
>>> p.open_files()
|
>>> p.open_files()
|
||||||
[popenfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)]
|
[popenfile(path='/home/giampaolo/svn/psutil/setup.py', fd=3, position=0, mode='r', flags=32768),
|
||||||
|
popenfile(path='/var/log/monitd', fd=4, position=235542, mode='a', flags=33793)]
|
||||||
>>>
|
>>>
|
||||||
>>> p.connections()
|
>>> p.connections()
|
||||||
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'),
|
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED'),
|
||||||
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'),
|
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), raddr=addr(ip='72.14.234.100', port=80), status='CLOSING'),
|
||||||
pconn(fd=119, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'),
|
pconn(fd=119, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=60759), raddr=addr(ip='72.14.234.104', port=80), status='ESTABLISHED'),
|
||||||
pconn(fd=123, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')]
|
pconn(fd=123, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=51314), raddr=addr(ip='72.14.234.83', port=443), status='SYN_SENT')]
|
||||||
>>>
|
>>>
|
||||||
>>> p.num_threads()
|
>>> p.num_threads()
|
||||||
4
|
4
|
||||||
|
@ -288,6 +357,15 @@ Process management
|
||||||
>>> p.rlimit(psutil.RLIMIT_NOFILE)
|
>>> p.rlimit(psutil.RLIMIT_NOFILE)
|
||||||
(5, 5)
|
(5, 5)
|
||||||
>>>
|
>>>
|
||||||
|
>>> p.environ()
|
||||||
|
{'LC_PAPER': 'it_IT.UTF-8', 'SHELL': '/bin/bash', 'GREP_OPTIONS': '--color=auto',
|
||||||
|
'XDG_CONFIG_DIRS': '/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg', 'COLORTERM': 'gnome-terminal',
|
||||||
|
...}
|
||||||
|
>>>
|
||||||
|
>>> p.as_dict()
|
||||||
|
{'status': 'running', 'num_ctx_switches': pctxsw(voluntary=63, involuntary=1), 'pid': 5457, ...}
|
||||||
|
>>> p.is_running()
|
||||||
|
True
|
||||||
>>> p.suspend()
|
>>> p.suspend()
|
||||||
>>> p.resume()
|
>>> p.resume()
|
||||||
>>>
|
>>>
|
||||||
|
@ -311,76 +389,82 @@ Further process APIs
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
>>> for p in psutil.process_iter():
|
>>> import psutil
|
||||||
... print(p)
|
>>> for proc in psutil.process_iter(attrs=['pid', 'name']):
|
||||||
|
... print(proc.info)
|
||||||
...
|
...
|
||||||
psutil.Process(pid=1, name='init')
|
{'pid': 1, 'name': 'systemd'}
|
||||||
psutil.Process(pid=2, name='kthreadd')
|
{'pid': 2, 'name': 'kthreadd'}
|
||||||
psutil.Process(pid=3, name='ksoftirqd/0')
|
{'pid': 3, 'name': 'ksoftirqd/0'}
|
||||||
...
|
...
|
||||||
>>>
|
>>>
|
||||||
|
>>> psutil.pid_exists(3)
|
||||||
|
True
|
||||||
|
>>>
|
||||||
>>> def on_terminate(proc):
|
>>> def on_terminate(proc):
|
||||||
... print("process {} terminated".format(proc))
|
... print("process {} terminated".format(proc))
|
||||||
...
|
...
|
||||||
>>> # waits for multiple processes to terminate
|
>>> # waits for multiple processes to terminate
|
||||||
>>> gone, alive = psutil.wait_procs(procs_list, 3, callback=on_terminate)
|
>>> gone, alive = psutil.wait_procs(procs_list, timeout=3, callback=on_terminate)
|
||||||
>>>
|
>>>
|
||||||
|
|
||||||
|
Popen wrapper:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> import psutil
|
||||||
|
>>> from subprocess import PIPE
|
||||||
|
>>> p = psutil.Popen(["/usr/bin/python", "-c", "print('hello')"], stdout=PIPE)
|
||||||
|
>>> p.name()
|
||||||
|
'python'
|
||||||
|
>>> p.username()
|
||||||
|
'giampaolo'
|
||||||
|
>>> p.communicate()
|
||||||
|
('hello\n', None)
|
||||||
|
>>> p.wait(timeout=2)
|
||||||
|
0
|
||||||
|
>>>
|
||||||
|
|
||||||
|
Windows services
|
||||||
|
================
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> list(psutil.win_service_iter())
|
||||||
|
[<WindowsService(name='AeLookupSvc', display_name='Application Experience') at 38850096>,
|
||||||
|
<WindowsService(name='ALG', display_name='Application Layer Gateway Service') at 38850128>,
|
||||||
|
<WindowsService(name='APNMCP', display_name='Ask Update Service') at 38850160>,
|
||||||
|
<WindowsService(name='AppIDSvc', display_name='Application Identity') at 38850192>,
|
||||||
|
...]
|
||||||
|
>>> s = psutil.win_service_get('alg')
|
||||||
|
>>> s.as_dict()
|
||||||
|
{'binpath': 'C:\\Windows\\System32\\alg.exe',
|
||||||
|
'description': 'Provides support for 3rd party protocol plug-ins for Internet Connection Sharing',
|
||||||
|
'display_name': 'Application Layer Gateway Service',
|
||||||
|
'name': 'alg',
|
||||||
|
'pid': None,
|
||||||
|
'start_type': 'manual',
|
||||||
|
'status': 'stopped',
|
||||||
|
'username': 'NT AUTHORITY\\LocalService'}
|
||||||
|
|
||||||
|
Other samples
|
||||||
|
=============
|
||||||
|
|
||||||
|
See `doc recipes <http://psutil.readthedocs.io/#recipes>`__.
|
||||||
|
|
||||||
======
|
======
|
||||||
Donate
|
Author
|
||||||
======
|
======
|
||||||
|
|
||||||
|
psutil was created and is maintained by
|
||||||
|
`Giampaolo Rodola' <http://grodola.blogspot.com/p/about.html>`__.
|
||||||
A lot of time and effort went into making psutil as it is right now.
|
A lot of time and effort went into making psutil as it is right now.
|
||||||
If you feel psutil is useful to you or your business and want to support its future development please consider donating me (`Giampaolo Rodola' <http://grodola.blogspot.com/p/about.html>`_) some money.
|
If you feel psutil is useful to you or your business and want to support its
|
||||||
I only ask for a small donation, but of course I appreciate any amount.
|
future development please consider donating me
|
||||||
|
(`Giampaolo <http://grodola.blogspot.com/p/about.html>`__) some money.
|
||||||
|
|
||||||
.. image:: http://www.paypal.com/en_US/i/btn/x-click-but04.gif
|
.. image:: http://www.paypal.com/en_US/i/btn/x-click-but04.gif
|
||||||
:target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
|
:target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
|
||||||
:alt: Donate via PayPal
|
:alt: Donate via PayPal
|
||||||
|
|
||||||
Don't want to donate money? Then maybe you could `write me a recommendation on Linkedin <http://www.linkedin.com/in/grodola>`_.
|
Don't want to donate money? Then maybe you could `write me a recommendation on Linkedin <https://www.linkedin.com/in/grodola>`_.
|
||||||
|
|
||||||
============
|
|
||||||
Mailing list
|
|
||||||
============
|
|
||||||
|
|
||||||
http://groups.google.com/group/psutil/
|
|
||||||
|
|
||||||
========
|
|
||||||
Timeline
|
|
||||||
========
|
|
||||||
|
|
||||||
- 2015-07-15: `psutil-3.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.1.1.tar.gz>`_
|
|
||||||
- 2015-07-15: `psutil-3.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.1.0.tar.gz>`_
|
|
||||||
- 2015-06-18: `psutil-3.0.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.0.1.tar.gz>`_
|
|
||||||
- 2015-06-13: `psutil-3.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.0.0.tar.gz>`_
|
|
||||||
- 2015-02-02: `psutil-2.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.2.1.tar.gz>`_
|
|
||||||
- 2015-01-06: `psutil-2.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.2.0.tar.gz>`_
|
|
||||||
- 2014-09-26: `psutil-2.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.3.tar.gz>`_
|
|
||||||
- 2014-09-21: `psutil-2.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.2.tar.gz>`_
|
|
||||||
- 2014-04-30: `psutil-2.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.1.tar.gz>`_
|
|
||||||
- 2014-04-08: `psutil-2.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.0.tar.gz>`_
|
|
||||||
- 2014-03-10: `psutil-2.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.0.0.tar.gz>`_
|
|
||||||
- 2013-11-25: `psutil-1.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.2.1.tar.gz>`_
|
|
||||||
- 2013-11-20: `psutil-1.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.2.0.tar.gz>`_
|
|
||||||
- 2013-11-07: `psutil-1.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.3.tar.gz>`_
|
|
||||||
- 2013-10-22: `psutil-1.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.2.tar.gz>`_
|
|
||||||
- 2013-10-08: `psutil-1.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.1.tar.gz>`_
|
|
||||||
- 2013-09-28: `psutil-1.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.0.tar.gz>`_
|
|
||||||
- 2013-07-12: `psutil-1.0.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.0.1.tar.gz>`_
|
|
||||||
- 2013-07-10: `psutil-1.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.0.0.tar.gz>`_
|
|
||||||
- 2013-05-03: `psutil-0.7.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.7.1.tar.gz>`_
|
|
||||||
- 2013-04-12: `psutil-0.7.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.7.0.tar.gz>`_
|
|
||||||
- 2012-08-16: `psutil-0.6.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.6.1.tar.gz>`_
|
|
||||||
- 2012-08-13: `psutil-0.6.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.6.0.tar.gz>`_
|
|
||||||
- 2012-06-29: `psutil-0.5.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.5.1.tar.gz>`_
|
|
||||||
- 2012-06-27: `psutil-0.5.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.5.0.tar.gz>`_
|
|
||||||
- 2011-12-14: `psutil-0.4.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.4.1.tar.gz>`_
|
|
||||||
- 2011-10-29: `psutil-0.4.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.4.0.tar.gz>`_
|
|
||||||
- 2011-07-08: `psutil-0.3.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.3.0.tar.gz>`_
|
|
||||||
- 2011-03-20: `psutil-0.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.2.1.tar.gz>`_
|
|
||||||
- 2010-11-13: `psutil-0.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.2.0.tar.gz>`_
|
|
||||||
- 2010-03-02: `psutil-0.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.3.tar.gz>`_
|
|
||||||
- 2009-05-06: `psutil-0.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.2.tar.gz>`_
|
|
||||||
- 2009-03-06: `psutil-0.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.1.tar.gz>`_
|
|
||||||
- 2009-01-27: `psutil-0.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.0.tar.gz>`_
|
|
||||||
|
|
|
@ -1,167 +0,0 @@
|
||||||
TODO
|
|
||||||
====
|
|
||||||
|
|
||||||
A collection of ideas and notes about stuff to implement in future versions.
|
|
||||||
"#NNN" occurrences refer to bug tracker issues at:
|
|
||||||
https://github.com/giampaolo/psutil/issues
|
|
||||||
|
|
||||||
|
|
||||||
HIGHER PRIORITY
|
|
||||||
===============
|
|
||||||
|
|
||||||
* OpenBSD support.
|
|
||||||
|
|
||||||
* #371: CPU temperature (apparently OSX and Linux only; on Linux it requires
|
|
||||||
lm-sensors lib).
|
|
||||||
|
|
||||||
* #269: expose network ifaces RX/TW queues. This should probably go into
|
|
||||||
net_if_stats(). Figure out on what platforms this is supported:
|
|
||||||
Linux: yes
|
|
||||||
Others: ?
|
|
||||||
|
|
||||||
* Process.threads(): thread names; patch for OSX available at:
|
|
||||||
https://code.google.com/p/plcrashreporter/issues/detail?id=65
|
|
||||||
|
|
||||||
* Asynchronous psutil.Popen (see http://bugs.python.org/issue1191964)
|
|
||||||
|
|
||||||
* (Windows) fall back on using WMIC for Process methods returning AccessDenied
|
|
||||||
|
|
||||||
* #613: thread names.
|
|
||||||
|
|
||||||
* #604: emulate os.getloadavg() on Windows
|
|
||||||
|
|
||||||
* #269: NIC rx/tx queue.
|
|
||||||
|
|
||||||
|
|
||||||
LOWER PRIORITY
|
|
||||||
==============
|
|
||||||
|
|
||||||
* #355: Android support.
|
|
||||||
|
|
||||||
* #276: GNU/Hurd support.
|
|
||||||
|
|
||||||
* #429: NetBSD support.
|
|
||||||
|
|
||||||
* DragonFlyBSD support?
|
|
||||||
|
|
||||||
* AIX support?
|
|
||||||
|
|
||||||
* examples/taskmgr-gui.py (using tk).
|
|
||||||
|
|
||||||
* system-wide number of open file descriptors:
|
|
||||||
* https://jira.hyperic.com/browse/SIGAR-30
|
|
||||||
* http://www.netadmintools.com/part295.html
|
|
||||||
|
|
||||||
* Number of system threads.
|
|
||||||
* Windows: http://msdn.microsoft.com/en-us/library/windows/desktop/ms684824(v=vs.85).aspx
|
|
||||||
|
|
||||||
* #357: what CPU a process is on.
|
|
||||||
|
|
||||||
* Doc / wiki which compares similarities between UNIX cli tools and psutil.
|
|
||||||
Example:
|
|
||||||
df -a -> psutil.disk_partitions
|
|
||||||
lsof -> psutil.Process.open_files() and psutil.Process.open_connections()
|
|
||||||
killall-> (actual script)
|
|
||||||
tty -> psutil.Process.terminal()
|
|
||||||
who -> psutil.users()
|
|
||||||
|
|
||||||
|
|
||||||
DEBATABLE
|
|
||||||
=========
|
|
||||||
|
|
||||||
* psutil.proc_tree() something which obtains a {pid:ppid, ...} dict for
|
|
||||||
all running processes in one shot. This can be factored out from
|
|
||||||
Process.children() and exposed as a first class function.
|
|
||||||
PROS: on Windows we can take advantage of _psutil_windows.ppid_map()
|
|
||||||
which is faster than iterating over all pids and calling ppid().
|
|
||||||
CONS: examples/pstree.py shows this can be easily done in the user code
|
|
||||||
so maybe it's not worth the addition.
|
|
||||||
|
|
||||||
* advanced cmdline interface exposing the whole API and providing different
|
|
||||||
kind of outputs (e.g. pprinted, colorized, json).
|
|
||||||
|
|
||||||
* [Linux]: process cgroups (http://en.wikipedia.org/wiki/Cgroups). They look
|
|
||||||
similar to prlimit() in terms of functionality but uglier (they should allow
|
|
||||||
limiting per-process network IO resources though, which is great). Needs
|
|
||||||
further reading.
|
|
||||||
|
|
||||||
* Should we expose OS constants (psutil.WINDOWS, psutil.OSX etc.)?
|
|
||||||
|
|
||||||
* Python 3.3. exposed different sched.h functions:
|
|
||||||
http://docs.python.org/dev/whatsnew/3.3.html#os
|
|
||||||
http://bugs.python.org/issue12655
|
|
||||||
http://docs.python.org/dev/library/os.html#interface-to-the-scheduler
|
|
||||||
It might be worth to take a look and figure out whether we can include some
|
|
||||||
of those in psutil.
|
|
||||||
Also, we can probably reimplement wait_pid() on POSIX which is currently
|
|
||||||
implemented as a busy-loop.
|
|
||||||
|
|
||||||
* Certain systems provide CPU times about process children. On those systems
|
|
||||||
Process.cpu_times() might return a (user, system, user_children,
|
|
||||||
system_children) ntuple.
|
|
||||||
* Linux: /proc/{PID}/stat
|
|
||||||
* Solaris: pr_cutime and pr_cstime
|
|
||||||
* FreeBSD: none
|
|
||||||
* OSX: none
|
|
||||||
* Windows: none
|
|
||||||
|
|
||||||
* ...also, os.times() provides 'elapsed' times as well.
|
|
||||||
|
|
||||||
* ...also Linux provides guest_time and cguest_time.
|
|
||||||
|
|
||||||
* Enrich exception classes hierarchy on Python >= 3.3 / post PEP-3151 so that:
|
|
||||||
- NoSuchProcess inherits from ProcessLookupError
|
|
||||||
- AccessDenied inherits from PermissionError
|
|
||||||
- TimeoutExpired inherits from TimeoutError (debatable)
|
|
||||||
See: http://docs.python.org/3/library/exceptions.html#os-exceptions
|
|
||||||
|
|
||||||
* Process.threads() might grow an extra "id" parameter so that it can be
|
|
||||||
used as such:
|
|
||||||
|
|
||||||
>>> p = psutil.Process(os.getpid())
|
|
||||||
>>> p.threads(id=psutil.current_thread_id())
|
|
||||||
thread(id=2539, user_time=0.03, system_time=0.02)
|
|
||||||
>>>
|
|
||||||
|
|
||||||
Note: this leads to questions such as "should we have a custom NoSuchThread
|
|
||||||
exception? Also see issue #418.
|
|
||||||
|
|
||||||
Note #2: this would work with os.getpid() only.
|
|
||||||
psutil.current_thread_id() might be desirable as per issue #418 though.
|
|
||||||
|
|
||||||
* should psutil.TimeoutExpired exception have a 'msg' kwarg similar to
|
|
||||||
NoSuchProcess and AccessDenied? Not that we need it, but currently we
|
|
||||||
cannot raise a TimeoutExpired exception with a specific error string.
|
|
||||||
|
|
||||||
* process_iter() might grow an "attrs" parameter similar to Process.as_dict()
|
|
||||||
invoke the necessary methods and include the results into a "cache"
|
|
||||||
attribute attached to the returned Process instances so that one can avoid
|
|
||||||
catching NSP and AccessDenied:
|
|
||||||
for p in process_iter(attrs=['cpu_percent']):
|
|
||||||
print(p.cache['cpu_percent'])
|
|
||||||
This also leads questions as whether we should introduce a sorting order.
|
|
||||||
|
|
||||||
* round Process.memory_percent() result?
|
|
||||||
|
|
||||||
* #550: number of threads per core.
|
|
||||||
|
|
||||||
* Have psutil.Process().cpu_affinity([]) be an alias for "all CPUs"?
|
|
||||||
|
|
||||||
|
|
||||||
COMPATIBILITY BREAKAGE
|
|
||||||
======================
|
|
||||||
|
|
||||||
Removals (will likely happen in 2.2):
|
|
||||||
|
|
||||||
* (S) psutil.Process.nice (deprecated in 0.5.0)
|
|
||||||
* (S) get_process_list (deprecated in 0.5.0)
|
|
||||||
* (S) psutil.*mem* functions (deprecated in 0.3.0 and 0.6.0)
|
|
||||||
* (M) psutil.network_io_counters (deprecated in 1.0.0)
|
|
||||||
* (M) local_address and remote_address Process.connection() namedtuple fields
|
|
||||||
(deprecated in 1.0.0)
|
|
||||||
|
|
||||||
|
|
||||||
REJECTED IDEAS
|
|
||||||
==============
|
|
||||||
|
|
||||||
STUB
|
|
|
@ -2,16 +2,12 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
# You can set these variables from the command line.
|
# You can set these variables from the command line.
|
||||||
|
PYTHON = python
|
||||||
SPHINXOPTS =
|
SPHINXOPTS =
|
||||||
SPHINXBUILD = sphinx-build
|
SPHINXBUILD = $(PYTHON) -m sphinx
|
||||||
PAPER =
|
PAPER =
|
||||||
BUILDDIR = _build
|
BUILDDIR = _build
|
||||||
|
|
||||||
# User-friendly check for sphinx-build
|
|
||||||
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
|
||||||
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
|
|
||||||
endif
|
|
||||||
|
|
||||||
# Internal variables.
|
# Internal variables.
|
||||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||||
PAPEROPT_letter = -D latex_paper_size=letter
|
PAPEROPT_letter = -D latex_paper_size=letter
|
||||||
|
@ -19,8 +15,7 @@ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||||
# the i18n builder cannot share the environment and doctrees with the others
|
# the i18n builder cannot share the environment and doctrees with the others
|
||||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||||
|
|
||||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
.PHONY: help
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@echo "Please use \`make <target>' where <target> is one of"
|
@echo "Please use \`make <target>' where <target> is one of"
|
||||||
@echo " html to make standalone HTML files"
|
@echo " html to make standalone HTML files"
|
||||||
|
@ -30,8 +25,10 @@ help:
|
||||||
@echo " json to make JSON files"
|
@echo " json to make JSON files"
|
||||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||||
@echo " qthelp to make HTML files and a qthelp project"
|
@echo " qthelp to make HTML files and a qthelp project"
|
||||||
|
@echo " applehelp to make an Apple Help Book"
|
||||||
@echo " devhelp to make HTML files and a Devhelp project"
|
@echo " devhelp to make HTML files and a Devhelp project"
|
||||||
@echo " epub to make an epub"
|
@echo " epub to make an epub"
|
||||||
|
@echo " epub3 to make an epub3"
|
||||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||||
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
||||||
|
@ -45,41 +42,51 @@ help:
|
||||||
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
||||||
@echo " linkcheck to check all external links for integrity"
|
@echo " linkcheck to check all external links for integrity"
|
||||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||||
|
@echo " coverage to run coverage check of the documentation (if enabled)"
|
||||||
|
@echo " dummy to check syntax errors of document sources"
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BUILDDIR)
|
rm -rf $(BUILDDIR)
|
||||||
|
|
||||||
|
.PHONY: html
|
||||||
html:
|
html:
|
||||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||||
|
|
||||||
|
.PHONY: dirhtml
|
||||||
dirhtml:
|
dirhtml:
|
||||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||||
|
|
||||||
|
.PHONY: singlehtml
|
||||||
singlehtml:
|
singlehtml:
|
||||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||||
|
|
||||||
|
.PHONY: pickle
|
||||||
pickle:
|
pickle:
|
||||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished; now you can process the pickle files."
|
@echo "Build finished; now you can process the pickle files."
|
||||||
|
|
||||||
|
.PHONY: json
|
||||||
json:
|
json:
|
||||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished; now you can process the JSON files."
|
@echo "Build finished; now you can process the JSON files."
|
||||||
|
|
||||||
|
.PHONY: htmlhelp
|
||||||
htmlhelp:
|
htmlhelp:
|
||||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||||
|
|
||||||
|
.PHONY: qthelp
|
||||||
qthelp:
|
qthelp:
|
||||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||||
@echo
|
@echo
|
||||||
|
@ -89,6 +96,16 @@ qthelp:
|
||||||
@echo "To view the help file:"
|
@echo "To view the help file:"
|
||||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/psutil.qhc"
|
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/psutil.qhc"
|
||||||
|
|
||||||
|
.PHONY: applehelp
|
||||||
|
applehelp:
|
||||||
|
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
|
||||||
|
@echo "N.B. You won't be able to view it unless you put it in" \
|
||||||
|
"~/Library/Documentation/Help or install it in your application" \
|
||||||
|
"bundle."
|
||||||
|
|
||||||
|
.PHONY: devhelp
|
||||||
devhelp:
|
devhelp:
|
||||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||||
@echo
|
@echo
|
||||||
|
@ -98,11 +115,19 @@ devhelp:
|
||||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/psutil"
|
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/psutil"
|
||||||
@echo "# devhelp"
|
@echo "# devhelp"
|
||||||
|
|
||||||
|
.PHONY: epub
|
||||||
epub:
|
epub:
|
||||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||||
|
|
||||||
|
.PHONY: epub3
|
||||||
|
epub3:
|
||||||
|
$(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3."
|
||||||
|
|
||||||
|
.PHONY: latex
|
||||||
latex:
|
latex:
|
||||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
@echo
|
@echo
|
||||||
|
@ -110,28 +135,33 @@ latex:
|
||||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||||
"(use \`make latexpdf' here to do that automatically)."
|
"(use \`make latexpdf' here to do that automatically)."
|
||||||
|
|
||||||
|
.PHONY: latexpdf
|
||||||
latexpdf:
|
latexpdf:
|
||||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
@echo "Running LaTeX files through pdflatex..."
|
@echo "Running LaTeX files through pdflatex..."
|
||||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||||
|
|
||||||
|
.PHONY: latexpdfja
|
||||||
latexpdfja:
|
latexpdfja:
|
||||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
@echo "Running LaTeX files through platex and dvipdfmx..."
|
@echo "Running LaTeX files through platex and dvipdfmx..."
|
||||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
||||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||||
|
|
||||||
|
.PHONY: text
|
||||||
text:
|
text:
|
||||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||||
|
|
||||||
|
.PHONY: man
|
||||||
man:
|
man:
|
||||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||||
|
|
||||||
|
.PHONY: texinfo
|
||||||
texinfo:
|
texinfo:
|
||||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||||
@echo
|
@echo
|
||||||
|
@ -139,39 +169,58 @@ texinfo:
|
||||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||||
"(use \`make info' here to do that automatically)."
|
"(use \`make info' here to do that automatically)."
|
||||||
|
|
||||||
|
.PHONY: info
|
||||||
info:
|
info:
|
||||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||||
@echo "Running Texinfo files through makeinfo..."
|
@echo "Running Texinfo files through makeinfo..."
|
||||||
make -C $(BUILDDIR)/texinfo info
|
make -C $(BUILDDIR)/texinfo info
|
||||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||||
|
|
||||||
|
.PHONY: gettext
|
||||||
gettext:
|
gettext:
|
||||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||||
|
|
||||||
|
.PHONY: changes
|
||||||
changes:
|
changes:
|
||||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||||
@echo
|
@echo
|
||||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||||
|
|
||||||
|
.PHONY: linkcheck
|
||||||
linkcheck:
|
linkcheck:
|
||||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||||
@echo
|
@echo
|
||||||
@echo "Link check complete; look for any errors in the above output " \
|
@echo "Link check complete; look for any errors in the above output " \
|
||||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||||
|
|
||||||
|
.PHONY: doctest
|
||||||
doctest:
|
doctest:
|
||||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||||
@echo "Testing of doctests in the sources finished, look at the " \
|
@echo "Testing of doctests in the sources finished, look at the " \
|
||||||
"results in $(BUILDDIR)/doctest/output.txt."
|
"results in $(BUILDDIR)/doctest/output.txt."
|
||||||
|
|
||||||
|
.PHONY: coverage
|
||||||
|
coverage:
|
||||||
|
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
|
||||||
|
@echo "Testing of coverage in the sources finished, look at the " \
|
||||||
|
"results in $(BUILDDIR)/coverage/python.txt."
|
||||||
|
|
||||||
|
.PHONY: xml
|
||||||
xml:
|
xml:
|
||||||
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
||||||
|
|
||||||
|
.PHONY: pseudoxml
|
||||||
pseudoxml:
|
pseudoxml:
|
||||||
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||||
@echo
|
@echo
|
||||||
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
||||||
|
|
||||||
|
.PHONY: dummy
|
||||||
|
dummy:
|
||||||
|
$(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. Dummy builder generates no files."
|
||||||
|
|
|
@ -3,7 +3,7 @@ About
|
||||||
|
|
||||||
This directory contains the reStructuredText (reST) sources to the psutil
|
This directory contains the reStructuredText (reST) sources to the psutil
|
||||||
documentation. You don't need to build them yourself, prebuilt versions are
|
documentation. You don't need to build them yourself, prebuilt versions are
|
||||||
available at https://pythonhosted.org/psutil/.
|
available at http://psutil.readthedocs.io.
|
||||||
In case you want, you need to install sphinx first:
|
In case you want, you need to install sphinx first:
|
||||||
|
|
||||||
$ pip install sphinx
|
$ pip install sphinx
|
||||||
|
@ -12,4 +12,4 @@ Then run:
|
||||||
|
|
||||||
$ make html
|
$ make html
|
||||||
|
|
||||||
You'll then have an HTML version of the doc at _build/html/index.html.
|
You'll then have an HTML version of the doc at _build/html/index.html.
|
||||||
|
|
|
@ -0,0 +1,518 @@
|
||||||
|
.wy-nav-content {
|
||||||
|
max-width: 100% !important;
|
||||||
|
padding: 15px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content dl:not(.docutils) {
|
||||||
|
margin: 0px 0px 0px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data dd {
|
||||||
|
margin-bottom: 0px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data .descname {
|
||||||
|
border-right:10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.local-toc li ul li{
|
||||||
|
padding-left: 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.function .descclassname {
|
||||||
|
font-weight: normal !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.class .descclassname {
|
||||||
|
font-weight: normal !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition.warning {
|
||||||
|
padding-top: 2px !important;
|
||||||
|
padding-bottom: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition.note {
|
||||||
|
padding-top: 2px !important;
|
||||||
|
padding-bottom: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-content dl:not(.docutils) dt {
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sig-paren {
|
||||||
|
padding-left: 2px;
|
||||||
|
padding-right: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3 {
|
||||||
|
background: #eee;
|
||||||
|
padding: 5px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition.warning {
|
||||||
|
padding-top: 5px !important;
|
||||||
|
padding-bottom: 5px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition.warning p {
|
||||||
|
margin-bottom: 5px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition.note {
|
||||||
|
padding-top: 5px !important;
|
||||||
|
padding-bottom: 5px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition.note p {
|
||||||
|
margin-bottom: 5px !important;
|
||||||
|
backround-color: rgb(238, 255, 204) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codeblock div[class^='highlight'], pre.literal-block div[class^='highlight'], .rst-content .literal-block div[class^='highlight'], div[class^='highlight'] div[class^='highlight'] {
|
||||||
|
background-color: #eeffcc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight .hll {
|
||||||
|
background-color: #ffffcc
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
background: #eeffcc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight-default, .highlight-python {
|
||||||
|
border-radius: 3px !important;
|
||||||
|
border: 1px solid #ac9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight .c {
|
||||||
|
color: #408090;
|
||||||
|
font-style: italic
|
||||||
|
}
|
||||||
|
|
||||||
|
.wy-side-nav-search {
|
||||||
|
background-color: grey !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
border-radius: 3px !important;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
div.highlight-default {
|
||||||
|
margin-bottom: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
padding: 5px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================================== */
|
||||||
|
/* Warnings and info boxes like python doc */
|
||||||
|
/* ================================================================== */
|
||||||
|
|
||||||
|
div.admonition {
|
||||||
|
margin-top: 10px !important;
|
||||||
|
margin-bottom: 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.warning {
|
||||||
|
background-color: #ffe4e4 !important;
|
||||||
|
border: 1px solid #f66 !important;
|
||||||
|
border-radius: 3px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.note {
|
||||||
|
background-color: #eee !important;
|
||||||
|
border: 1px solid #ccc !important;
|
||||||
|
border-radius: 3px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.admonition p.admonition-title + p {
|
||||||
|
display: inline !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.admonition-title {
|
||||||
|
display: inline !important;
|
||||||
|
background: none !important;
|
||||||
|
color: black !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.admonition-title:after {
|
||||||
|
content: ":" !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.body div.admonition, div.body div.impl-detail {
|
||||||
|
}
|
||||||
|
|
||||||
|
.fa-exclamation-circle:before, .wy-inline-validate.wy-inline-validate-warning .wy-input-context:before, .wy-inline-validate.wy-inline-validate-info .wy-input-context:before, .rst-content .admonition-title:before {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note code {
|
||||||
|
background: #d6d6d6 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================================== */
|
||||||
|
/* Syntax highlight like Python doc.
|
||||||
|
/* ================================================================== */
|
||||||
|
|
||||||
|
/* Comment */
|
||||||
|
.highlight .err {
|
||||||
|
border: 1px solid #FF0000
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Error */
|
||||||
|
.highlight .k {
|
||||||
|
color: #007020;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keyword */
|
||||||
|
.highlight .o {
|
||||||
|
color: #666666
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Operator */
|
||||||
|
.highlight .ch {
|
||||||
|
color: #408090;
|
||||||
|
font-style: italic
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Comment.Hashbang */
|
||||||
|
.highlight .cm {
|
||||||
|
color: #408090;
|
||||||
|
font-style: italic
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Comment.Multiline */
|
||||||
|
.highlight .cp {
|
||||||
|
color: #007020
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Comment.Preproc */
|
||||||
|
.highlight .cpf {
|
||||||
|
color: #408090;
|
||||||
|
font-style: italic
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Comment.PreprocFile */
|
||||||
|
.highlight .c1 {
|
||||||
|
color: #408090;
|
||||||
|
font-style: italic
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Comment.Single */
|
||||||
|
.highlight .cs {
|
||||||
|
color: #408090;
|
||||||
|
background-color: #fff0f0
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Comment.Special */
|
||||||
|
.highlight .gd {
|
||||||
|
color: #A00000
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generic.Deleted */
|
||||||
|
.highlight .ge {
|
||||||
|
font-style: italic
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generic.Emph */
|
||||||
|
.highlight .gr {
|
||||||
|
color: #FF0000
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generic.Error */
|
||||||
|
.highlight .gh {
|
||||||
|
color: #000080;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generic.Heading */
|
||||||
|
.highlight .gi {
|
||||||
|
color: #00A000
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generic.Inserted */
|
||||||
|
.highlight .go {
|
||||||
|
color: #333333
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generic.Output */
|
||||||
|
.highlight .gp {
|
||||||
|
color: #c65d09;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generic.Prompt */
|
||||||
|
.highlight .gs {
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generic.Strong */
|
||||||
|
.highlight .gu {
|
||||||
|
color: #800080;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generic.Subheading */
|
||||||
|
.highlight .gt {
|
||||||
|
color: #0044DD
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generic.Traceback */
|
||||||
|
.highlight .kc {
|
||||||
|
color: #007020;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keyword.Constant */
|
||||||
|
.highlight .kd {
|
||||||
|
color: #007020;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keyword.Declaration */
|
||||||
|
.highlight .kn {
|
||||||
|
color: #007020;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keyword.Namespace */
|
||||||
|
.highlight .kp {
|
||||||
|
color: #007020
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keyword.Pseudo */
|
||||||
|
.highlight .kr {
|
||||||
|
color: #007020;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keyword.Reserved */
|
||||||
|
.highlight .kt {
|
||||||
|
color: #902000
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keyword.Type */
|
||||||
|
.highlight .m {
|
||||||
|
color: #208050
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.Number */
|
||||||
|
.highlight .s {
|
||||||
|
color: #4070a0
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.String */
|
||||||
|
.highlight .na {
|
||||||
|
color: #4070a0
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Attribute */
|
||||||
|
.highlight .nb {
|
||||||
|
color: #007020
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Builtin */
|
||||||
|
.highlight .nc {
|
||||||
|
color: #0e84b5;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Class */
|
||||||
|
.highlight .no {
|
||||||
|
color: #60add5
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Constant */
|
||||||
|
.highlight .nd {
|
||||||
|
color: #555555;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Decorator */
|
||||||
|
.highlight .ni {
|
||||||
|
color: #d55537;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Entity */
|
||||||
|
.highlight .ne {
|
||||||
|
color: #007020
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Exception */
|
||||||
|
.highlight .nf {
|
||||||
|
color: #06287e
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Function */
|
||||||
|
.highlight .nl {
|
||||||
|
color: #002070;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Label */
|
||||||
|
.highlight .nn {
|
||||||
|
color: #0e84b5;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Namespace */
|
||||||
|
.highlight .nt {
|
||||||
|
color: #062873;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Tag */
|
||||||
|
.highlight .nv {
|
||||||
|
color: #bb60d5
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Variable */
|
||||||
|
.highlight .ow {
|
||||||
|
color: #007020;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Operator.Word */
|
||||||
|
.highlight .w {
|
||||||
|
color: #bbbbbb
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text.Whitespace */
|
||||||
|
.highlight .mb {
|
||||||
|
color: #208050
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.Number.Bin */
|
||||||
|
.highlight .mf {
|
||||||
|
color: #208050
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.Number.Float */
|
||||||
|
.highlight .mh {
|
||||||
|
color: #208050
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.Number.Hex */
|
||||||
|
.highlight .mi {
|
||||||
|
color: #208050
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.Number.Integer */
|
||||||
|
.highlight .mo {
|
||||||
|
color: #208050
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.Number.Oct */
|
||||||
|
.highlight .sa {
|
||||||
|
color: #4070a0
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.String.Affix */
|
||||||
|
.highlight .sb {
|
||||||
|
color: #4070a0
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.String.Backtick */
|
||||||
|
.highlight .sc {
|
||||||
|
color: #4070a0
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.String.Char */
|
||||||
|
.highlight .dl {
|
||||||
|
color: #4070a0
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.String.Delimiter */
|
||||||
|
.highlight .sd {
|
||||||
|
color: #4070a0;
|
||||||
|
font-style: italic
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.String.Doc */
|
||||||
|
.highlight .s2 {
|
||||||
|
color: #4070a0
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.String.Double */
|
||||||
|
.highlight .se {
|
||||||
|
color: #4070a0;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.String.Escape */
|
||||||
|
.highlight .sh {
|
||||||
|
color: #4070a0
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.String.Heredoc */
|
||||||
|
.highlight .si {
|
||||||
|
color: #70a0d0;
|
||||||
|
font-style: italic
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.String.Interpol */
|
||||||
|
.highlight .sx {
|
||||||
|
color: #c65d09
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.String.Other */
|
||||||
|
.highlight .sr {
|
||||||
|
color: #235388
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.String.Regex */
|
||||||
|
.highlight .s1 {
|
||||||
|
color: #4070a0
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.String.Single */
|
||||||
|
.highlight .ss {
|
||||||
|
color: #517918
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Literal.String.Symbol */
|
||||||
|
.highlight .bp {
|
||||||
|
color: #007020
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Builtin.Pseudo */
|
||||||
|
.highlight .fm {
|
||||||
|
color: #06287e
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Function.Magic */
|
||||||
|
.highlight .vc {
|
||||||
|
color: #bb60d5
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Variable.Class */
|
||||||
|
.highlight .vg {
|
||||||
|
color: #bb60d5
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Variable.Global */
|
||||||
|
.highlight .vi {
|
||||||
|
color: #bb60d5
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Variable.Instance */
|
||||||
|
.highlight .vm {
|
||||||
|
color: #bb60d5
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Name.Variable.Magic */
|
||||||
|
.highlight .il {
|
||||||
|
color: #208050
|
||||||
|
}
|
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 4.8 KiB |
|
@ -1,12 +0,0 @@
|
||||||
{#
|
|
||||||
basic/globaltoc.html
|
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Sphinx sidebar template: global table of contents.
|
|
||||||
|
|
||||||
:copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
|
|
||||||
:license: BSD, see LICENSE for details.
|
|
||||||
#}
|
|
||||||
<h3>{{ _('Manual') }}</h3>
|
|
||||||
{{ toctree() }}
|
|
||||||
<a href="{{ pathto(master_doc) }}">Back to Welcome</a>
|
|
|
@ -1,4 +0,0 @@
|
||||||
{% extends "defindex.html" %}
|
|
||||||
{% block tables %}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,8 +0,0 @@
|
||||||
<h3>Useful links</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://github.com/giampaolo/psutil">Github project</a></li>
|
|
||||||
<li><a href="http://grodola.blogspot.com/search/label/psutil">Blog</a></li>
|
|
||||||
<li><a href="https://pypi.python.org/pypi?:action=display&name=psutil#downloads">Download</a></li>
|
|
||||||
<li><a href="https://github.com/giampaolo/psutil/issues">Issues</a></li>
|
|
||||||
<li><a href="http://groups.google.com/group/psutil/topics">Forum</a></li>
|
|
||||||
</ul>
|
|
|
@ -1,66 +0,0 @@
|
||||||
{% extends "!page.html" %}
|
|
||||||
{% block extrahead %}
|
|
||||||
{{ super() }}
|
|
||||||
{% if not embedded %}<script type="text/javascript" src="{{ pathto('_static/copybutton.js', 1) }}"></script>{% endif %}
|
|
||||||
<script type="text/javascript">
|
|
||||||
|
|
||||||
// Store editor pop-up help state in localStorage
|
|
||||||
// so it does not re-pop-up itself between page loads.
|
|
||||||
// Do not even to pretend to support IE gracefully.
|
|
||||||
(function($) {
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
var box = $("#editor-trap");
|
|
||||||
var klass = "toggled";
|
|
||||||
var storageKey = "toggled";
|
|
||||||
|
|
||||||
function toggle() {
|
|
||||||
box.toggleClass(klass);
|
|
||||||
// Store the toggle status in local storage as "has value string" or null
|
|
||||||
window.localStorage.setItem(storageKey, box.hasClass(klass) ? "toggled" : "not-toggled");
|
|
||||||
}
|
|
||||||
|
|
||||||
box.click(toggle);
|
|
||||||
|
|
||||||
// Check the persistent state of the editor pop-up
|
|
||||||
// Note that localStorage does not necessarily support boolean values (ugh!)
|
|
||||||
// http://stackoverflow.com/questions/3263161/cannot-set-boolean-values-in-localstorage
|
|
||||||
var v = window.localStorage.getItem(storageKey);
|
|
||||||
if(v == "toggled" || !v) {
|
|
||||||
box.addClass(klass);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
})(jQuery);
|
|
||||||
</script>
|
|
||||||
<script type="text/javascript">
|
|
||||||
|
|
||||||
var _gaq = _gaq || [];
|
|
||||||
_gaq.push(['_setAccount', 'UA-2097050-4']);
|
|
||||||
_gaq.push(['_trackPageview']);
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
|
||||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
|
||||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
|
||||||
})();
|
|
||||||
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block rootrellink %}
|
|
||||||
<li><a href="https://github.com/giampaolo/psutil/"><img src="{{ pathto('_static/logo.png', 1) }}" style="height: 30px; vertical-align: middle; padding-right: 1em;" /> Project Homepage</a>{{ reldelim1 }}</li>
|
|
||||||
<li><a href="{{ pathto('index') }}">{{ shorttitle }}</a>{{ reldelim1 }}</li>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
|
||||||
{% block footer %}
|
|
||||||
<div class="footer">
|
|
||||||
© Copyright {{ copyright|e }}.
|
|
||||||
<br />
|
|
||||||
Last updated on {{ last_updated|e }}.
|
|
||||||
<br />
|
|
||||||
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> {{ sphinx_version|e }}.
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
|
@ -1,187 +0,0 @@
|
||||||
@import url("default.css");
|
|
||||||
|
|
||||||
body {
|
|
||||||
background-color: white;
|
|
||||||
margin-left: 1em;
|
|
||||||
margin-right: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.related {
|
|
||||||
margin-bottom: 1.2em;
|
|
||||||
padding: 0.5em 0;
|
|
||||||
border-top: 1px solid #ccc;
|
|
||||||
margin-top: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.related a:hover {
|
|
||||||
color: #0095C4;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.related:first-child {
|
|
||||||
border-top: 0;
|
|
||||||
padding-top: 0;
|
|
||||||
border-bottom: 1px solid #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar {
|
|
||||||
background-color: #eeeeee;
|
|
||||||
border-radius: 5px;
|
|
||||||
line-height: 130%;
|
|
||||||
font-size: smaller;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar h3, div.sphinxsidebar h4 {
|
|
||||||
margin-top: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebarwrapper > h3:first-child {
|
|
||||||
margin-top: 0.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebarwrapper > ul > li > ul > li {
|
|
||||||
margin-bottom: 0.4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar a:hover {
|
|
||||||
color: #0095C4;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar input {
|
|
||||||
font-family: 'Lucida Grande','Lucida Sans','DejaVu Sans',Arial,sans-serif;
|
|
||||||
border: 1px solid #999999;
|
|
||||||
font-size: smaller;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.sphinxsidebar input[type=text] {
|
|
||||||
max-width: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body {
|
|
||||||
padding: 0 0 0 1.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body p {
|
|
||||||
line-height: 140%;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 {
|
|
||||||
margin: 0;
|
|
||||||
border: 0;
|
|
||||||
padding: 0.3em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body hr {
|
|
||||||
border: 0;
|
|
||||||
background-color: #ccc;
|
|
||||||
height: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body pre {
|
|
||||||
border-radius: 3px;
|
|
||||||
border: 1px solid #ac9;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body div.admonition, div.body div.impl-detail {
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body div.impl-detail > p {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body div.seealso {
|
|
||||||
border: 1px solid #dddd66;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body a {
|
|
||||||
color: #00608f;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body a:visited {
|
|
||||||
color: #30306f;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body a:hover {
|
|
||||||
color: #00B0E4;
|
|
||||||
}
|
|
||||||
|
|
||||||
tt, pre {
|
|
||||||
font-family: monospace, sans-serif;
|
|
||||||
font-size: 96.5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body tt {
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body tt.descname {
|
|
||||||
font-size: 120%;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body tt.xref, div.body a tt {
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
p.deprecated {
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.docutils {
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
min-width: 20%;
|
|
||||||
border-radius: 3px;
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.docutils td, table.docutils th {
|
|
||||||
border: 1px solid #ddd !important;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table p, table li {
|
|
||||||
text-align: left !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.docutils th {
|
|
||||||
background-color: #eee;
|
|
||||||
padding: 0.3em 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.docutils td {
|
|
||||||
background-color: white;
|
|
||||||
padding: 0.3em 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.footnote, table.footnote td {
|
|
||||||
border: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.footer {
|
|
||||||
line-height: 150%;
|
|
||||||
margin-top: -2em;
|
|
||||||
text-align: right;
|
|
||||||
width: auto;
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.footer a:hover {
|
|
||||||
color: #0095C4;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body h1,
|
|
||||||
div.body h2,
|
|
||||||
div.body h3 {
|
|
||||||
background-color: #EAEAEA;
|
|
||||||
border-bottom: 1px solid #CCC;
|
|
||||||
padding-top: 2px;
|
|
||||||
padding-bottom: 2px;
|
|
||||||
padding-left: 5px;
|
|
||||||
margin-top: 5px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.body h2 {
|
|
||||||
padding-left:10px;
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
[theme]
|
|
||||||
inherit = default
|
|
||||||
stylesheet = pydoctheme.css
|
|
||||||
pygments_style = sphinx
|
|
||||||
|
|
||||||
[options]
|
|
||||||
bodyfont = 'Lucida Grande', 'Lucida Sans', 'DejaVu Sans', Arial, sans-serif
|
|
||||||
headfont = 'Lucida Grande', 'Lucida Sans', 'DejaVu Sans', Arial, sans-serif
|
|
||||||
footerbgcolor = white
|
|
||||||
footertextcolor = #555555
|
|
||||||
relbarbgcolor = white
|
|
||||||
relbartextcolor = #666666
|
|
||||||
relbarlinkcolor = #444444
|
|
||||||
sidebarbgcolor = white
|
|
||||||
sidebartextcolor = #444444
|
|
||||||
sidebarlinkcolor = #444444
|
|
||||||
bgcolor = white
|
|
||||||
textcolor = #222222
|
|
||||||
linkcolor = #0090c0
|
|
||||||
visitedlinkcolor = #00608f
|
|
||||||
headtextcolor = #1a1a1a
|
|
||||||
headbgcolor = white
|
|
||||||
headlinkcolor = #aaaaaa
|
|
|
@ -1,7 +1,7 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# psutil documentation build configuration file, created by
|
# psutil documentation build configuration file, created by
|
||||||
# sphinx-quickstart.
|
# sphinx-quickstart on Wed Oct 19 21:54:30 2016.
|
||||||
#
|
#
|
||||||
# This file is execfile()d with the current directory set to its
|
# This file is execfile()d with the current directory set to its
|
||||||
# containing dir.
|
# containing dir.
|
||||||
|
@ -12,12 +12,22 @@
|
||||||
# All configuration values have a default; values that are commented out
|
# All configuration values have a default; values that are commented out
|
||||||
# serve to show the default.
|
# serve to show the default.
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
#
|
||||||
|
# import os
|
||||||
|
# import sys
|
||||||
|
# sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
|
# -- General configuration ------------------------------------------------
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
PROJECT_NAME = "psutil"
|
PROJECT_NAME = "psutil"
|
||||||
AUTHOR = "Giampaolo Rodola'"
|
AUTHOR = u"Giampaolo Rodola"
|
||||||
THIS_YEAR = str(datetime.datetime.now().year)
|
THIS_YEAR = str(datetime.datetime.now().year)
|
||||||
HERE = os.path.abspath(os.path.dirname(__file__))
|
HERE = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
@ -35,27 +45,33 @@ def get_version():
|
||||||
else:
|
else:
|
||||||
raise ValueError("couldn't find version string")
|
raise ValueError("couldn't find version string")
|
||||||
|
|
||||||
|
|
||||||
VERSION = get_version()
|
VERSION = get_version()
|
||||||
|
|
||||||
# If your documentation needs a minimal Sphinx version, state it here.
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
needs_sphinx = '1.0'
|
#
|
||||||
|
# needs_sphinx = '1.0'
|
||||||
|
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
# ones.
|
# ones.
|
||||||
extensions = ['sphinx.ext.autodoc',
|
extensions = ['sphinx.ext.autodoc',
|
||||||
'sphinx.ext.coverage',
|
'sphinx.ext.coverage',
|
||||||
'sphinx.ext.pngmath',
|
'sphinx.ext.imgmath',
|
||||||
'sphinx.ext.viewcode',
|
'sphinx.ext.viewcode',
|
||||||
'sphinx.ext.intersphinx']
|
'sphinx.ext.intersphinx']
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_template']
|
templates_path = ['_templates']
|
||||||
|
|
||||||
# The suffix of source filenames.
|
# The suffix(es) of source filenames.
|
||||||
|
# You can specify multiple suffix as a list of string:
|
||||||
|
#
|
||||||
|
# source_suffix = ['.rst', '.md']
|
||||||
source_suffix = '.rst'
|
source_suffix = '.rst'
|
||||||
|
|
||||||
# The encoding of source files.
|
# The encoding of source files.
|
||||||
|
#
|
||||||
# source_encoding = 'utf-8-sig'
|
# source_encoding = 'utf-8-sig'
|
||||||
|
|
||||||
# The master toctree document.
|
# The master toctree document.
|
||||||
|
@ -64,6 +80,7 @@ master_doc = 'index'
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = PROJECT_NAME
|
project = PROJECT_NAME
|
||||||
copyright = '2009-%s, %s' % (THIS_YEAR, AUTHOR)
|
copyright = '2009-%s, %s' % (THIS_YEAR, AUTHOR)
|
||||||
|
author = AUTHOR
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
# |version| and |release|, also used in various other places throughout the
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
@ -71,35 +88,47 @@ copyright = '2009-%s, %s' % (THIS_YEAR, AUTHOR)
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = VERSION
|
version = VERSION
|
||||||
|
# The full version, including alpha/beta/rc tags.
|
||||||
|
release = VERSION
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
# language = None
|
#
|
||||||
|
# This is also used if you do content translation via gettext catalogs.
|
||||||
|
# Usually you set "language" from the command line for these cases.
|
||||||
|
language = None
|
||||||
|
|
||||||
# There are two options for replacing |today|: either, you set today to some
|
# There are two options for replacing |today|: either, you set today to some
|
||||||
# non-false value, then it is used:
|
# non-false value, then it is used:
|
||||||
|
#
|
||||||
# today = ''
|
# today = ''
|
||||||
|
#
|
||||||
# Else, today_fmt is used as the format for a strftime call.
|
# Else, today_fmt is used as the format for a strftime call.
|
||||||
|
#
|
||||||
# today_fmt = '%B %d, %Y'
|
# today_fmt = '%B %d, %Y'
|
||||||
|
|
||||||
# List of patterns, relative to source directory, that match files and
|
# List of patterns, relative to source directory, that match files and
|
||||||
# directories to ignore when looking for source files.
|
# directories to ignore when looking for source files.
|
||||||
exclude_patterns = ['_build']
|
# This patterns also effect to html_static_path and html_extra_path
|
||||||
|
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||||
|
|
||||||
# The reST default role (used for this markup: `text`) to use for all
|
# The reST default role (used for this markup: `text`) to use for all
|
||||||
# documents.
|
# documents.
|
||||||
|
#
|
||||||
# default_role = None
|
# default_role = None
|
||||||
|
|
||||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||||
add_function_parentheses = True
|
#
|
||||||
|
# add_function_parentheses = True
|
||||||
|
|
||||||
# If true, the current module name will be prepended to all description
|
# If true, the current module name will be prepended to all description
|
||||||
# unit titles (such as .. function::).
|
# unit titles (such as .. function::).
|
||||||
|
#
|
||||||
# add_module_names = True
|
# add_module_names = True
|
||||||
|
|
||||||
autodoc_docstring_signature = True
|
|
||||||
|
|
||||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||||
# output. They are ignored by default.
|
# output. They are ignored by default.
|
||||||
|
#
|
||||||
# show_authors = False
|
# show_authors = False
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
|
@ -108,141 +137,240 @@ pygments_style = 'sphinx'
|
||||||
# A list of ignored prefixes for module index sorting.
|
# A list of ignored prefixes for module index sorting.
|
||||||
# modindex_common_prefix = []
|
# modindex_common_prefix = []
|
||||||
|
|
||||||
|
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||||
|
# keep_warnings = False
|
||||||
|
|
||||||
# -- Options for HTML output -------------------------------------------------
|
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||||
|
todo_include_todos = False
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output ----------------------------------------------
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
|
#
|
||||||
|
html_theme = 'sphinx_rtd_theme'
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
# documentation.
|
# documentation.
|
||||||
html_theme = 'pydoctheme'
|
#
|
||||||
html_theme_options = {'collapsiblesidebar': True}
|
# html_theme_options = {}
|
||||||
|
|
||||||
# Add any paths that contain custom themes here, relative to this directory.
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
html_theme_path = ["_themes"]
|
# html_theme_path = []
|
||||||
|
|
||||||
# The name for this set of Sphinx documents. If None, it defaults to
|
# The name for this set of Sphinx documents.
|
||||||
# "<project> v<release> documentation".
|
# "<project> v<release> documentation" by default.
|
||||||
html_title = "{project} {version} documentation".format(**locals())
|
#
|
||||||
|
# html_title = u'psutil v1.0'
|
||||||
|
|
||||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||||
|
#
|
||||||
# html_short_title = None
|
# html_short_title = None
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the top
|
# The name of an image file (relative to this directory) to place at the top
|
||||||
# of the sidebar.
|
# of the sidebar.
|
||||||
# html_logo = 'logo.png'
|
#
|
||||||
|
# html_logo = None
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to use as a favicon of
|
||||||
|
# the docs. This file should be a Windows icon file (.ico) being 16x16 or
|
||||||
|
# 32x32 pixels large.
|
||||||
|
|
||||||
# The name of an image file (within the static path) to use as favicon of the
|
|
||||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
|
||||||
# pixels large.
|
|
||||||
html_favicon = '_static/favicon.ico'
|
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets) here,
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
# relative to this directory. They are copied after the builtin static files,
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
html_static_path = ['_static']
|
html_static_path = ['_static']
|
||||||
|
|
||||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
# Add any extra paths that contain custom files (such as robots.txt or
|
||||||
# using the given strftime format.
|
# .htaccess) here, relative to this directory. These files are copied
|
||||||
html_last_updated_fmt = '%b %d, %Y'
|
# directly to the root of the documentation.
|
||||||
|
#
|
||||||
|
# html_extra_path = []
|
||||||
|
|
||||||
|
# If not None, a 'Last updated on:' timestamp is inserted at every page
|
||||||
|
# bottom, using the given strftime format.
|
||||||
|
# The empty string is equivalent to '%b %d, %Y'.
|
||||||
|
#
|
||||||
|
# html_last_updated_fmt = None
|
||||||
|
|
||||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||||
# typographically correct entities.
|
# typographically correct entities.
|
||||||
html_use_smartypants = True
|
#
|
||||||
|
# html_use_smartypants = True
|
||||||
|
|
||||||
# Custom sidebar templates, maps document names to template names.
|
# Custom sidebar templates, maps document names to template names.
|
||||||
html_sidebars = {
|
#
|
||||||
'index': 'indexsidebar.html',
|
# html_sidebars = {}
|
||||||
'**': ['globaltoc.html',
|
|
||||||
'relations.html',
|
|
||||||
'sourcelink.html',
|
|
||||||
'searchbox.html']
|
|
||||||
}
|
|
||||||
|
|
||||||
# Additional templates that should be rendered to pages, maps page names to
|
# Additional templates that should be rendered to pages, maps page names to
|
||||||
# template names.
|
# template names.
|
||||||
# html_additional_pages = {
|
#
|
||||||
# 'index': 'indexcontent.html',
|
# html_additional_pages = {}
|
||||||
# }
|
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
html_domain_indices = False
|
#
|
||||||
|
# html_domain_indices = True
|
||||||
|
|
||||||
# If false, no index is generated.
|
# If false, no index is generated.
|
||||||
html_use_index = True
|
#
|
||||||
|
# html_use_index = True
|
||||||
|
|
||||||
# If true, the index is split into individual pages for each letter.
|
# If true, the index is split into individual pages for each letter.
|
||||||
|
#
|
||||||
# html_split_index = False
|
# html_split_index = False
|
||||||
|
|
||||||
# If true, links to the reST sources are added to the pages.
|
# If true, links to the reST sources are added to the pages.
|
||||||
|
#
|
||||||
# html_show_sourcelink = True
|
# html_show_sourcelink = True
|
||||||
|
|
||||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||||
|
#
|
||||||
# html_show_sphinx = True
|
# html_show_sphinx = True
|
||||||
|
|
||||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||||
|
#
|
||||||
# html_show_copyright = True
|
# html_show_copyright = True
|
||||||
|
|
||||||
# If true, an OpenSearch description file will be output, and all pages will
|
# If true, an OpenSearch description file will be output, and all pages will
|
||||||
# contain a <link> tag referring to it. The value of this option must be the
|
# contain a <link> tag referring to it. The value of this option must be the
|
||||||
# base URL from which the finished HTML is served.
|
# base URL from which the finished HTML is served.
|
||||||
|
#
|
||||||
# html_use_opensearch = ''
|
# html_use_opensearch = ''
|
||||||
|
|
||||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||||
# html_file_suffix = None
|
# html_file_suffix = None
|
||||||
|
|
||||||
|
# Language to be used for generating the HTML full-text search index.
|
||||||
|
# Sphinx supports the following languages:
|
||||||
|
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
|
||||||
|
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh'
|
||||||
|
#
|
||||||
|
# html_search_language = 'en'
|
||||||
|
|
||||||
|
# A dictionary with options for the search language support, empty by default.
|
||||||
|
# 'ja' uses this config value.
|
||||||
|
# 'zh' user can custom change `jieba` dictionary path.
|
||||||
|
#
|
||||||
|
# html_search_options = {'type': 'default'}
|
||||||
|
|
||||||
|
# The name of a javascript file (relative to the configuration directory) that
|
||||||
|
# implements a search results scorer. If empty, the default will be used.
|
||||||
|
#
|
||||||
|
# html_search_scorer = 'scorer.js'
|
||||||
|
|
||||||
# Output file base name for HTML help builder.
|
# Output file base name for HTML help builder.
|
||||||
htmlhelp_basename = '%s-doc' % PROJECT_NAME
|
htmlhelp_basename = '%s-doc' % PROJECT_NAME
|
||||||
|
|
||||||
# -- Options for LaTeX output ------------------------------------------------
|
# -- Options for LaTeX output ---------------------------------------------
|
||||||
|
|
||||||
# The paper size ('letter' or 'a4').
|
latex_elements = {
|
||||||
# latex_paper_size = 'letter'
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
|
#
|
||||||
|
# 'papersize': 'letterpaper',
|
||||||
|
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
# latex_font_size = '10pt'
|
#
|
||||||
|
# 'pointsize': '10pt',
|
||||||
|
|
||||||
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
#
|
||||||
|
# 'preamble': '',
|
||||||
|
|
||||||
|
# Latex figure (float) alignment
|
||||||
|
#
|
||||||
|
# 'figure_align': 'htbp',
|
||||||
|
}
|
||||||
|
|
||||||
# Grouping the document tree into LaTeX files. List of tuples
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
# (source start file, target name, title, author, documentclass
|
# (source start file, target name, title,
|
||||||
# [howto/manual]).
|
# author, documentclass [howto, manual, or own class]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
('index', '%s.tex' % PROJECT_NAME,
|
(master_doc, 'psutil.tex', u'psutil Documentation',
|
||||||
'%s documentation' % PROJECT_NAME, AUTHOR),
|
AUTHOR, 'manual'),
|
||||||
]
|
]
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
# the top of the title page.
|
# the title page.
|
||||||
|
#
|
||||||
# latex_logo = None
|
# latex_logo = None
|
||||||
|
|
||||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||||
# not chapters.
|
# not chapters.
|
||||||
|
#
|
||||||
# latex_use_parts = False
|
# latex_use_parts = False
|
||||||
|
|
||||||
# If true, show page references after internal links.
|
# If true, show page references after internal links.
|
||||||
|
#
|
||||||
# latex_show_pagerefs = False
|
# latex_show_pagerefs = False
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
# If true, show URL addresses after external links.
|
||||||
|
#
|
||||||
# latex_show_urls = False
|
# latex_show_urls = False
|
||||||
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
|
||||||
# latex_preamble = ''
|
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
# Documents to append as an appendix to all manuals.
|
||||||
|
#
|
||||||
# latex_appendices = []
|
# latex_appendices = []
|
||||||
|
|
||||||
|
# It false, will not define \strong, \code, itleref, \crossref ... but only
|
||||||
|
# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added
|
||||||
|
# packages.
|
||||||
|
#
|
||||||
|
# latex_keep_old_macro_names = True
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
|
#
|
||||||
# latex_domain_indices = True
|
# latex_domain_indices = True
|
||||||
|
|
||||||
|
|
||||||
# -- Options for manual page output ------------------------------------------
|
# -- Options for manual page output ---------------------------------------
|
||||||
|
|
||||||
# One entry per manual page. List of tuples
|
# One entry per manual page. List of tuples
|
||||||
# (source start file, name, description, authors, manual section).
|
# (source start file, name, description, authors, manual section).
|
||||||
man_pages = [
|
man_pages = [
|
||||||
('index', PROJECT_NAME, '%s documentation' % PROJECT_NAME, [AUTHOR], 1)
|
(master_doc, 'psutil', u'psutil Documentation',
|
||||||
|
[author], 1)
|
||||||
]
|
]
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
# If true, show URL addresses after external links.
|
||||||
|
#
|
||||||
# man_show_urls = False
|
# man_show_urls = False
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for Texinfo output -------------------------------------------
|
||||||
|
|
||||||
|
# Grouping the document tree into Texinfo files. List of tuples
|
||||||
|
# (source start file, target name, title, author,
|
||||||
|
# dir menu entry, description, category)
|
||||||
|
texinfo_documents = [
|
||||||
|
(master_doc, 'psutil', u'psutil Documentation',
|
||||||
|
author, 'psutil', 'One line description of project.',
|
||||||
|
'Miscellaneous'),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Documents to append as an appendix to all manuals.
|
||||||
|
#
|
||||||
|
# texinfo_appendices = []
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
#
|
||||||
|
# texinfo_domain_indices = True
|
||||||
|
|
||||||
|
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||||
|
#
|
||||||
|
# texinfo_show_urls = 'footnote'
|
||||||
|
|
||||||
|
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||||
|
#
|
||||||
|
# texinfo_no_detailmenu = False
|
||||||
|
|
||||||
|
|
||||||
|
html_context = {
|
||||||
|
'css_files': [
|
||||||
|
'https://media.readthedocs.org/css/sphinx_rtd_theme.css',
|
||||||
|
'https://media.readthedocs.org/css/readthedocs-doc-embed.css',
|
||||||
|
'_static/css/custom.css',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,242 +1,242 @@
|
||||||
@ECHO OFF
|
@ECHO OFF
|
||||||
|
|
||||||
REM Command file for Sphinx documentation
|
REM Command file for Sphinx documentation
|
||||||
|
|
||||||
if "%SPHINXBUILD%" == "" (
|
if "%SPHINXBUILD%" == "" (
|
||||||
set SPHINXBUILD=sphinx-build
|
set SPHINXBUILD=sphinx-build
|
||||||
)
|
)
|
||||||
set BUILDDIR=_build
|
set BUILDDIR=_build
|
||||||
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
||||||
set I18NSPHINXOPTS=%SPHINXOPTS% .
|
set I18NSPHINXOPTS=%SPHINXOPTS% .
|
||||||
if NOT "%PAPER%" == "" (
|
if NOT "%PAPER%" == "" (
|
||||||
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
||||||
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
|
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "" goto help
|
if "%1" == "" goto help
|
||||||
|
|
||||||
if "%1" == "help" (
|
if "%1" == "help" (
|
||||||
:help
|
:help
|
||||||
echo.Please use `make ^<target^>` where ^<target^> is one of
|
echo.Please use `make ^<target^>` where ^<target^> is one of
|
||||||
echo. html to make standalone HTML files
|
echo. html to make standalone HTML files
|
||||||
echo. dirhtml to make HTML files named index.html in directories
|
echo. dirhtml to make HTML files named index.html in directories
|
||||||
echo. singlehtml to make a single large HTML file
|
echo. singlehtml to make a single large HTML file
|
||||||
echo. pickle to make pickle files
|
echo. pickle to make pickle files
|
||||||
echo. json to make JSON files
|
echo. json to make JSON files
|
||||||
echo. htmlhelp to make HTML files and a HTML help project
|
echo. htmlhelp to make HTML files and a HTML help project
|
||||||
echo. qthelp to make HTML files and a qthelp project
|
echo. qthelp to make HTML files and a qthelp project
|
||||||
echo. devhelp to make HTML files and a Devhelp project
|
echo. devhelp to make HTML files and a Devhelp project
|
||||||
echo. epub to make an epub
|
echo. epub to make an epub
|
||||||
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
||||||
echo. text to make text files
|
echo. text to make text files
|
||||||
echo. man to make manual pages
|
echo. man to make manual pages
|
||||||
echo. texinfo to make Texinfo files
|
echo. texinfo to make Texinfo files
|
||||||
echo. gettext to make PO message catalogs
|
echo. gettext to make PO message catalogs
|
||||||
echo. changes to make an overview over all changed/added/deprecated items
|
echo. changes to make an overview over all changed/added/deprecated items
|
||||||
echo. xml to make Docutils-native XML files
|
echo. xml to make Docutils-native XML files
|
||||||
echo. pseudoxml to make pseudoxml-XML files for display purposes
|
echo. pseudoxml to make pseudoxml-XML files for display purposes
|
||||||
echo. linkcheck to check all external links for integrity
|
echo. linkcheck to check all external links for integrity
|
||||||
echo. doctest to run all doctests embedded in the documentation if enabled
|
echo. doctest to run all doctests embedded in the documentation if enabled
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "clean" (
|
if "%1" == "clean" (
|
||||||
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
|
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
|
||||||
del /q /s %BUILDDIR%\*
|
del /q /s %BUILDDIR%\*
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
%SPHINXBUILD% 2> nul
|
%SPHINXBUILD% 2> nul
|
||||||
if errorlevel 9009 (
|
if errorlevel 9009 (
|
||||||
echo.
|
echo.
|
||||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||||
echo.may add the Sphinx directory to PATH.
|
echo.may add the Sphinx directory to PATH.
|
||||||
echo.
|
echo.
|
||||||
echo.If you don't have Sphinx installed, grab it from
|
echo.If you don't have Sphinx installed, grab it from
|
||||||
echo.http://sphinx-doc.org/
|
echo.http://sphinx-doc.org/
|
||||||
exit /b 1
|
exit /b 1
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "html" (
|
if "%1" == "html" (
|
||||||
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "dirhtml" (
|
if "%1" == "dirhtml" (
|
||||||
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
|
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
|
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "singlehtml" (
|
if "%1" == "singlehtml" (
|
||||||
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
|
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
|
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "pickle" (
|
if "%1" == "pickle" (
|
||||||
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
|
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished; now you can process the pickle files.
|
echo.Build finished; now you can process the pickle files.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "json" (
|
if "%1" == "json" (
|
||||||
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
|
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished; now you can process the JSON files.
|
echo.Build finished; now you can process the JSON files.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "htmlhelp" (
|
if "%1" == "htmlhelp" (
|
||||||
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
|
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished; now you can run HTML Help Workshop with the ^
|
echo.Build finished; now you can run HTML Help Workshop with the ^
|
||||||
.hhp project file in %BUILDDIR%/htmlhelp.
|
.hhp project file in %BUILDDIR%/htmlhelp.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "qthelp" (
|
if "%1" == "qthelp" (
|
||||||
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
|
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
||||||
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
||||||
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\psutil.qhcp
|
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\pyftpdlib.qhcp
|
||||||
echo.To view the help file:
|
echo.To view the help file:
|
||||||
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\psutil.ghc
|
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\pyftpdlib.ghc
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "devhelp" (
|
if "%1" == "devhelp" (
|
||||||
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
|
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished.
|
echo.Build finished.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "epub" (
|
if "%1" == "epub" (
|
||||||
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
|
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished. The epub file is in %BUILDDIR%/epub.
|
echo.Build finished. The epub file is in %BUILDDIR%/epub.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "latex" (
|
if "%1" == "latex" (
|
||||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
|
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "latexpdf" (
|
if "%1" == "latexpdf" (
|
||||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||||
cd %BUILDDIR%/latex
|
cd %BUILDDIR%/latex
|
||||||
make all-pdf
|
make all-pdf
|
||||||
cd %BUILDDIR%/..
|
cd %BUILDDIR%/..
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "latexpdfja" (
|
if "%1" == "latexpdfja" (
|
||||||
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||||
cd %BUILDDIR%/latex
|
cd %BUILDDIR%/latex
|
||||||
make all-pdf-ja
|
make all-pdf-ja
|
||||||
cd %BUILDDIR%/..
|
cd %BUILDDIR%/..
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "text" (
|
if "%1" == "text" (
|
||||||
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
|
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished. The text files are in %BUILDDIR%/text.
|
echo.Build finished. The text files are in %BUILDDIR%/text.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "man" (
|
if "%1" == "man" (
|
||||||
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
|
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished. The manual pages are in %BUILDDIR%/man.
|
echo.Build finished. The manual pages are in %BUILDDIR%/man.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "texinfo" (
|
if "%1" == "texinfo" (
|
||||||
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
|
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
|
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "gettext" (
|
if "%1" == "gettext" (
|
||||||
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
|
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
|
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "changes" (
|
if "%1" == "changes" (
|
||||||
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.The overview file is in %BUILDDIR%/changes.
|
echo.The overview file is in %BUILDDIR%/changes.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "linkcheck" (
|
if "%1" == "linkcheck" (
|
||||||
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
|
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Link check complete; look for any errors in the above output ^
|
echo.Link check complete; look for any errors in the above output ^
|
||||||
or in %BUILDDIR%/linkcheck/output.txt.
|
or in %BUILDDIR%/linkcheck/output.txt.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "doctest" (
|
if "%1" == "doctest" (
|
||||||
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
|
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Testing of doctests in the sources finished, look at the ^
|
echo.Testing of doctests in the sources finished, look at the ^
|
||||||
results in %BUILDDIR%/doctest/output.txt.
|
results in %BUILDDIR%/doctest/output.txt.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "xml" (
|
if "%1" == "xml" (
|
||||||
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
|
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished. The XML files are in %BUILDDIR%/xml.
|
echo.Build finished. The XML files are in %BUILDDIR%/xml.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
if "%1" == "pseudoxml" (
|
if "%1" == "pseudoxml" (
|
||||||
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
|
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
|
||||||
if errorlevel 1 exit /b 1
|
if errorlevel 1 exit /b 1
|
||||||
echo.
|
echo.
|
||||||
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
|
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
:end
|
:end
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
cpu 1974613 1749 485728 6305758 80280 15 5924 0 0 0
|
|
||||||
|
|
||||||
cpu0 519156 374 132999 5977865 72925 10 1458 0 0 0
|
|
||||||
|
|
||||||
cpu1 524667 401 125931 108960 2110 4 2214 0 0 0
|
|
||||||
|
|
||||||
cpu2 462286 520 117046 109514 2666 0 828 0 0 0
|
|
||||||
|
|
||||||
cpu3 468502 453 109750 109418 2578 0 1424 0 0 0
|
|
||||||
|
|
||||||
|
|
|
@ -1,78 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
|
||||||
# Use of this source code is governed by a BSD-style license that can be
|
|
||||||
# found in the LICENSE file.
|
|
||||||
|
|
||||||
"""
|
|
||||||
A clone of 'ifconfig' on UNIX.
|
|
||||||
|
|
||||||
$ python examples/ifconfig.py
|
|
||||||
lo (speed=0MB, duplex=?, mtu=65536, up=yes):
|
|
||||||
IPv4 address : 127.0.0.1
|
|
||||||
broadcast : 127.0.0.1
|
|
||||||
netmask : 255.0.0.0
|
|
||||||
IPv6 address : ::1
|
|
||||||
netmask : ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
|
|
||||||
MAC address : 00:00:00:00:00:00
|
|
||||||
broadcast : 00:00:00:00:00:00
|
|
||||||
|
|
||||||
wlan0 (speed=0MB, duplex=?, mtu=1500, up=yes):
|
|
||||||
IPv4 address : 10.0.3.1
|
|
||||||
broadcast : 10.0.3.255
|
|
||||||
netmask : 255.255.255.0
|
|
||||||
IPv6 address : fe80::3005:adff:fe31:8698
|
|
||||||
netmask : ffff:ffff:ffff:ffff::
|
|
||||||
MAC address : 32:05:ad:31:86:98
|
|
||||||
broadcast : ff:ff:ff:ff:ff:ff
|
|
||||||
|
|
||||||
eth0 (speed=100MB, duplex=full, mtu=1500, up=yes):
|
|
||||||
IPv4 address : 192.168.1.2
|
|
||||||
broadcast : 192.168.1.255
|
|
||||||
netmask : 255.255.255.0
|
|
||||||
IPv6 address : fe80::c685:8ff:fe45:641
|
|
||||||
netmask : ffff:ffff:ffff:ffff::
|
|
||||||
MAC address : c4:85:08:45:06:41
|
|
||||||
broadcast : ff:ff:ff:ff:ff:ff
|
|
||||||
"""
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
import socket
|
|
||||||
|
|
||||||
import psutil
|
|
||||||
|
|
||||||
|
|
||||||
af_map = {
|
|
||||||
socket.AF_INET: 'IPv4',
|
|
||||||
socket.AF_INET6: 'IPv6',
|
|
||||||
psutil.AF_LINK: 'MAC',
|
|
||||||
}
|
|
||||||
|
|
||||||
duplex_map = {
|
|
||||||
psutil.NIC_DUPLEX_FULL: "full",
|
|
||||||
psutil.NIC_DUPLEX_HALF: "half",
|
|
||||||
psutil.NIC_DUPLEX_UNKNOWN: "?",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
stats = psutil.net_if_stats()
|
|
||||||
for nic, addrs in psutil.net_if_addrs().items():
|
|
||||||
if nic in stats:
|
|
||||||
print("%s (speed=%sMB, duplex=%s, mtu=%s, up=%s):" % (
|
|
||||||
nic, stats[nic].speed, duplex_map[stats[nic].duplex],
|
|
||||||
stats[nic].mtu, "yes" if stats[nic].isup else "no"))
|
|
||||||
else:
|
|
||||||
print("%s:" % (nic))
|
|
||||||
for addr in addrs:
|
|
||||||
print(" %-8s" % af_map.get(addr.family, addr.family), end="")
|
|
||||||
print(" address : %s" % addr.address)
|
|
||||||
if addr.broadcast:
|
|
||||||
print(" broadcast : %s" % addr.broadcast)
|
|
||||||
if addr.netmask:
|
|
||||||
print(" netmask : %s" % addr.netmask)
|
|
||||||
print("")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
|
@ -1,167 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
|
||||||
# Use of this source code is governed by a BSD-style license that can be
|
|
||||||
# found in the LICENSE file.
|
|
||||||
|
|
||||||
"""
|
|
||||||
Print detailed information about a process.
|
|
||||||
Author: Giampaolo Rodola' <g.rodola@gmail.com>
|
|
||||||
|
|
||||||
$ python examples/process_detail.py
|
|
||||||
pid 820
|
|
||||||
name python
|
|
||||||
exe /usr/bin/python2.7
|
|
||||||
parent 29613 (bash)
|
|
||||||
cmdline python examples/process_detail.py
|
|
||||||
started 2014-41-27 03:41
|
|
||||||
user giampaolo
|
|
||||||
uids real=1000, effective=1000, saved=1000
|
|
||||||
gids real=1000, effective=1000, saved=1000
|
|
||||||
terminal /dev/pts/17
|
|
||||||
cwd /ssd/svn/psutil
|
|
||||||
memory 0.1% (resident=10.6M, virtual=58.5M)
|
|
||||||
cpu 0.0% (user=0.09, system=0.0)
|
|
||||||
status running
|
|
||||||
niceness 0
|
|
||||||
num threads 1
|
|
||||||
I/O bytes-read=0B, bytes-written=0B
|
|
||||||
open files
|
|
||||||
running threads id=820, user-time=0.09, sys-time=0.0
|
|
||||||
"""
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
import os
|
|
||||||
import socket
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import psutil
|
|
||||||
|
|
||||||
|
|
||||||
POSIX = os.name == 'posix'
|
|
||||||
|
|
||||||
|
|
||||||
def convert_bytes(n):
|
|
||||||
symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
|
|
||||||
prefix = {}
|
|
||||||
for i, s in enumerate(symbols):
|
|
||||||
prefix[s] = 1 << (i + 1) * 10
|
|
||||||
for s in reversed(symbols):
|
|
||||||
if n >= prefix[s]:
|
|
||||||
value = float(n) / prefix[s]
|
|
||||||
return '%.1f%s' % (value, s)
|
|
||||||
return "%sB" % n
|
|
||||||
|
|
||||||
|
|
||||||
def print_(a, b):
|
|
||||||
if sys.stdout.isatty() and POSIX:
|
|
||||||
fmt = '\x1b[1;32m%-17s\x1b[0m %s' % (a, b)
|
|
||||||
else:
|
|
||||||
fmt = '%-15s %s' % (a, b)
|
|
||||||
# python 2/3 compatibility layer
|
|
||||||
sys.stdout.write(fmt + '\n')
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
|
|
||||||
def run(pid):
|
|
||||||
ACCESS_DENIED = ''
|
|
||||||
try:
|
|
||||||
p = psutil.Process(pid)
|
|
||||||
pinfo = p.as_dict(ad_value=ACCESS_DENIED)
|
|
||||||
except psutil.NoSuchProcess as err:
|
|
||||||
sys.exit(str(err))
|
|
||||||
|
|
||||||
try:
|
|
||||||
parent = p.parent()
|
|
||||||
if parent:
|
|
||||||
parent = '(%s)' % parent.name()
|
|
||||||
else:
|
|
||||||
parent = ''
|
|
||||||
except psutil.Error:
|
|
||||||
parent = ''
|
|
||||||
if pinfo['create_time'] != ACCESS_DENIED:
|
|
||||||
started = datetime.datetime.fromtimestamp(
|
|
||||||
pinfo['create_time']).strftime('%Y-%m-%d %H:%M')
|
|
||||||
else:
|
|
||||||
started = ACCESS_DENIED
|
|
||||||
io = pinfo.get('io_counters', ACCESS_DENIED)
|
|
||||||
if pinfo['memory_info'] != ACCESS_DENIED:
|
|
||||||
mem = '%s%% (resident=%s, virtual=%s) ' % (
|
|
||||||
round(pinfo['memory_percent'], 1),
|
|
||||||
convert_bytes(pinfo['memory_info'].rss),
|
|
||||||
convert_bytes(pinfo['memory_info'].vms))
|
|
||||||
else:
|
|
||||||
mem = ACCESS_DENIED
|
|
||||||
children = p.children()
|
|
||||||
|
|
||||||
print_('pid', pinfo['pid'])
|
|
||||||
print_('name', pinfo['name'])
|
|
||||||
print_('exe', pinfo['exe'])
|
|
||||||
print_('parent', '%s %s' % (pinfo['ppid'], parent))
|
|
||||||
print_('cmdline', ' '.join(pinfo['cmdline']))
|
|
||||||
print_('started', started)
|
|
||||||
print_('user', pinfo['username'])
|
|
||||||
if POSIX and pinfo['uids'] and pinfo['gids']:
|
|
||||||
print_('uids', 'real=%s, effective=%s, saved=%s' % pinfo['uids'])
|
|
||||||
if POSIX and pinfo['gids']:
|
|
||||||
print_('gids', 'real=%s, effective=%s, saved=%s' % pinfo['gids'])
|
|
||||||
if POSIX:
|
|
||||||
print_('terminal', pinfo['terminal'] or '')
|
|
||||||
print_('cwd', pinfo['cwd'])
|
|
||||||
print_('memory', mem)
|
|
||||||
print_('cpu', '%s%% (user=%s, system=%s)' % (
|
|
||||||
pinfo['cpu_percent'],
|
|
||||||
getattr(pinfo['cpu_times'], 'user', '?'),
|
|
||||||
getattr(pinfo['cpu_times'], 'system', '?')))
|
|
||||||
print_('status', pinfo['status'])
|
|
||||||
print_('niceness', pinfo['nice'])
|
|
||||||
print_('num threads', pinfo['num_threads'])
|
|
||||||
if io != ACCESS_DENIED:
|
|
||||||
print_('I/O', 'bytes-read=%s, bytes-written=%s' % (
|
|
||||||
convert_bytes(io.read_bytes),
|
|
||||||
convert_bytes(io.write_bytes)))
|
|
||||||
if children:
|
|
||||||
print_('children', '')
|
|
||||||
for child in children:
|
|
||||||
print_('', 'pid=%s name=%s' % (child.pid, child.name()))
|
|
||||||
|
|
||||||
if pinfo['open_files'] != ACCESS_DENIED:
|
|
||||||
print_('open files', '')
|
|
||||||
for file in pinfo['open_files']:
|
|
||||||
print_('', 'fd=%s %s ' % (file.fd, file.path))
|
|
||||||
|
|
||||||
if pinfo['threads']:
|
|
||||||
print_('running threads', '')
|
|
||||||
for thread in pinfo['threads']:
|
|
||||||
print_('', 'id=%s, user-time=%s, sys-time=%s' % (
|
|
||||||
thread.id, thread.user_time, thread.system_time))
|
|
||||||
if pinfo['connections'] not in (ACCESS_DENIED, []):
|
|
||||||
print_('open connections', '')
|
|
||||||
for conn in pinfo['connections']:
|
|
||||||
if conn.type == socket.SOCK_STREAM:
|
|
||||||
type = 'TCP'
|
|
||||||
elif conn.type == socket.SOCK_DGRAM:
|
|
||||||
type = 'UDP'
|
|
||||||
else:
|
|
||||||
type = 'UNIX'
|
|
||||||
lip, lport = conn.laddr
|
|
||||||
if not conn.raddr:
|
|
||||||
rip, rport = '*', '*'
|
|
||||||
else:
|
|
||||||
rip, rport = conn.raddr
|
|
||||||
print_('', '%s:%s -> %s:%s type=%s status=%s' % (
|
|
||||||
lip, lport, rip, rport, type, conn.status))
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv=None):
|
|
||||||
if argv is None:
|
|
||||||
argv = sys.argv
|
|
||||||
if len(argv) == 1:
|
|
||||||
sys.exit(run(os.getpid()))
|
|
||||||
elif len(argv) == 2:
|
|
||||||
sys.exit(run(int(argv[1])))
|
|
||||||
else:
|
|
||||||
sys.exit('usage: %s [pid]' % __file__)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
sys.exit(main())
|
|
|
@ -23,179 +23,10 @@ if "%PYTHON%" == "" (
|
||||||
set PYTHON=C:\Python27\python.exe
|
set PYTHON=C:\Python27\python.exe
|
||||||
)
|
)
|
||||||
if "%TSCRIPT%" == "" (
|
if "%TSCRIPT%" == "" (
|
||||||
set TSCRIPT=test\test_psutil.py
|
set TSCRIPT=psutil\tests\__main__.py
|
||||||
)
|
)
|
||||||
|
|
||||||
set PYTHON26=C:\Python26\python.exe
|
|
||||||
set PYTHON27=C:\Python27\python.exe
|
|
||||||
set PYTHON33=C:\Python33\python.exe
|
|
||||||
set PYTHON34=C:\Python34\python.exe
|
|
||||||
set PYTHON26-64=C:\Python26-64\python.exe
|
|
||||||
set PYTHON27-64=C:\Python27-64\python.exe
|
|
||||||
set PYTHON33-64=C:\Python33-64\python.exe
|
|
||||||
set PYTHON34-64=C:\Python34-64\python.exe
|
|
||||||
|
|
||||||
set ALL_PYTHONS=%PYTHON26% %PYTHON27% %PYTHON33% %PYTHON34% %PYTHON26-64% %PYTHON27-64% %PYTHON33-64% %PYTHON34-64%
|
|
||||||
|
|
||||||
rem Needed to locate the .pypirc file and upload exes on PYPI.
|
rem Needed to locate the .pypirc file and upload exes on PYPI.
|
||||||
set HOME=%USERPROFILE%
|
set HOME=%USERPROFILE%
|
||||||
|
|
||||||
rem ==========================================================================
|
%PYTHON% scripts\internal\winmake.py %1 %2 %3 %4 %5 %6
|
||||||
|
|
||||||
if "%1" == "help" (
|
|
||||||
:help
|
|
||||||
echo Run `make ^<target^>` where ^<target^> is one of:
|
|
||||||
echo build compile without installing
|
|
||||||
echo build-all build exes + wheels
|
|
||||||
echo clean clean build files
|
|
||||||
echo flake8 run flake8
|
|
||||||
echo install compile and install
|
|
||||||
echo setup-dev-env install pip, pywin32, wheels, etc. for all python versions
|
|
||||||
echo test run tests
|
|
||||||
echo test-memleaks run memory leak tests
|
|
||||||
echo test-process run process related tests
|
|
||||||
echo test-system run system APIs related tests
|
|
||||||
echo uninstall uninstall
|
|
||||||
echo upload-all upload exes + wheels
|
|
||||||
goto :eof
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "clean" (
|
|
||||||
for /r %%R in (__pycache__) do if exist %%R (rmdir /S /Q %%R)
|
|
||||||
for /r %%R in (*.pyc) do if exist %%R (del /s %%R)
|
|
||||||
for /r %%R in (*.pyd) do if exist %%R (del /s %%R)
|
|
||||||
for /r %%R in (*.orig) do if exist %%R (del /s %%R)
|
|
||||||
for /r %%R in (*.bak) do if exist %%R (del /s %%R)
|
|
||||||
for /r %%R in (*.rej) do if exist %%R (del /s %%R)
|
|
||||||
if exist psutil.egg-info (rmdir /S /Q psutil.egg-info)
|
|
||||||
if exist build (rmdir /S /Q build)
|
|
||||||
if exist dist (rmdir /S /Q dist)
|
|
||||||
goto :eof
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "build" (
|
|
||||||
:build
|
|
||||||
"C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat"
|
|
||||||
%PYTHON% setup.py build
|
|
||||||
if %errorlevel% neq 0 goto :error
|
|
||||||
rem copies *.pyd files in ./psutil directory in order to allow
|
|
||||||
rem "import psutil" when using the interactive interpreter from
|
|
||||||
rem within this directory.
|
|
||||||
%PYTHON% setup.py build_ext -i
|
|
||||||
if %errorlevel% neq 0 goto :error
|
|
||||||
goto :eof
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "install" (
|
|
||||||
:install
|
|
||||||
call :build
|
|
||||||
%PYTHON% setup.py install
|
|
||||||
goto :eof
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "uninstall" (
|
|
||||||
for %%A in ("%PYTHON%") do (
|
|
||||||
set folder=%%~dpA
|
|
||||||
)
|
|
||||||
for /F "delims=" %%i in ('dir /b %folder%\Lib\site-packages\*psutil*') do (
|
|
||||||
rmdir /S /Q %folder%\Lib\site-packages\%%i
|
|
||||||
)
|
|
||||||
goto :eof
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "test" (
|
|
||||||
call :install
|
|
||||||
%PYTHON% %TSCRIPT%
|
|
||||||
goto :eof
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "test-process" (
|
|
||||||
call :install
|
|
||||||
%PYTHON% -m unittest -v test.test_psutil.TestProcess
|
|
||||||
goto :eof
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "test-system" (
|
|
||||||
call :install
|
|
||||||
%PYTHON% -m unittest -v test.test_psutil.TestSystem
|
|
||||||
goto :eof
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "test-memleaks" (
|
|
||||||
call :install
|
|
||||||
%PYTHON% test\test_memory_leaks.py
|
|
||||||
goto :eof
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "build-all" (
|
|
||||||
:build-all
|
|
||||||
"C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat"
|
|
||||||
for %%P in (%ALL_PYTHONS%) do (
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
@echo building exe for %%P
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
%%P setup.py build bdist_wininst || goto :error
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
@echo building wheel for %%P
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
%%P setup.py build bdist_wheel || goto :error
|
|
||||||
)
|
|
||||||
echo OK
|
|
||||||
goto :eof
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "upload-all" (
|
|
||||||
:upload-exes
|
|
||||||
"C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat"
|
|
||||||
for %%P in (%ALL_PYTHONS%) do (
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
@echo uploading exe for %%P
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
%%P setup.py build bdist_wininst upload || goto :error
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
@echo uploading wheel for %%P
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
%%P setup.py build bdist_wheel upload || goto :error
|
|
||||||
)
|
|
||||||
echo OK
|
|
||||||
goto :eof
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "setup-dev-env" (
|
|
||||||
:setup-env
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
@echo downloading pip installer
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
C:\python27\python.exe -c "import urllib2; r = urllib2.urlopen('https://raw.github.com/pypa/pip/master/contrib/get-pip.py'); open('get-pip.py', 'wb').write(r.read())"
|
|
||||||
for %%P in (%ALL_PYTHONS%) do (
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
@echo installing pip for %%P
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
%%P get-pip.py
|
|
||||||
)
|
|
||||||
for %%P in (%ALL_PYTHONS%) do (
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
@echo installing deps for %%P
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
rem mandatory / for unittests
|
|
||||||
%%P -m pip install unittest2 ipaddress mock wmi wheel pypiwin32 --upgrade
|
|
||||||
rem nice to have
|
|
||||||
%%P -m pip install ipdb pep8 pyflakes flake8 --upgrade
|
|
||||||
)
|
|
||||||
goto :eof
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%1" == "flake8" (
|
|
||||||
:flake8
|
|
||||||
%PYTHON% -c "from flake8.main import main; main()"
|
|
||||||
goto :eof
|
|
||||||
)
|
|
||||||
|
|
||||||
goto :help
|
|
||||||
|
|
||||||
:error
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
@echo last command exited with error code %errorlevel%
|
|
||||||
@echo ------------------------------------------------
|
|
||||||
@exit /b %errorlevel%
|
|
||||||
goto :eof
|
|
||||||
|
|
|
@ -1,434 +0,0 @@
|
||||||
Metadata-Version: 1.1
|
|
||||||
Name: psutil
|
|
||||||
Version: 3.1.1
|
|
||||||
Summary: psutil is a cross-platform library for retrieving information onrunning processes and system utilization (CPU, memory, disks, network)in Python.
|
|
||||||
Home-page: https://github.com/giampaolo/psutil
|
|
||||||
Author: Giampaolo Rodola
|
|
||||||
Author-email: g.rodola <at> gmail <dot> com
|
|
||||||
License: BSD
|
|
||||||
Description: .. image:: https://img.shields.io/pypi/dm/psutil.svg
|
|
||||||
:target: https://pypi.python.org/pypi/psutil#downloads
|
|
||||||
:alt: Downloads this month
|
|
||||||
|
|
||||||
.. image:: https://api.travis-ci.org/giampaolo/psutil.png?branch=master
|
|
||||||
:target: https://travis-ci.org/giampaolo/psutil
|
|
||||||
:alt: Linux tests (Travis)
|
|
||||||
|
|
||||||
.. image:: https://ci.appveyor.com/api/projects/status/qdwvw7v1t915ywr5/branch/master?svg=true
|
|
||||||
:target: https://ci.appveyor.com/project/giampaolo/psutil
|
|
||||||
:alt: Windows tests (Appveyor)
|
|
||||||
|
|
||||||
.. image:: https://coveralls.io/repos/giampaolo/psutil/badge.svg?branch=master&service=github
|
|
||||||
:target: https://coveralls.io/github/giampaolo/psutil?branch=master
|
|
||||||
:alt: Test coverage (coverall.io)
|
|
||||||
|
|
||||||
.. image:: https://img.shields.io/pypi/v/psutil.svg
|
|
||||||
:target: https://pypi.python.org/pypi/psutil/
|
|
||||||
:alt: Latest version
|
|
||||||
|
|
||||||
.. image:: https://img.shields.io/github/stars/giampaolo/psutil.svg
|
|
||||||
:target: https://github.com/giampaolo/psutil/
|
|
||||||
:alt: Github stars
|
|
||||||
|
|
||||||
.. image:: https://img.shields.io/scrutinizer/g/giampaolo/psutil.svg
|
|
||||||
:target: https://scrutinizer-ci.com/g/giampaolo/psutil/
|
|
||||||
:alt: Code quality (scrutinizer-ci.com)
|
|
||||||
|
|
||||||
.. image:: https://img.shields.io/pypi/l/psutil.svg
|
|
||||||
:target: https://pypi.python.org/pypi/psutil/
|
|
||||||
:alt: License
|
|
||||||
|
|
||||||
===========
|
|
||||||
Quick links
|
|
||||||
===========
|
|
||||||
|
|
||||||
- `Home page <https://github.com/giampaolo/psutil>`_
|
|
||||||
- `Documentation <http://pythonhosted.org/psutil/>`_
|
|
||||||
- `Installation <https://github.com/giampaolo/psutil/blob/master/INSTALL.rst>`_
|
|
||||||
- `Download <https://pypi.python.org/pypi?:action=display&name=psutil#downloads>`_
|
|
||||||
- `Forum <http://groups.google.com/group/psutil/topics>`_
|
|
||||||
- `Blog <http://grodola.blogspot.com/search/label/psutil>`_
|
|
||||||
- `Development guide <https://github.com/giampaolo/psutil/blob/master/DEVGUIDE.rst>`_
|
|
||||||
- `What's new <https://github.com/giampaolo/psutil/blob/master/HISTORY.rst>`_
|
|
||||||
|
|
||||||
=======
|
|
||||||
Summary
|
|
||||||
=======
|
|
||||||
|
|
||||||
psutil (python system and process utilities) is a cross-platform library for
|
|
||||||
retrieving information on **running processes** and **system utilization**
|
|
||||||
(CPU, memory, disks, network) in Python. It is useful mainly for **system
|
|
||||||
monitoring**, **profiling and limiting process resources** and **management of
|
|
||||||
running processes**. It implements many functionalities offered by command line
|
|
||||||
tools such as: ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice,
|
|
||||||
ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap. It currently supports
|
|
||||||
**Linux, Windows, OSX, FreeBSD** and **Sun Solaris**, both **32-bit** and
|
|
||||||
**64-bit** architectures, with Python versions from **2.6 to 3.5** (users of
|
|
||||||
Python 2.4 and 2.5 may use `2.1.3 <https://pypi.python.org/pypi?name=psutil&version=2.1.3&:action=files>`__ version).
|
|
||||||
`PyPy <http://pypy.org/>`__ is also known to work.
|
|
||||||
|
|
||||||
====================
|
|
||||||
Example applications
|
|
||||||
====================
|
|
||||||
|
|
||||||
.. image:: http://psutil.googlecode.com/svn/wiki/images/top-thumb.png
|
|
||||||
:target: http://psutil.googlecode.com/svn/wiki/images/top.png
|
|
||||||
:alt: top
|
|
||||||
|
|
||||||
.. image:: http://psutil.googlecode.com/svn/wiki/images/nettop-thumb.png
|
|
||||||
:target: http://psutil.googlecode.com/svn/wiki/images/nettop.png
|
|
||||||
:alt: nettop
|
|
||||||
|
|
||||||
.. image:: http://psutil.googlecode.com/svn/wiki/images/iotop-thumb.png
|
|
||||||
:target: http://psutil.googlecode.com/svn/wiki/images/iotop.png
|
|
||||||
:alt: iotop
|
|
||||||
|
|
||||||
See also:
|
|
||||||
|
|
||||||
* https://github.com/nicolargo/glances
|
|
||||||
* https://github.com/google/grr
|
|
||||||
* https://github.com/Jahaja/psdash
|
|
||||||
|
|
||||||
==============
|
|
||||||
Example usages
|
|
||||||
==============
|
|
||||||
|
|
||||||
CPU
|
|
||||||
===
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
>>> import psutil
|
|
||||||
>>> psutil.cpu_times()
|
|
||||||
scputimes(user=3961.46, nice=169.729, system=2150.659, idle=16900.540, iowait=629.59, irq=0.0, softirq=19.42, steal=0.0, guest=0, nice=0.0)
|
|
||||||
>>>
|
|
||||||
>>> for x in range(3):
|
|
||||||
... psutil.cpu_percent(interval=1)
|
|
||||||
...
|
|
||||||
4.0
|
|
||||||
5.9
|
|
||||||
3.8
|
|
||||||
>>>
|
|
||||||
>>> for x in range(3):
|
|
||||||
... psutil.cpu_percent(interval=1, percpu=True)
|
|
||||||
...
|
|
||||||
[4.0, 6.9, 3.7, 9.2]
|
|
||||||
[7.0, 8.5, 2.4, 2.1]
|
|
||||||
[1.2, 9.0, 9.9, 7.2]
|
|
||||||
>>>
|
|
||||||
>>>
|
|
||||||
>>> for x in range(3):
|
|
||||||
... psutil.cpu_times_percent(interval=1, percpu=False)
|
|
||||||
...
|
|
||||||
scputimes(user=1.5, nice=0.0, system=0.5, idle=96.5, iowait=1.5, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
|
||||||
scputimes(user=1.0, nice=0.0, system=0.0, idle=99.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
|
||||||
scputimes(user=2.0, nice=0.0, system=0.0, idle=98.0, iowait=0.0, irq=0.0, softirq=0.0, steal=0.0, guest=0.0, guest_nice=0.0)
|
|
||||||
>>>
|
|
||||||
>>> psutil.cpu_count()
|
|
||||||
4
|
|
||||||
>>> psutil.cpu_count(logical=False)
|
|
||||||
2
|
|
||||||
>>>
|
|
||||||
|
|
||||||
Memory
|
|
||||||
======
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
>>> psutil.virtual_memory()
|
|
||||||
svmem(total=8374149120, available=2081050624, percent=75.1, used=8074080256, free=300068864, active=3294920704, inactive=1361616896, buffers=529895424, cached=1251086336)
|
|
||||||
>>> psutil.swap_memory()
|
|
||||||
sswap(total=2097147904, used=296128512, free=1801019392, percent=14.1, sin=304193536, sout=677842944)
|
|
||||||
>>>
|
|
||||||
|
|
||||||
Disks
|
|
||||||
=====
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
>>> psutil.disk_partitions()
|
|
||||||
[sdiskpart(device='/dev/sda1', mountpoint='/', fstype='ext4', opts='rw,nosuid'),
|
|
||||||
sdiskpart(device='/dev/sda2', mountpoint='/home', fstype='ext, opts='rw')]
|
|
||||||
>>>
|
|
||||||
>>> psutil.disk_usage('/')
|
|
||||||
sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
|
|
||||||
>>>
|
|
||||||
>>> psutil.disk_io_counters(perdisk=False)
|
|
||||||
sdiskio(read_count=719566, write_count=1082197, read_bytes=18626220032, write_bytes=24081764352, read_time=5023392, write_time=63199568)
|
|
||||||
>>>
|
|
||||||
|
|
||||||
Network
|
|
||||||
=======
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
>>> psutil.net_io_counters(pernic=True)
|
|
||||||
{'eth0': netio(bytes_sent=485291293, bytes_recv=6004858642, packets_sent=3251564, packets_recv=4787798, errin=0, errout=0, dropin=0, dropout=0),
|
|
||||||
'lo': netio(bytes_sent=2838627, bytes_recv=2838627, packets_sent=30567, packets_recv=30567, errin=0, errout=0, dropin=0, dropout=0)}
|
|
||||||
>>>
|
|
||||||
>>> psutil.net_connections()
|
|
||||||
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED', pid=1254),
|
|
||||||
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING', pid=2987),
|
|
||||||
pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED', pid=None),
|
|
||||||
pconn(fd=-1, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT', pid=None)
|
|
||||||
...]
|
|
||||||
>>>
|
|
||||||
>>> psutil.net_if_addrs()
|
|
||||||
{'lo': [snic(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast='127.0.0.1'),
|
|
||||||
snic(family=<AddressFamily.AF_INET6: 10>, address='::1', netmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff', broadcast=None),
|
|
||||||
snic(family=<AddressFamily.AF_LINK: 17>, address='00:00:00:00:00:00', netmask=None, broadcast='00:00:00:00:00:00')],
|
|
||||||
'wlan0': [snic(family=<AddressFamily.AF_INET: 2>, address='192.168.1.3', netmask='255.255.255.0', broadcast='192.168.1.255'),
|
|
||||||
snic(family=<AddressFamily.AF_INET6: 10>, address='fe80::c685:8ff:fe45:641%wlan0', netmask='ffff:ffff:ffff:ffff::', broadcast=None),
|
|
||||||
snic(family=<AddressFamily.AF_LINK: 17>, address='c4:85:08:45:06:41', netmask=None, broadcast='ff:ff:ff:ff:ff:ff')]}
|
|
||||||
>>>
|
|
||||||
>>> psutil.net_if_stats()
|
|
||||||
{'eth0': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_FULL: 2>, speed=100, mtu=1500),
|
|
||||||
'lo': snicstats(isup=True, duplex=<NicDuplex.NIC_DUPLEX_UNKNOWN: 0>, speed=0, mtu=65536)}
|
|
||||||
|
|
||||||
Other system info
|
|
||||||
=================
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
>>> psutil.users()
|
|
||||||
[user(name='giampaolo', terminal='pts/2', host='localhost', started=1340737536.0),
|
|
||||||
user(name='giampaolo', terminal='pts/3', host='localhost', started=1340737792.0)]
|
|
||||||
>>>
|
|
||||||
>>> psutil.boot_time()
|
|
||||||
1365519115.0
|
|
||||||
>>>
|
|
||||||
|
|
||||||
Process management
|
|
||||||
==================
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
>>> import psutil
|
|
||||||
>>> psutil.pids()
|
|
||||||
[1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224,
|
|
||||||
268, 1215, 1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355,
|
|
||||||
2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245,
|
|
||||||
4263, 4282, 4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358,
|
|
||||||
4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446, 5167, 5234, 5235,
|
|
||||||
5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
|
|
||||||
>>>
|
|
||||||
>>> p = psutil.Process(7055)
|
|
||||||
>>> p.name()
|
|
||||||
'python'
|
|
||||||
>>> p.exe()
|
|
||||||
'/usr/bin/python'
|
|
||||||
>>> p.cwd()
|
|
||||||
'/home/giampaolo'
|
|
||||||
>>> p.cmdline()
|
|
||||||
['/usr/bin/python', 'main.py']
|
|
||||||
>>>
|
|
||||||
>>> p.status()
|
|
||||||
'running'
|
|
||||||
>>> p.username()
|
|
||||||
'giampaolo'
|
|
||||||
>>> p.create_time()
|
|
||||||
1267551141.5019531
|
|
||||||
>>> p.terminal()
|
|
||||||
'/dev/pts/0'
|
|
||||||
>>>
|
|
||||||
>>> p.uids()
|
|
||||||
puids(real=1000, effective=1000, saved=1000)
|
|
||||||
>>> p.gids()
|
|
||||||
pgids(real=1000, effective=1000, saved=1000)
|
|
||||||
>>>
|
|
||||||
>>> p.cpu_times()
|
|
||||||
pcputimes(user=1.02, system=0.31)
|
|
||||||
>>> p.cpu_percent(interval=1.0)
|
|
||||||
12.1
|
|
||||||
>>> p.cpu_affinity()
|
|
||||||
[0, 1, 2, 3]
|
|
||||||
>>> p.cpu_affinity([0]) # set
|
|
||||||
>>>
|
|
||||||
>>> p.memory_percent()
|
|
||||||
0.63423
|
|
||||||
>>>
|
|
||||||
>>> p.memory_info()
|
|
||||||
pmem(rss=7471104, vms=68513792)
|
|
||||||
>>> p.memory_info_ex()
|
|
||||||
extmem(rss=9662464, vms=49192960, shared=3612672, text=2564096, lib=0, data=5754880, dirty=0)
|
|
||||||
>>> p.memory_maps()
|
|
||||||
[pmmap_grouped(path='/lib/x86_64-linux-gnu/libutil-2.15.so', rss=16384, anonymous=8192, swap=0),
|
|
||||||
pmmap_grouped(path='/lib/x86_64-linux-gnu/libc-2.15.so', rss=6384, anonymous=15, swap=0),
|
|
||||||
pmmap_grouped(path='/lib/x86_64-linux-gnu/libcrypto.so.1.0.0', rss=34124, anonymous=1245, swap=0),
|
|
||||||
pmmap_grouped(path='[heap]', rss=54653, anonymous=8192, swap=0),
|
|
||||||
pmmap_grouped(path='[stack]', rss=1542, anonymous=166, swap=0),
|
|
||||||
...]
|
|
||||||
>>>
|
|
||||||
>>> p.io_counters()
|
|
||||||
pio(read_count=478001, write_count=59371, read_bytes=700416, write_bytes=69632)
|
|
||||||
>>>
|
|
||||||
>>> p.open_files()
|
|
||||||
[popenfile(path='/home/giampaolo/svn/psutil/somefile', fd=3)]
|
|
||||||
>>>
|
|
||||||
>>> p.connections()
|
|
||||||
[pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 48776), raddr=('93.186.135.91', 80), status='ESTABLISHED'),
|
|
||||||
pconn(fd=117, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 43761), raddr=('72.14.234.100', 80), status='CLOSING'),
|
|
||||||
pconn(fd=119, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 60759), raddr=('72.14.234.104', 80), status='ESTABLISHED'),
|
|
||||||
pconn(fd=123, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=('10.0.0.1', 51314), raddr=('72.14.234.83', 443), status='SYN_SENT')]
|
|
||||||
>>>
|
|
||||||
>>> p.num_threads()
|
|
||||||
4
|
|
||||||
>>> p.num_fds()
|
|
||||||
8
|
|
||||||
>>> p.threads()
|
|
||||||
[pthread(id=5234, user_time=22.5, system_time=9.2891),
|
|
||||||
pthread(id=5235, user_time=0.0, system_time=0.0),
|
|
||||||
pthread(id=5236, user_time=0.0, system_time=0.0),
|
|
||||||
pthread(id=5237, user_time=0.0707, system_time=1.1)]
|
|
||||||
>>>
|
|
||||||
>>> p.num_ctx_switches()
|
|
||||||
pctxsw(voluntary=78, involuntary=19)
|
|
||||||
>>>
|
|
||||||
>>> p.nice()
|
|
||||||
0
|
|
||||||
>>> p.nice(10) # set
|
|
||||||
>>>
|
|
||||||
>>> p.ionice(psutil.IOPRIO_CLASS_IDLE) # IO priority (Win and Linux only)
|
|
||||||
>>> p.ionice()
|
|
||||||
pionice(ioclass=<IOPriority.IOPRIO_CLASS_IDLE: 3>, value=0)
|
|
||||||
>>>
|
|
||||||
>>> p.rlimit(psutil.RLIMIT_NOFILE, (5, 5)) # set resource limits (Linux only)
|
|
||||||
>>> p.rlimit(psutil.RLIMIT_NOFILE)
|
|
||||||
(5, 5)
|
|
||||||
>>>
|
|
||||||
>>> p.suspend()
|
|
||||||
>>> p.resume()
|
|
||||||
>>>
|
|
||||||
>>> p.terminate()
|
|
||||||
>>> p.wait(timeout=3)
|
|
||||||
0
|
|
||||||
>>>
|
|
||||||
>>> psutil.test()
|
|
||||||
USER PID %CPU %MEM VSZ RSS TTY START TIME COMMAND
|
|
||||||
root 1 0.0 0.0 24584 2240 Jun17 00:00 init
|
|
||||||
root 2 0.0 0.0 0 0 Jun17 00:00 kthreadd
|
|
||||||
root 3 0.0 0.0 0 0 Jun17 00:05 ksoftirqd/0
|
|
||||||
...
|
|
||||||
giampaolo 31475 0.0 0.0 20760 3024 /dev/pts/0 Jun19 00:00 python2.4
|
|
||||||
giampaolo 31721 0.0 2.2 773060 181896 00:04 10:30 chrome
|
|
||||||
root 31763 0.0 0.0 0 0 00:05 00:00 kworker/0:1
|
|
||||||
>>>
|
|
||||||
|
|
||||||
Further process APIs
|
|
||||||
====================
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
>>> for p in psutil.process_iter():
|
|
||||||
... print(p)
|
|
||||||
...
|
|
||||||
psutil.Process(pid=1, name='init')
|
|
||||||
psutil.Process(pid=2, name='kthreadd')
|
|
||||||
psutil.Process(pid=3, name='ksoftirqd/0')
|
|
||||||
...
|
|
||||||
>>>
|
|
||||||
>>> def on_terminate(proc):
|
|
||||||
... print("process {} terminated".format(proc))
|
|
||||||
...
|
|
||||||
>>> # waits for multiple processes to terminate
|
|
||||||
>>> gone, alive = psutil.wait_procs(procs_list, 3, callback=on_terminate)
|
|
||||||
>>>
|
|
||||||
|
|
||||||
======
|
|
||||||
Donate
|
|
||||||
======
|
|
||||||
|
|
||||||
A lot of time and effort went into making psutil as it is right now.
|
|
||||||
If you feel psutil is useful to you or your business and want to support its future development please consider donating me (`Giampaolo Rodola' <http://grodola.blogspot.com/p/about.html>`_) some money.
|
|
||||||
I only ask for a small donation, but of course I appreciate any amount.
|
|
||||||
|
|
||||||
.. image:: http://www.paypal.com/en_US/i/btn/x-click-but04.gif
|
|
||||||
:target: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A9ZS7PKKRM3S8
|
|
||||||
:alt: Donate via PayPal
|
|
||||||
|
|
||||||
Don't want to donate money? Then maybe you could `write me a recommendation on Linkedin <http://www.linkedin.com/in/grodola>`_.
|
|
||||||
|
|
||||||
============
|
|
||||||
Mailing list
|
|
||||||
============
|
|
||||||
|
|
||||||
http://groups.google.com/group/psutil/
|
|
||||||
|
|
||||||
========
|
|
||||||
Timeline
|
|
||||||
========
|
|
||||||
|
|
||||||
- 2015-07-15: `psutil-3.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.1.1.tar.gz>`_
|
|
||||||
- 2015-07-15: `psutil-3.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.1.0.tar.gz>`_
|
|
||||||
- 2015-06-18: `psutil-3.0.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.0.1.tar.gz>`_
|
|
||||||
- 2015-06-13: `psutil-3.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-3.0.0.tar.gz>`_
|
|
||||||
- 2015-02-02: `psutil-2.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.2.1.tar.gz>`_
|
|
||||||
- 2015-01-06: `psutil-2.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.2.0.tar.gz>`_
|
|
||||||
- 2014-09-26: `psutil-2.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.3.tar.gz>`_
|
|
||||||
- 2014-09-21: `psutil-2.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.2.tar.gz>`_
|
|
||||||
- 2014-04-30: `psutil-2.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.1.tar.gz>`_
|
|
||||||
- 2014-04-08: `psutil-2.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.1.0.tar.gz>`_
|
|
||||||
- 2014-03-10: `psutil-2.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-2.0.0.tar.gz>`_
|
|
||||||
- 2013-11-25: `psutil-1.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.2.1.tar.gz>`_
|
|
||||||
- 2013-11-20: `psutil-1.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.2.0.tar.gz>`_
|
|
||||||
- 2013-11-07: `psutil-1.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.3.tar.gz>`_
|
|
||||||
- 2013-10-22: `psutil-1.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.2.tar.gz>`_
|
|
||||||
- 2013-10-08: `psutil-1.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.1.tar.gz>`_
|
|
||||||
- 2013-09-28: `psutil-1.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.1.0.tar.gz>`_
|
|
||||||
- 2013-07-12: `psutil-1.0.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.0.1.tar.gz>`_
|
|
||||||
- 2013-07-10: `psutil-1.0.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-1.0.0.tar.gz>`_
|
|
||||||
- 2013-05-03: `psutil-0.7.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.7.1.tar.gz>`_
|
|
||||||
- 2013-04-12: `psutil-0.7.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.7.0.tar.gz>`_
|
|
||||||
- 2012-08-16: `psutil-0.6.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.6.1.tar.gz>`_
|
|
||||||
- 2012-08-13: `psutil-0.6.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.6.0.tar.gz>`_
|
|
||||||
- 2012-06-29: `psutil-0.5.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.5.1.tar.gz>`_
|
|
||||||
- 2012-06-27: `psutil-0.5.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.5.0.tar.gz>`_
|
|
||||||
- 2011-12-14: `psutil-0.4.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.4.1.tar.gz>`_
|
|
||||||
- 2011-10-29: `psutil-0.4.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.4.0.tar.gz>`_
|
|
||||||
- 2011-07-08: `psutil-0.3.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.3.0.tar.gz>`_
|
|
||||||
- 2011-03-20: `psutil-0.2.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.2.1.tar.gz>`_
|
|
||||||
- 2010-11-13: `psutil-0.2.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.2.0.tar.gz>`_
|
|
||||||
- 2010-03-02: `psutil-0.1.3.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.3.tar.gz>`_
|
|
||||||
- 2009-05-06: `psutil-0.1.2.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.2.tar.gz>`_
|
|
||||||
- 2009-03-06: `psutil-0.1.1.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.1.tar.gz>`_
|
|
||||||
- 2009-01-27: `psutil-0.1.0.tar.gz <https://pypi.python.org/packages/source/p/psutil/psutil-0.1.0.tar.gz>`_
|
|
||||||
|
|
||||||
Keywords: ps,top,kill,free,lsof,netstat,nice,tty,ionice,uptime,taskmgr,process,df,iotop,iostat,ifconfig,taskset,who,pidof,pmap,smem,pstree,monitoring,ulimit,prlimit
|
|
||||||
Platform: Platform Independent
|
|
||||||
Classifier: Development Status :: 5 - Production/Stable
|
|
||||||
Classifier: Environment :: Console
|
|
||||||
Classifier: Environment :: Win32 (MS Windows)
|
|
||||||
Classifier: Intended Audience :: Developers
|
|
||||||
Classifier: Intended Audience :: Information Technology
|
|
||||||
Classifier: Intended Audience :: System Administrators
|
|
||||||
Classifier: License :: OSI Approved :: BSD License
|
|
||||||
Classifier: Operating System :: MacOS :: MacOS X
|
|
||||||
Classifier: Operating System :: Microsoft :: Windows :: Windows NT/2000
|
|
||||||
Classifier: Operating System :: Microsoft
|
|
||||||
Classifier: Operating System :: OS Independent
|
|
||||||
Classifier: Operating System :: POSIX :: BSD :: FreeBSD
|
|
||||||
Classifier: Operating System :: POSIX :: Linux
|
|
||||||
Classifier: Operating System :: POSIX :: SunOS/Solaris
|
|
||||||
Classifier: Operating System :: POSIX
|
|
||||||
Classifier: Programming Language :: C
|
|
||||||
Classifier: Programming Language :: Python :: 2
|
|
||||||
Classifier: Programming Language :: Python :: 2.6
|
|
||||||
Classifier: Programming Language :: Python :: 2.7
|
|
||||||
Classifier: Programming Language :: Python :: 3
|
|
||||||
Classifier: Programming Language :: Python :: 3.0
|
|
||||||
Classifier: Programming Language :: Python :: 3.1
|
|
||||||
Classifier: Programming Language :: Python :: 3.2
|
|
||||||
Classifier: Programming Language :: Python :: 3.3
|
|
||||||
Classifier: Programming Language :: Python :: 3.4
|
|
||||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
||||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
||||||
Classifier: Programming Language :: Python
|
|
||||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
||||||
Classifier: Topic :: Software Development :: Libraries
|
|
||||||
Classifier: Topic :: System :: Benchmark
|
|
||||||
Classifier: Topic :: System :: Hardware
|
|
||||||
Classifier: Topic :: System :: Monitoring
|
|
||||||
Classifier: Topic :: System :: Networking :: Monitoring
|
|
||||||
Classifier: Topic :: System :: Networking
|
|
||||||
Classifier: Topic :: System :: Systems Administration
|
|
||||||
Classifier: Topic :: Utilities
|
|
|
@ -1,96 +0,0 @@
|
||||||
.coveragerc
|
|
||||||
.git-pre-commit
|
|
||||||
.gitignore
|
|
||||||
.travis.yml
|
|
||||||
CREDITS
|
|
||||||
HISTORY.rst
|
|
||||||
INSTALL.rst
|
|
||||||
LICENSE
|
|
||||||
MANIFEST.in
|
|
||||||
Makefile
|
|
||||||
README.rst
|
|
||||||
TODO
|
|
||||||
make.bat
|
|
||||||
setup.py
|
|
||||||
tox.ini
|
|
||||||
docs/Makefile
|
|
||||||
docs/README
|
|
||||||
docs/conf.py
|
|
||||||
docs/index.rst
|
|
||||||
docs/make.bat
|
|
||||||
docs/xxx
|
|
||||||
docs/_static/copybutton.js
|
|
||||||
docs/_static/favicon.ico
|
|
||||||
docs/_static/logo.png
|
|
||||||
docs/_static/sidebar.js
|
|
||||||
docs/_template/globaltoc.html
|
|
||||||
docs/_template/indexcontent.html
|
|
||||||
docs/_template/indexsidebar.html
|
|
||||||
docs/_template/page.html
|
|
||||||
docs/_themes/pydoctheme/theme.conf
|
|
||||||
docs/_themes/pydoctheme/static/pydoctheme.css
|
|
||||||
examples/disk_usage.py
|
|
||||||
examples/free.py
|
|
||||||
examples/ifconfig.py
|
|
||||||
examples/iotop.py
|
|
||||||
examples/killall.py
|
|
||||||
examples/meminfo.py
|
|
||||||
examples/netstat.py
|
|
||||||
examples/nettop.py
|
|
||||||
examples/pidof.py
|
|
||||||
examples/pmap.py
|
|
||||||
examples/process_detail.py
|
|
||||||
examples/ps.py
|
|
||||||
examples/pstree.py
|
|
||||||
examples/top.py
|
|
||||||
examples/who.py
|
|
||||||
psutil/__init__.py
|
|
||||||
psutil/_common.py
|
|
||||||
psutil/_compat.py
|
|
||||||
psutil/_psbsd.py
|
|
||||||
psutil/_pslinux.py
|
|
||||||
psutil/_psosx.py
|
|
||||||
psutil/_psposix.py
|
|
||||||
psutil/_pssunos.py
|
|
||||||
psutil/_psutil_bsd.c
|
|
||||||
psutil/_psutil_bsd.h
|
|
||||||
psutil/_psutil_common.c
|
|
||||||
psutil/_psutil_common.h
|
|
||||||
psutil/_psutil_linux.c
|
|
||||||
psutil/_psutil_linux.h
|
|
||||||
psutil/_psutil_osx.c
|
|
||||||
psutil/_psutil_osx.h
|
|
||||||
psutil/_psutil_posix.c
|
|
||||||
psutil/_psutil_posix.h
|
|
||||||
psutil/_psutil_sunos.c
|
|
||||||
psutil/_psutil_sunos.h
|
|
||||||
psutil/_psutil_windows.c
|
|
||||||
psutil/_psutil_windows.h
|
|
||||||
psutil/_pswindows.py
|
|
||||||
psutil.egg-info/PKG-INFO
|
|
||||||
psutil.egg-info/SOURCES.txt
|
|
||||||
psutil.egg-info/dependency_links.txt
|
|
||||||
psutil.egg-info/top_level.txt
|
|
||||||
psutil/arch/bsd/process_info.c
|
|
||||||
psutil/arch/bsd/process_info.h
|
|
||||||
psutil/arch/osx/process_info.c
|
|
||||||
psutil/arch/osx/process_info.h
|
|
||||||
psutil/arch/windows/glpi.h
|
|
||||||
psutil/arch/windows/inet_ntop.c
|
|
||||||
psutil/arch/windows/inet_ntop.h
|
|
||||||
psutil/arch/windows/ntextapi.h
|
|
||||||
psutil/arch/windows/process_handles.c
|
|
||||||
psutil/arch/windows/process_handles.h
|
|
||||||
psutil/arch/windows/process_info.c
|
|
||||||
psutil/arch/windows/process_info.h
|
|
||||||
psutil/arch/windows/security.c
|
|
||||||
psutil/arch/windows/security.h
|
|
||||||
test/README.rst
|
|
||||||
test/_bsd.py
|
|
||||||
test/_linux.py
|
|
||||||
test/_osx.py
|
|
||||||
test/_posix.py
|
|
||||||
test/_sunos.py
|
|
||||||
test/_windows.py
|
|
||||||
test/test_memory_leaks.py
|
|
||||||
test/test_psutil.py
|
|
|
@ -1 +0,0 @@
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
psutil
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
API REFERENCES
|
||||||
|
==============
|
||||||
|
|
||||||
|
- psutil.sensors_battery:
|
||||||
|
https://github.com/Kentzo/Power/
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,36 +1,95 @@
|
||||||
# /usr/bin/env python
|
|
||||||
|
|
||||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||||
# Use of this source code is governed by a BSD-style license that can be
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
# found in the LICENSE file.
|
# found in the LICENSE file.
|
||||||
|
|
||||||
"""Common objects shared by all _ps* modules."""
|
"""Common objects shared by __init__.py and _ps*.py modules."""
|
||||||
|
|
||||||
|
# Note: this module is imported by setup.py so it should not import
|
||||||
|
# psutil or third-party modules.
|
||||||
|
|
||||||
from __future__ import division
|
from __future__ import division
|
||||||
|
|
||||||
|
import contextlib
|
||||||
import errno
|
import errno
|
||||||
import functools
|
import functools
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import stat
|
import stat
|
||||||
import sys
|
import sys
|
||||||
|
import threading
|
||||||
|
import warnings
|
||||||
|
from collections import defaultdict
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from socket import AF_INET, SOCK_STREAM, SOCK_DGRAM
|
from socket import AF_INET
|
||||||
|
from socket import SOCK_DGRAM
|
||||||
|
from socket import SOCK_STREAM
|
||||||
try:
|
try:
|
||||||
import threading
|
from socket import AF_INET6
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import dummy_threading as threading
|
AF_INET6 = None
|
||||||
|
try:
|
||||||
|
from socket import AF_UNIX
|
||||||
|
except ImportError:
|
||||||
|
AF_UNIX = None
|
||||||
|
|
||||||
if sys.version_info >= (3, 4):
|
if sys.version_info >= (3, 4):
|
||||||
import enum
|
import enum
|
||||||
else:
|
else:
|
||||||
enum = None
|
enum = None
|
||||||
|
|
||||||
|
# can't take it from _common.py as this script is imported by setup.py
|
||||||
|
PY3 = sys.version_info[0] == 3
|
||||||
|
|
||||||
# --- constants
|
__all__ = [
|
||||||
|
# constants
|
||||||
|
'FREEBSD', 'BSD', 'LINUX', 'NETBSD', 'OPENBSD', 'OSX', 'POSIX', 'SUNOS',
|
||||||
|
'WINDOWS',
|
||||||
|
'ENCODING', 'ENCODING_ERRS', 'AF_INET6',
|
||||||
|
# connection constants
|
||||||
|
'CONN_CLOSE', 'CONN_CLOSE_WAIT', 'CONN_CLOSING', 'CONN_ESTABLISHED',
|
||||||
|
'CONN_FIN_WAIT1', 'CONN_FIN_WAIT2', 'CONN_LAST_ACK', 'CONN_LISTEN',
|
||||||
|
'CONN_NONE', 'CONN_SYN_RECV', 'CONN_SYN_SENT', 'CONN_TIME_WAIT',
|
||||||
|
# net constants
|
||||||
|
'NIC_DUPLEX_FULL', 'NIC_DUPLEX_HALF', 'NIC_DUPLEX_UNKNOWN',
|
||||||
|
# process status constants
|
||||||
|
'STATUS_DEAD', 'STATUS_DISK_SLEEP', 'STATUS_IDLE', 'STATUS_LOCKED',
|
||||||
|
'STATUS_RUNNING', 'STATUS_SLEEPING', 'STATUS_STOPPED', 'STATUS_SUSPENDED',
|
||||||
|
'STATUS_TRACING_STOP', 'STATUS_WAITING', 'STATUS_WAKE_KILL',
|
||||||
|
'STATUS_WAKING', 'STATUS_ZOMBIE',
|
||||||
|
# named tuples
|
||||||
|
'pconn', 'pcputimes', 'pctxsw', 'pgids', 'pio', 'pionice', 'popenfile',
|
||||||
|
'pthread', 'puids', 'sconn', 'scpustats', 'sdiskio', 'sdiskpart',
|
||||||
|
'sdiskusage', 'snetio', 'snic', 'snicstats', 'sswap', 'suser',
|
||||||
|
# utility functions
|
||||||
|
'conn_tmap', 'deprecated_method', 'isfile_strict', 'memoize',
|
||||||
|
'parse_environ_block', 'path_exists_strict', 'usage_percent',
|
||||||
|
'supports_ipv6', 'sockfam_to_enum', 'socktype_to_enum', "wrap_numbers",
|
||||||
|
]
|
||||||
|
|
||||||
AF_INET6 = getattr(socket, 'AF_INET6', None)
|
|
||||||
AF_UNIX = getattr(socket, 'AF_UNIX', None)
|
|
||||||
|
|
||||||
|
# ===================================================================
|
||||||
|
# --- OS constants
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
|
||||||
|
POSIX = os.name == "posix"
|
||||||
|
WINDOWS = os.name == "nt"
|
||||||
|
LINUX = sys.platform.startswith("linux")
|
||||||
|
OSX = sys.platform.startswith("darwin")
|
||||||
|
FREEBSD = sys.platform.startswith("freebsd")
|
||||||
|
OPENBSD = sys.platform.startswith("openbsd")
|
||||||
|
NETBSD = sys.platform.startswith("netbsd")
|
||||||
|
BSD = FREEBSD or OPENBSD or NETBSD
|
||||||
|
SUNOS = sys.platform.startswith("sunos") or sys.platform.startswith("solaris")
|
||||||
|
AIX = sys.platform.startswith("aix")
|
||||||
|
|
||||||
|
|
||||||
|
# ===================================================================
|
||||||
|
# --- API constants
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
|
||||||
|
# Process.status()
|
||||||
STATUS_RUNNING = "running"
|
STATUS_RUNNING = "running"
|
||||||
STATUS_SLEEPING = "sleeping"
|
STATUS_SLEEPING = "sleeping"
|
||||||
STATUS_DISK_SLEEP = "disk-sleep"
|
STATUS_DISK_SLEEP = "disk-sleep"
|
||||||
|
@ -40,10 +99,12 @@ STATUS_ZOMBIE = "zombie"
|
||||||
STATUS_DEAD = "dead"
|
STATUS_DEAD = "dead"
|
||||||
STATUS_WAKE_KILL = "wake-kill"
|
STATUS_WAKE_KILL = "wake-kill"
|
||||||
STATUS_WAKING = "waking"
|
STATUS_WAKING = "waking"
|
||||||
STATUS_IDLE = "idle" # BSD
|
STATUS_IDLE = "idle" # FreeBSD, OSX
|
||||||
STATUS_LOCKED = "locked" # BSD
|
STATUS_LOCKED = "locked" # FreeBSD
|
||||||
STATUS_WAITING = "waiting" # BSD
|
STATUS_WAITING = "waiting" # FreeBSD
|
||||||
|
STATUS_SUSPENDED = "suspended" # NetBSD
|
||||||
|
|
||||||
|
# Process.connections() and psutil.net_connections()
|
||||||
CONN_ESTABLISHED = "ESTABLISHED"
|
CONN_ESTABLISHED = "ESTABLISHED"
|
||||||
CONN_SYN_SENT = "SYN_SENT"
|
CONN_SYN_SENT = "SYN_SENT"
|
||||||
CONN_SYN_RECV = "SYN_RECV"
|
CONN_SYN_RECV = "SYN_RECV"
|
||||||
|
@ -57,6 +118,7 @@ CONN_LISTEN = "LISTEN"
|
||||||
CONN_CLOSING = "CLOSING"
|
CONN_CLOSING = "CLOSING"
|
||||||
CONN_NONE = "NONE"
|
CONN_NONE = "NONE"
|
||||||
|
|
||||||
|
# net_if_stats()
|
||||||
if enum is None:
|
if enum is None:
|
||||||
NIC_DUPLEX_FULL = 2
|
NIC_DUPLEX_FULL = 2
|
||||||
NIC_DUPLEX_HALF = 1
|
NIC_DUPLEX_HALF = 1
|
||||||
|
@ -69,102 +131,105 @@ else:
|
||||||
|
|
||||||
globals().update(NicDuplex.__members__)
|
globals().update(NicDuplex.__members__)
|
||||||
|
|
||||||
|
# sensors_battery()
|
||||||
|
if enum is None:
|
||||||
|
POWER_TIME_UNKNOWN = -1
|
||||||
|
POWER_TIME_UNLIMITED = -2
|
||||||
|
else:
|
||||||
|
class BatteryTime(enum.IntEnum):
|
||||||
|
POWER_TIME_UNKNOWN = -1
|
||||||
|
POWER_TIME_UNLIMITED = -2
|
||||||
|
|
||||||
# --- functions
|
globals().update(BatteryTime.__members__)
|
||||||
|
|
||||||
def usage_percent(used, total, _round=None):
|
# --- others
|
||||||
"""Calculate percentage usage of 'used' against 'total'."""
|
|
||||||
|
ENCODING = sys.getfilesystemencoding()
|
||||||
|
if not PY3:
|
||||||
|
ENCODING_ERRS = "replace"
|
||||||
|
else:
|
||||||
try:
|
try:
|
||||||
ret = (used / total) * 100
|
ENCODING_ERRS = sys.getfilesystemencodeerrors() # py 3.6
|
||||||
except ZeroDivisionError:
|
except AttributeError:
|
||||||
ret = 0
|
ENCODING_ERRS = "surrogateescape" if POSIX else "replace"
|
||||||
if _round is not None:
|
|
||||||
return round(ret, _round)
|
|
||||||
else:
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
def memoize(fun):
|
# ===================================================================
|
||||||
"""A simple memoize decorator for functions supporting (hashable)
|
# --- namedtuples
|
||||||
positional arguments.
|
# ===================================================================
|
||||||
It also provides a cache_clear() function for clearing the cache:
|
|
||||||
|
|
||||||
>>> @memoize
|
# --- for system functions
|
||||||
... def foo()
|
|
||||||
... return 1
|
|
||||||
...
|
|
||||||
>>> foo()
|
|
||||||
1
|
|
||||||
>>> foo.cache_clear()
|
|
||||||
>>>
|
|
||||||
"""
|
|
||||||
@functools.wraps(fun)
|
|
||||||
def wrapper(*args, **kwargs):
|
|
||||||
key = (args, frozenset(sorted(kwargs.items())))
|
|
||||||
lock.acquire()
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
return cache[key]
|
|
||||||
except KeyError:
|
|
||||||
ret = cache[key] = fun(*args, **kwargs)
|
|
||||||
finally:
|
|
||||||
lock.release()
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def cache_clear():
|
# psutil.swap_memory()
|
||||||
"""Clear cache."""
|
sswap = namedtuple('sswap', ['total', 'used', 'free', 'percent', 'sin',
|
||||||
lock.acquire()
|
'sout'])
|
||||||
try:
|
# psutil.disk_usage()
|
||||||
cache.clear()
|
sdiskusage = namedtuple('sdiskusage', ['total', 'used', 'free', 'percent'])
|
||||||
finally:
|
# psutil.disk_io_counters()
|
||||||
lock.release()
|
sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
|
||||||
|
'read_bytes', 'write_bytes',
|
||||||
|
'read_time', 'write_time'])
|
||||||
|
# psutil.disk_partitions()
|
||||||
|
sdiskpart = namedtuple('sdiskpart', ['device', 'mountpoint', 'fstype', 'opts'])
|
||||||
|
# psutil.net_io_counters()
|
||||||
|
snetio = namedtuple('snetio', ['bytes_sent', 'bytes_recv',
|
||||||
|
'packets_sent', 'packets_recv',
|
||||||
|
'errin', 'errout',
|
||||||
|
'dropin', 'dropout'])
|
||||||
|
# psutil.users()
|
||||||
|
suser = namedtuple('suser', ['name', 'terminal', 'host', 'started', 'pid'])
|
||||||
|
# psutil.net_connections()
|
||||||
|
sconn = namedtuple('sconn', ['fd', 'family', 'type', 'laddr', 'raddr',
|
||||||
|
'status', 'pid'])
|
||||||
|
# psutil.net_if_addrs()
|
||||||
|
snic = namedtuple('snic', ['family', 'address', 'netmask', 'broadcast', 'ptp'])
|
||||||
|
# psutil.net_if_stats()
|
||||||
|
snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu'])
|
||||||
|
# psutil.cpu_stats()
|
||||||
|
scpustats = namedtuple(
|
||||||
|
'scpustats', ['ctx_switches', 'interrupts', 'soft_interrupts', 'syscalls'])
|
||||||
|
# psutil.cpu_freq()
|
||||||
|
scpufreq = namedtuple('scpufreq', ['current', 'min', 'max'])
|
||||||
|
# psutil.sensors_temperatures()
|
||||||
|
shwtemp = namedtuple(
|
||||||
|
'shwtemp', ['label', 'current', 'high', 'critical'])
|
||||||
|
# psutil.sensors_battery()
|
||||||
|
sbattery = namedtuple('sbattery', ['percent', 'secsleft', 'power_plugged'])
|
||||||
|
# psutil.sensors_battery()
|
||||||
|
sfan = namedtuple('sfan', ['label', 'current'])
|
||||||
|
|
||||||
lock = threading.RLock()
|
# --- for Process methods
|
||||||
cache = {}
|
|
||||||
wrapper.cache_clear = cache_clear
|
# psutil.Process.cpu_times()
|
||||||
return wrapper
|
pcputimes = namedtuple('pcputimes',
|
||||||
|
['user', 'system', 'children_user', 'children_system'])
|
||||||
|
# psutil.Process.open_files()
|
||||||
def isfile_strict(path):
|
popenfile = namedtuple('popenfile', ['path', 'fd'])
|
||||||
"""Same as os.path.isfile() but does not swallow EACCES / EPERM
|
# psutil.Process.threads()
|
||||||
exceptions, see:
|
pthread = namedtuple('pthread', ['id', 'user_time', 'system_time'])
|
||||||
http://mail.python.org/pipermail/python-dev/2012-June/120787.html
|
# psutil.Process.uids()
|
||||||
"""
|
puids = namedtuple('puids', ['real', 'effective', 'saved'])
|
||||||
try:
|
# psutil.Process.gids()
|
||||||
st = os.stat(path)
|
pgids = namedtuple('pgids', ['real', 'effective', 'saved'])
|
||||||
except OSError as err:
|
# psutil.Process.io_counters()
|
||||||
if err.errno in (errno.EPERM, errno.EACCES):
|
pio = namedtuple('pio', ['read_count', 'write_count',
|
||||||
raise
|
'read_bytes', 'write_bytes'])
|
||||||
return False
|
# psutil.Process.ionice()
|
||||||
else:
|
pionice = namedtuple('pionice', ['ioclass', 'value'])
|
||||||
return stat.S_ISREG(st.st_mode)
|
# psutil.Process.ctx_switches()
|
||||||
|
pctxsw = namedtuple('pctxsw', ['voluntary', 'involuntary'])
|
||||||
|
# psutil.Process.connections()
|
||||||
def sockfam_to_enum(num):
|
pconn = namedtuple('pconn', ['fd', 'family', 'type', 'laddr', 'raddr',
|
||||||
"""Convert a numeric socket family value to an IntEnum member.
|
'status'])
|
||||||
If it's not a known member, return the numeric value itself.
|
|
||||||
"""
|
# psutil.connections() and psutil.Process.connections()
|
||||||
if enum is None:
|
addr = namedtuple('addr', ['ip', 'port'])
|
||||||
return num
|
|
||||||
try:
|
|
||||||
return socket.AddressFamily(num)
|
|
||||||
except (ValueError, AttributeError):
|
|
||||||
return num
|
|
||||||
|
|
||||||
|
|
||||||
def socktype_to_enum(num):
|
|
||||||
"""Convert a numeric socket type value to an IntEnum member.
|
|
||||||
If it's not a known member, return the numeric value itself.
|
|
||||||
"""
|
|
||||||
if enum is None:
|
|
||||||
return num
|
|
||||||
try:
|
|
||||||
return socket.AddressType(num)
|
|
||||||
except (ValueError, AttributeError):
|
|
||||||
return num
|
|
||||||
|
|
||||||
|
|
||||||
|
# ===================================================================
|
||||||
# --- Process.connections() 'kind' parameter mapping
|
# --- Process.connections() 'kind' parameter mapping
|
||||||
|
# ===================================================================
|
||||||
|
|
||||||
|
|
||||||
conn_tmap = {
|
conn_tmap = {
|
||||||
"all": ([AF_INET, AF_INET6, AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
|
"all": ([AF_INET, AF_INET6, AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
|
||||||
|
@ -188,59 +253,323 @@ if AF_UNIX is not None:
|
||||||
"unix": ([AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
|
"unix": ([AF_UNIX], [SOCK_STREAM, SOCK_DGRAM]),
|
||||||
})
|
})
|
||||||
|
|
||||||
del AF_INET, AF_INET6, AF_UNIX, SOCK_STREAM, SOCK_DGRAM
|
del AF_INET, AF_UNIX, SOCK_STREAM, SOCK_DGRAM
|
||||||
|
|
||||||
|
|
||||||
# --- namedtuples for psutil.* system-related functions
|
# ===================================================================
|
||||||
|
# --- utils
|
||||||
# psutil.swap_memory()
|
# ===================================================================
|
||||||
sswap = namedtuple('sswap', ['total', 'used', 'free', 'percent', 'sin',
|
|
||||||
'sout'])
|
|
||||||
# psutil.disk_usage()
|
|
||||||
sdiskusage = namedtuple('sdiskusage', ['total', 'used', 'free', 'percent'])
|
|
||||||
# psutil.disk_io_counters()
|
|
||||||
sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
|
|
||||||
'read_bytes', 'write_bytes',
|
|
||||||
'read_time', 'write_time'])
|
|
||||||
# psutil.disk_partitions()
|
|
||||||
sdiskpart = namedtuple('sdiskpart', ['device', 'mountpoint', 'fstype', 'opts'])
|
|
||||||
# psutil.net_io_counters()
|
|
||||||
snetio = namedtuple('snetio', ['bytes_sent', 'bytes_recv',
|
|
||||||
'packets_sent', 'packets_recv',
|
|
||||||
'errin', 'errout',
|
|
||||||
'dropin', 'dropout'])
|
|
||||||
# psutil.users()
|
|
||||||
suser = namedtuple('suser', ['name', 'terminal', 'host', 'started'])
|
|
||||||
# psutil.net_connections()
|
|
||||||
sconn = namedtuple('sconn', ['fd', 'family', 'type', 'laddr', 'raddr',
|
|
||||||
'status', 'pid'])
|
|
||||||
# psutil.net_if_addrs()
|
|
||||||
snic = namedtuple('snic', ['family', 'address', 'netmask', 'broadcast'])
|
|
||||||
# psutil.net_if_stats()
|
|
||||||
snicstats = namedtuple('snicstats', ['isup', 'duplex', 'speed', 'mtu'])
|
|
||||||
|
|
||||||
|
|
||||||
# --- namedtuples for psutil.Process methods
|
def usage_percent(used, total, _round=None):
|
||||||
|
"""Calculate percentage usage of 'used' against 'total'."""
|
||||||
|
try:
|
||||||
|
ret = (used / total) * 100
|
||||||
|
except ZeroDivisionError:
|
||||||
|
ret = 0.0 if isinstance(used, float) or isinstance(total, float) else 0
|
||||||
|
if _round is not None:
|
||||||
|
return round(ret, _round)
|
||||||
|
else:
|
||||||
|
return ret
|
||||||
|
|
||||||
# psutil.Process.memory_info()
|
|
||||||
pmem = namedtuple('pmem', ['rss', 'vms'])
|
def memoize(fun):
|
||||||
# psutil.Process.cpu_times()
|
"""A simple memoize decorator for functions supporting (hashable)
|
||||||
pcputimes = namedtuple('pcputimes', ['user', 'system'])
|
positional arguments.
|
||||||
# psutil.Process.open_files()
|
It also provides a cache_clear() function for clearing the cache:
|
||||||
popenfile = namedtuple('popenfile', ['path', 'fd'])
|
|
||||||
# psutil.Process.threads()
|
>>> @memoize
|
||||||
pthread = namedtuple('pthread', ['id', 'user_time', 'system_time'])
|
... def foo()
|
||||||
# psutil.Process.uids()
|
... return 1
|
||||||
puids = namedtuple('puids', ['real', 'effective', 'saved'])
|
...
|
||||||
# psutil.Process.gids()
|
>>> foo()
|
||||||
pgids = namedtuple('pgids', ['real', 'effective', 'saved'])
|
1
|
||||||
# psutil.Process.io_counters()
|
>>> foo.cache_clear()
|
||||||
pio = namedtuple('pio', ['read_count', 'write_count',
|
>>>
|
||||||
'read_bytes', 'write_bytes'])
|
"""
|
||||||
# psutil.Process.ionice()
|
@functools.wraps(fun)
|
||||||
pionice = namedtuple('pionice', ['ioclass', 'value'])
|
def wrapper(*args, **kwargs):
|
||||||
# psutil.Process.ctx_switches()
|
key = (args, frozenset(sorted(kwargs.items())))
|
||||||
pctxsw = namedtuple('pctxsw', ['voluntary', 'involuntary'])
|
try:
|
||||||
# psutil.Process.connections()
|
return cache[key]
|
||||||
pconn = namedtuple('pconn', ['fd', 'family', 'type', 'laddr', 'raddr',
|
except KeyError:
|
||||||
'status'])
|
ret = cache[key] = fun(*args, **kwargs)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def cache_clear():
|
||||||
|
"""Clear cache."""
|
||||||
|
cache.clear()
|
||||||
|
|
||||||
|
cache = {}
|
||||||
|
wrapper.cache_clear = cache_clear
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def memoize_when_activated(fun):
|
||||||
|
"""A memoize decorator which is disabled by default. It can be
|
||||||
|
activated and deactivated on request.
|
||||||
|
For efficiency reasons it can be used only against class methods
|
||||||
|
accepting no arguments.
|
||||||
|
|
||||||
|
>>> class Foo:
|
||||||
|
... @memoize
|
||||||
|
... def foo()
|
||||||
|
... print(1)
|
||||||
|
...
|
||||||
|
>>> f = Foo()
|
||||||
|
>>> # deactivated (default)
|
||||||
|
>>> foo()
|
||||||
|
1
|
||||||
|
>>> foo()
|
||||||
|
1
|
||||||
|
>>>
|
||||||
|
>>> # activated
|
||||||
|
>>> foo.cache_activate()
|
||||||
|
>>> foo()
|
||||||
|
1
|
||||||
|
>>> foo()
|
||||||
|
>>> foo()
|
||||||
|
>>>
|
||||||
|
"""
|
||||||
|
@functools.wraps(fun)
|
||||||
|
def wrapper(self):
|
||||||
|
if not wrapper.cache_activated:
|
||||||
|
return fun(self)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
ret = cache[fun]
|
||||||
|
except KeyError:
|
||||||
|
ret = cache[fun] = fun(self)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def cache_activate():
|
||||||
|
"""Activate cache."""
|
||||||
|
wrapper.cache_activated = True
|
||||||
|
|
||||||
|
def cache_deactivate():
|
||||||
|
"""Deactivate and clear cache."""
|
||||||
|
wrapper.cache_activated = False
|
||||||
|
cache.clear()
|
||||||
|
|
||||||
|
cache = {}
|
||||||
|
wrapper.cache_activated = False
|
||||||
|
wrapper.cache_activate = cache_activate
|
||||||
|
wrapper.cache_deactivate = cache_deactivate
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
def isfile_strict(path):
|
||||||
|
"""Same as os.path.isfile() but does not swallow EACCES / EPERM
|
||||||
|
exceptions, see:
|
||||||
|
http://mail.python.org/pipermail/python-dev/2012-June/120787.html
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
st = os.stat(path)
|
||||||
|
except OSError as err:
|
||||||
|
if err.errno in (errno.EPERM, errno.EACCES):
|
||||||
|
raise
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return stat.S_ISREG(st.st_mode)
|
||||||
|
|
||||||
|
|
||||||
|
def path_exists_strict(path):
|
||||||
|
"""Same as os.path.exists() but does not swallow EACCES / EPERM
|
||||||
|
exceptions, see:
|
||||||
|
http://mail.python.org/pipermail/python-dev/2012-June/120787.html
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
os.stat(path)
|
||||||
|
except OSError as err:
|
||||||
|
if err.errno in (errno.EPERM, errno.EACCES):
|
||||||
|
raise
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
def supports_ipv6():
|
||||||
|
"""Return True if IPv6 is supported on this platform."""
|
||||||
|
if not socket.has_ipv6 or AF_INET6 is None:
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
sock = socket.socket(AF_INET6, socket.SOCK_STREAM)
|
||||||
|
with contextlib.closing(sock):
|
||||||
|
sock.bind(("::1", 0))
|
||||||
|
return True
|
||||||
|
except socket.error:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def parse_environ_block(data):
|
||||||
|
"""Parse a C environ block of environment variables into a dictionary."""
|
||||||
|
# The block is usually raw data from the target process. It might contain
|
||||||
|
# trailing garbage and lines that do not look like assignments.
|
||||||
|
ret = {}
|
||||||
|
pos = 0
|
||||||
|
|
||||||
|
# localize global variable to speed up access.
|
||||||
|
WINDOWS_ = WINDOWS
|
||||||
|
while True:
|
||||||
|
next_pos = data.find("\0", pos)
|
||||||
|
# nul byte at the beginning or double nul byte means finish
|
||||||
|
if next_pos <= pos:
|
||||||
|
break
|
||||||
|
# there might not be an equals sign
|
||||||
|
equal_pos = data.find("=", pos, next_pos)
|
||||||
|
if equal_pos > pos:
|
||||||
|
key = data[pos:equal_pos]
|
||||||
|
value = data[equal_pos + 1:next_pos]
|
||||||
|
# Windows expects environment variables to be uppercase only
|
||||||
|
if WINDOWS_:
|
||||||
|
key = key.upper()
|
||||||
|
ret[key] = value
|
||||||
|
pos = next_pos + 1
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def sockfam_to_enum(num):
|
||||||
|
"""Convert a numeric socket family value to an IntEnum member.
|
||||||
|
If it's not a known member, return the numeric value itself.
|
||||||
|
"""
|
||||||
|
if enum is None:
|
||||||
|
return num
|
||||||
|
else: # pragma: no cover
|
||||||
|
try:
|
||||||
|
return socket.AddressFamily(num)
|
||||||
|
except (ValueError, AttributeError):
|
||||||
|
return num
|
||||||
|
|
||||||
|
|
||||||
|
def socktype_to_enum(num):
|
||||||
|
"""Convert a numeric socket type value to an IntEnum member.
|
||||||
|
If it's not a known member, return the numeric value itself.
|
||||||
|
"""
|
||||||
|
if enum is None:
|
||||||
|
return num
|
||||||
|
else: # pragma: no cover
|
||||||
|
try:
|
||||||
|
return socket.AddressType(num)
|
||||||
|
except (ValueError, AttributeError):
|
||||||
|
return num
|
||||||
|
|
||||||
|
|
||||||
|
def deprecated_method(replacement):
|
||||||
|
"""A decorator which can be used to mark a method as deprecated
|
||||||
|
'replcement' is the method name which will be called instead.
|
||||||
|
"""
|
||||||
|
def outer(fun):
|
||||||
|
msg = "%s() is deprecated and will be removed; use %s() instead" % (
|
||||||
|
fun.__name__, replacement)
|
||||||
|
if fun.__doc__ is None:
|
||||||
|
fun.__doc__ = msg
|
||||||
|
|
||||||
|
@functools.wraps(fun)
|
||||||
|
def inner(self, *args, **kwargs):
|
||||||
|
warnings.warn(msg, category=FutureWarning, stacklevel=2)
|
||||||
|
return getattr(self, replacement)(*args, **kwargs)
|
||||||
|
return inner
|
||||||
|
return outer
|
||||||
|
|
||||||
|
|
||||||
|
class _WrapNumbers:
|
||||||
|
"""Watches numbers so that they don't overflow and wrap
|
||||||
|
(reset to zero).
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.lock = threading.Lock()
|
||||||
|
self.cache = {}
|
||||||
|
self.reminders = {}
|
||||||
|
self.reminder_keys = {}
|
||||||
|
|
||||||
|
def _add_dict(self, input_dict, name):
|
||||||
|
assert name not in self.cache
|
||||||
|
assert name not in self.reminders
|
||||||
|
assert name not in self.reminder_keys
|
||||||
|
self.cache[name] = input_dict
|
||||||
|
self.reminders[name] = defaultdict(int)
|
||||||
|
self.reminder_keys[name] = defaultdict(set)
|
||||||
|
|
||||||
|
def _remove_dead_reminders(self, input_dict, name):
|
||||||
|
"""In case the number of keys changed between calls (e.g. a
|
||||||
|
disk disappears) this removes the entry from self.reminders.
|
||||||
|
"""
|
||||||
|
old_dict = self.cache[name]
|
||||||
|
gone_keys = set(old_dict.keys()) - set(input_dict.keys())
|
||||||
|
for gone_key in gone_keys:
|
||||||
|
for remkey in self.reminder_keys[name][gone_key]:
|
||||||
|
del self.reminders[name][remkey]
|
||||||
|
del self.reminder_keys[name][gone_key]
|
||||||
|
|
||||||
|
def run(self, input_dict, name):
|
||||||
|
"""Cache dict and sum numbers which overflow and wrap.
|
||||||
|
Return an updated copy of `input_dict`
|
||||||
|
"""
|
||||||
|
if name not in self.cache:
|
||||||
|
# This was the first call.
|
||||||
|
self._add_dict(input_dict, name)
|
||||||
|
return input_dict
|
||||||
|
|
||||||
|
self._remove_dead_reminders(input_dict, name)
|
||||||
|
|
||||||
|
old_dict = self.cache[name]
|
||||||
|
new_dict = {}
|
||||||
|
for key in input_dict.keys():
|
||||||
|
input_tuple = input_dict[key]
|
||||||
|
try:
|
||||||
|
old_tuple = old_dict[key]
|
||||||
|
except KeyError:
|
||||||
|
# The input dict has a new key (e.g. a new disk or NIC)
|
||||||
|
# which didn't exist in the previous call.
|
||||||
|
new_dict[key] = input_tuple
|
||||||
|
continue
|
||||||
|
|
||||||
|
bits = []
|
||||||
|
for i in range(len(input_tuple)):
|
||||||
|
input_value = input_tuple[i]
|
||||||
|
old_value = old_tuple[i]
|
||||||
|
remkey = (key, i)
|
||||||
|
if input_value < old_value:
|
||||||
|
# it wrapped!
|
||||||
|
self.reminders[name][remkey] += old_value
|
||||||
|
self.reminder_keys[name][key].add(remkey)
|
||||||
|
bits.append(input_value + self.reminders[name][remkey])
|
||||||
|
|
||||||
|
new_dict[key] = tuple(bits)
|
||||||
|
|
||||||
|
self.cache[name] = input_dict
|
||||||
|
return new_dict
|
||||||
|
|
||||||
|
def cache_clear(self, name=None):
|
||||||
|
"""Clear the internal cache, optionally only for function 'name'."""
|
||||||
|
with self.lock:
|
||||||
|
if name is None:
|
||||||
|
self.cache.clear()
|
||||||
|
self.reminders.clear()
|
||||||
|
self.reminder_keys.clear()
|
||||||
|
else:
|
||||||
|
self.cache.pop(name, None)
|
||||||
|
self.reminders.pop(name, None)
|
||||||
|
self.reminder_keys.pop(name, None)
|
||||||
|
|
||||||
|
def cache_info(self):
|
||||||
|
"""Return internal cache dicts as a tuple of 3 elements."""
|
||||||
|
with self.lock:
|
||||||
|
return (self.cache, self.reminders, self.reminder_keys)
|
||||||
|
|
||||||
|
|
||||||
|
def wrap_numbers(input_dict, name):
|
||||||
|
"""Given an `input_dict` and a function `name`, adjust the numbers
|
||||||
|
which "wrap" (restart from zero) across different calls by adding
|
||||||
|
"old value" to "new value" and return an updated dict.
|
||||||
|
"""
|
||||||
|
with _wn.lock:
|
||||||
|
return _wn.run(input_dict, name)
|
||||||
|
|
||||||
|
|
||||||
|
_wn = _WrapNumbers()
|
||||||
|
wrap_numbers.cache_clear = _wn.cache_clear
|
||||||
|
wrap_numbers.cache_info = _wn.cache_info
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||||
# Use of this source code is governed by a BSD-style license that can be
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
# found in the LICENSE file.
|
# found in the LICENSE file.
|
||||||
|
@ -8,9 +6,11 @@
|
||||||
|
|
||||||
import collections
|
import collections
|
||||||
import functools
|
import functools
|
||||||
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
__all__ = ["PY3", "long", "xrange", "unicode", "callable", "lru_cache"]
|
__all__ = ["PY3", "long", "xrange", "unicode", "basestring", "u", "b",
|
||||||
|
"callable", "lru_cache", "which"]
|
||||||
|
|
||||||
PY3 = sys.version_info[0] == 3
|
PY3 = sys.version_info[0] == 3
|
||||||
|
|
||||||
|
@ -18,17 +18,25 @@ if PY3:
|
||||||
long = int
|
long = int
|
||||||
xrange = range
|
xrange = range
|
||||||
unicode = str
|
unicode = str
|
||||||
|
basestring = str
|
||||||
|
|
||||||
def u(s):
|
def u(s):
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
def b(s):
|
||||||
|
return s.encode("latin-1")
|
||||||
else:
|
else:
|
||||||
long = long
|
long = long
|
||||||
xrange = xrange
|
xrange = xrange
|
||||||
unicode = unicode
|
unicode = unicode
|
||||||
|
basestring = basestring
|
||||||
|
|
||||||
def u(s):
|
def u(s):
|
||||||
return unicode(s, "unicode_escape")
|
return unicode(s, "unicode_escape")
|
||||||
|
|
||||||
|
def b(s):
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
# removed in 3.0, reintroduced in 3.2
|
# removed in 3.0, reintroduced in 3.2
|
||||||
try:
|
try:
|
||||||
|
@ -187,3 +195,55 @@ except ImportError:
|
||||||
return functools.update_wrapper(wrapper, user_function)
|
return functools.update_wrapper(wrapper, user_function)
|
||||||
|
|
||||||
return decorating_function
|
return decorating_function
|
||||||
|
|
||||||
|
|
||||||
|
# python 3.3
|
||||||
|
try:
|
||||||
|
from shutil import which
|
||||||
|
except ImportError:
|
||||||
|
def which(cmd, mode=os.F_OK | os.X_OK, path=None):
|
||||||
|
"""Given a command, mode, and a PATH string, return the path which
|
||||||
|
conforms to the given mode on the PATH, or None if there is no such
|
||||||
|
file.
|
||||||
|
|
||||||
|
`mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
|
||||||
|
of os.environ.get("PATH"), or can be overridden with a custom search
|
||||||
|
path.
|
||||||
|
"""
|
||||||
|
def _access_check(fn, mode):
|
||||||
|
return (os.path.exists(fn) and os.access(fn, mode) and
|
||||||
|
not os.path.isdir(fn))
|
||||||
|
|
||||||
|
if os.path.dirname(cmd):
|
||||||
|
if _access_check(cmd, mode):
|
||||||
|
return cmd
|
||||||
|
return None
|
||||||
|
|
||||||
|
if path is None:
|
||||||
|
path = os.environ.get("PATH", os.defpath)
|
||||||
|
if not path:
|
||||||
|
return None
|
||||||
|
path = path.split(os.pathsep)
|
||||||
|
|
||||||
|
if sys.platform == "win32":
|
||||||
|
if os.curdir not in path:
|
||||||
|
path.insert(0, os.curdir)
|
||||||
|
|
||||||
|
pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
|
||||||
|
if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
|
||||||
|
files = [cmd]
|
||||||
|
else:
|
||||||
|
files = [cmd + ext for ext in pathext]
|
||||||
|
else:
|
||||||
|
files = [cmd]
|
||||||
|
|
||||||
|
seen = set()
|
||||||
|
for dir in path:
|
||||||
|
normdir = os.path.normcase(dir)
|
||||||
|
if normdir not in seen:
|
||||||
|
seen.add(normdir)
|
||||||
|
for thefile in files:
|
||||||
|
name = os.path.join(dir, thefile)
|
||||||
|
if _access_check(name, mode):
|
||||||
|
return name
|
||||||
|
return None
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
|
# found in the LICENSE file.
|
||||||
|
|
||||||
|
|
||||||
|
class Error(Exception):
|
||||||
|
"""Base exception class. All other psutil exceptions inherit
|
||||||
|
from this one.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, msg=""):
|
||||||
|
Exception.__init__(self, msg)
|
||||||
|
self.msg = msg
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
ret = "psutil.%s %s" % (self.__class__.__name__, self.msg)
|
||||||
|
return ret.strip()
|
||||||
|
|
||||||
|
__str__ = __repr__
|
||||||
|
|
||||||
|
|
||||||
|
class NoSuchProcess(Error):
|
||||||
|
"""Exception raised when a process with a certain PID doesn't
|
||||||
|
or no longer exists.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, pid, name=None, msg=None):
|
||||||
|
Error.__init__(self, msg)
|
||||||
|
self.pid = pid
|
||||||
|
self.name = name
|
||||||
|
self.msg = msg
|
||||||
|
if msg is None:
|
||||||
|
if name:
|
||||||
|
details = "(pid=%s, name=%s)" % (self.pid, repr(self.name))
|
||||||
|
else:
|
||||||
|
details = "(pid=%s)" % self.pid
|
||||||
|
self.msg = "process no longer exists " + details
|
||||||
|
|
||||||
|
|
||||||
|
class ZombieProcess(NoSuchProcess):
|
||||||
|
"""Exception raised when querying a zombie process. This is
|
||||||
|
raised on OSX, BSD and Solaris only, and not always: depending
|
||||||
|
on the query the OS may be able to succeed anyway.
|
||||||
|
On Linux all zombie processes are querable (hence this is never
|
||||||
|
raised). Windows doesn't have zombie processes.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, pid, name=None, ppid=None, msg=None):
|
||||||
|
NoSuchProcess.__init__(self, msg)
|
||||||
|
self.pid = pid
|
||||||
|
self.ppid = ppid
|
||||||
|
self.name = name
|
||||||
|
self.msg = msg
|
||||||
|
if msg is None:
|
||||||
|
args = ["pid=%s" % pid]
|
||||||
|
if name:
|
||||||
|
args.append("name=%s" % repr(self.name))
|
||||||
|
if ppid:
|
||||||
|
args.append("ppid=%s" % self.ppid)
|
||||||
|
details = "(%s)" % ", ".join(args)
|
||||||
|
self.msg = "process still exists but it's a zombie " + details
|
||||||
|
|
||||||
|
|
||||||
|
class AccessDenied(Error):
|
||||||
|
"""Exception raised when permission to perform an action is denied."""
|
||||||
|
|
||||||
|
def __init__(self, pid=None, name=None, msg=None):
|
||||||
|
Error.__init__(self, msg)
|
||||||
|
self.pid = pid
|
||||||
|
self.name = name
|
||||||
|
self.msg = msg
|
||||||
|
if msg is None:
|
||||||
|
if (pid is not None) and (name is not None):
|
||||||
|
self.msg = "(pid=%s, name=%s)" % (pid, repr(name))
|
||||||
|
elif (pid is not None):
|
||||||
|
self.msg = "(pid=%s)" % self.pid
|
||||||
|
else:
|
||||||
|
self.msg = ""
|
||||||
|
|
||||||
|
|
||||||
|
class TimeoutExpired(Error):
|
||||||
|
"""Raised on Process.wait(timeout) if timeout expires and process
|
||||||
|
is still alive.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, seconds, pid=None, name=None):
|
||||||
|
Error.__init__(self, "timeout after %s seconds" % seconds)
|
||||||
|
self.seconds = seconds
|
||||||
|
self.pid = pid
|
||||||
|
self.name = name
|
||||||
|
if (pid is not None) and (name is not None):
|
||||||
|
self.msg += " (pid=%s, name=%s)" % (pid, repr(name))
|
||||||
|
elif (pid is not None):
|
||||||
|
self.msg += " (pid=%s)" % self.pid
|
|
@ -0,0 +1,573 @@
|
||||||
|
# Copyright (c) 2009, Giampaolo Rodola'
|
||||||
|
# Copyright (c) 2017, Arnon Yaari
|
||||||
|
# All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
|
# found in the LICENSE file.
|
||||||
|
|
||||||
|
"""AIX platform implementation."""
|
||||||
|
|
||||||
|
import errno
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from collections import namedtuple
|
||||||
|
from socket import AF_INET
|
||||||
|
|
||||||
|
from . import _common
|
||||||
|
from . import _psposix
|
||||||
|
from . import _psutil_aix as cext
|
||||||
|
from . import _psutil_posix as cext_posix
|
||||||
|
from ._common import AF_INET6
|
||||||
|
from ._common import memoize_when_activated
|
||||||
|
from ._common import NIC_DUPLEX_FULL
|
||||||
|
from ._common import NIC_DUPLEX_HALF
|
||||||
|
from ._common import NIC_DUPLEX_UNKNOWN
|
||||||
|
from ._common import sockfam_to_enum
|
||||||
|
from ._common import socktype_to_enum
|
||||||
|
from ._common import usage_percent
|
||||||
|
from ._compat import PY3
|
||||||
|
from ._exceptions import AccessDenied
|
||||||
|
from ._exceptions import NoSuchProcess
|
||||||
|
from ._exceptions import ZombieProcess
|
||||||
|
|
||||||
|
|
||||||
|
__extra__all__ = ["PROCFS_PATH"]
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- globals
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
HAS_THREADS = hasattr(cext, "proc_threads")
|
||||||
|
|
||||||
|
PAGE_SIZE = os.sysconf('SC_PAGE_SIZE')
|
||||||
|
AF_LINK = cext_posix.AF_LINK
|
||||||
|
|
||||||
|
PROC_STATUSES = {
|
||||||
|
cext.SIDL: _common.STATUS_IDLE,
|
||||||
|
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||||
|
cext.SACTIVE: _common.STATUS_RUNNING,
|
||||||
|
cext.SSWAP: _common.STATUS_RUNNING, # TODO what status is this?
|
||||||
|
cext.SSTOP: _common.STATUS_STOPPED,
|
||||||
|
}
|
||||||
|
|
||||||
|
TCP_STATUSES = {
|
||||||
|
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
||||||
|
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
|
||||||
|
cext.TCPS_SYN_RCVD: _common.CONN_SYN_RECV,
|
||||||
|
cext.TCPS_FIN_WAIT_1: _common.CONN_FIN_WAIT1,
|
||||||
|
cext.TCPS_FIN_WAIT_2: _common.CONN_FIN_WAIT2,
|
||||||
|
cext.TCPS_TIME_WAIT: _common.CONN_TIME_WAIT,
|
||||||
|
cext.TCPS_CLOSED: _common.CONN_CLOSE,
|
||||||
|
cext.TCPS_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
|
||||||
|
cext.TCPS_LAST_ACK: _common.CONN_LAST_ACK,
|
||||||
|
cext.TCPS_LISTEN: _common.CONN_LISTEN,
|
||||||
|
cext.TCPS_CLOSING: _common.CONN_CLOSING,
|
||||||
|
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
|
||||||
|
}
|
||||||
|
|
||||||
|
proc_info_map = dict(
|
||||||
|
ppid=0,
|
||||||
|
rss=1,
|
||||||
|
vms=2,
|
||||||
|
create_time=3,
|
||||||
|
nice=4,
|
||||||
|
num_threads=5,
|
||||||
|
status=6,
|
||||||
|
ttynr=7)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- named tuples
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
# psutil.Process.memory_info()
|
||||||
|
pmem = namedtuple('pmem', ['rss', 'vms'])
|
||||||
|
# psutil.Process.memory_full_info()
|
||||||
|
pfullmem = pmem
|
||||||
|
# psutil.Process.cpu_times()
|
||||||
|
scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait'])
|
||||||
|
# psutil.virtual_memory()
|
||||||
|
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
|
||||||
|
# psutil.Process.memory_maps(grouped=True)
|
||||||
|
pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss', 'anon', 'locked'])
|
||||||
|
# psutil.Process.memory_maps(grouped=False)
|
||||||
|
pmmap_ext = namedtuple(
|
||||||
|
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- utils
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def get_procfs_path():
|
||||||
|
"""Return updated psutil.PROCFS_PATH constant."""
|
||||||
|
return sys.modules['psutil'].PROCFS_PATH
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- memory
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def virtual_memory():
|
||||||
|
total, avail, free, pinned, inuse = cext.virtual_mem()
|
||||||
|
percent = usage_percent((total - avail), total, _round=1)
|
||||||
|
return svmem(total, avail, percent, inuse, free)
|
||||||
|
|
||||||
|
|
||||||
|
def swap_memory():
|
||||||
|
"""Swap system memory as a (total, used, free, sin, sout) tuple."""
|
||||||
|
total, free, sin, sout = cext.swap_mem()
|
||||||
|
used = total - free
|
||||||
|
percent = usage_percent(used, total, _round=1)
|
||||||
|
return _common.sswap(total, used, free, percent, sin, sout)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- CPU
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def cpu_times():
|
||||||
|
"""Return system-wide CPU times as a named tuple"""
|
||||||
|
ret = cext.per_cpu_times()
|
||||||
|
return scputimes(*[sum(x) for x in zip(*ret)])
|
||||||
|
|
||||||
|
|
||||||
|
def per_cpu_times():
|
||||||
|
"""Return system per-CPU times as a list of named tuples"""
|
||||||
|
ret = cext.per_cpu_times()
|
||||||
|
return [scputimes(*x) for x in ret]
|
||||||
|
|
||||||
|
|
||||||
|
def cpu_count_logical():
|
||||||
|
"""Return the number of logical CPUs in the system."""
|
||||||
|
try:
|
||||||
|
return os.sysconf("SC_NPROCESSORS_ONLN")
|
||||||
|
except ValueError:
|
||||||
|
# mimic os.cpu_count() behavior
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def cpu_count_physical():
|
||||||
|
cmd = "lsdev -Cc processor"
|
||||||
|
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE)
|
||||||
|
stdout, stderr = p.communicate()
|
||||||
|
if PY3:
|
||||||
|
stdout, stderr = [x.decode(sys.stdout.encoding)
|
||||||
|
for x in (stdout, stderr)]
|
||||||
|
if p.returncode != 0:
|
||||||
|
raise RuntimeError("%r command error\n%s" % (cmd, stderr))
|
||||||
|
processors = stdout.strip().splitlines()
|
||||||
|
return len(processors) or None
|
||||||
|
|
||||||
|
|
||||||
|
def cpu_stats():
|
||||||
|
"""Return various CPU stats as a named tuple."""
|
||||||
|
ctx_switches, interrupts, soft_interrupts, syscalls = cext.cpu_stats()
|
||||||
|
return _common.scpustats(
|
||||||
|
ctx_switches, interrupts, soft_interrupts, syscalls)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- disks
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
disk_io_counters = cext.disk_io_counters
|
||||||
|
disk_usage = _psposix.disk_usage
|
||||||
|
|
||||||
|
|
||||||
|
def disk_partitions(all=False):
|
||||||
|
"""Return system disk partitions."""
|
||||||
|
# TODO - the filtering logic should be better checked so that
|
||||||
|
# it tries to reflect 'df' as much as possible
|
||||||
|
retlist = []
|
||||||
|
partitions = cext.disk_partitions()
|
||||||
|
for partition in partitions:
|
||||||
|
device, mountpoint, fstype, opts = partition
|
||||||
|
if device == 'none':
|
||||||
|
device = ''
|
||||||
|
if not all:
|
||||||
|
# Differently from, say, Linux, we don't have a list of
|
||||||
|
# common fs types so the best we can do, AFAIK, is to
|
||||||
|
# filter by filesystem having a total size > 0.
|
||||||
|
if not disk_usage(mountpoint).total:
|
||||||
|
continue
|
||||||
|
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
|
||||||
|
retlist.append(ntuple)
|
||||||
|
return retlist
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- network
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
net_if_addrs = cext_posix.net_if_addrs
|
||||||
|
net_io_counters = cext.net_io_counters
|
||||||
|
|
||||||
|
|
||||||
|
def net_connections(kind, _pid=-1):
|
||||||
|
"""Return socket connections. If pid == -1 return system-wide
|
||||||
|
connections (as opposed to connections opened by one process only).
|
||||||
|
"""
|
||||||
|
cmap = _common.conn_tmap
|
||||||
|
if kind not in cmap:
|
||||||
|
raise ValueError("invalid %r kind argument; choose between %s"
|
||||||
|
% (kind, ', '.join([repr(x) for x in cmap])))
|
||||||
|
families, types = _common.conn_tmap[kind]
|
||||||
|
rawlist = cext.net_connections(_pid)
|
||||||
|
ret = set()
|
||||||
|
for item in rawlist:
|
||||||
|
fd, fam, type_, laddr, raddr, status, pid = item
|
||||||
|
if fam not in families:
|
||||||
|
continue
|
||||||
|
if type_ not in types:
|
||||||
|
continue
|
||||||
|
status = TCP_STATUSES[status]
|
||||||
|
if fam in (AF_INET, AF_INET6):
|
||||||
|
if laddr:
|
||||||
|
laddr = _common.addr(*laddr)
|
||||||
|
if raddr:
|
||||||
|
raddr = _common.addr(*raddr)
|
||||||
|
fam = sockfam_to_enum(fam)
|
||||||
|
type_ = socktype_to_enum(type_)
|
||||||
|
if _pid == -1:
|
||||||
|
nt = _common.sconn(fd, fam, type_, laddr, raddr, status, pid)
|
||||||
|
else:
|
||||||
|
nt = _common.pconn(fd, fam, type_, laddr, raddr, status)
|
||||||
|
ret.add(nt)
|
||||||
|
return list(ret)
|
||||||
|
|
||||||
|
|
||||||
|
def net_if_stats():
|
||||||
|
"""Get NIC stats (isup, duplex, speed, mtu)."""
|
||||||
|
duplex_map = {"Full": NIC_DUPLEX_FULL,
|
||||||
|
"Half": NIC_DUPLEX_HALF}
|
||||||
|
names = set([x[0] for x in net_if_addrs()])
|
||||||
|
ret = {}
|
||||||
|
for name in names:
|
||||||
|
isup, mtu = cext.net_if_stats(name)
|
||||||
|
|
||||||
|
# try to get speed and duplex
|
||||||
|
# TODO: rewrite this in C (entstat forks, so use truss -f to follow.
|
||||||
|
# looks like it is using an undocumented ioctl?)
|
||||||
|
duplex = ""
|
||||||
|
speed = 0
|
||||||
|
p = subprocess.Popen(["/usr/bin/entstat", "-d", name],
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
stdout, stderr = p.communicate()
|
||||||
|
if PY3:
|
||||||
|
stdout, stderr = [x.decode(sys.stdout.encoding)
|
||||||
|
for x in (stdout, stderr)]
|
||||||
|
if p.returncode == 0:
|
||||||
|
re_result = re.search("Running: (\d+) Mbps.*?(\w+) Duplex", stdout)
|
||||||
|
if re_result is not None:
|
||||||
|
speed = int(re_result.group(1))
|
||||||
|
duplex = re_result.group(2)
|
||||||
|
|
||||||
|
duplex = duplex_map.get(duplex, NIC_DUPLEX_UNKNOWN)
|
||||||
|
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- other system functions
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def boot_time():
|
||||||
|
"""The system boot time expressed in seconds since the epoch."""
|
||||||
|
return cext.boot_time()
|
||||||
|
|
||||||
|
|
||||||
|
def users():
|
||||||
|
"""Return currently connected users as a list of namedtuples."""
|
||||||
|
retlist = []
|
||||||
|
rawlist = cext.users()
|
||||||
|
localhost = (':0.0', ':0')
|
||||||
|
for item in rawlist:
|
||||||
|
user, tty, hostname, tstamp, user_process, pid = item
|
||||||
|
# note: the underlying C function includes entries about
|
||||||
|
# system boot, run level and others. We might want
|
||||||
|
# to use them in the future.
|
||||||
|
if not user_process:
|
||||||
|
continue
|
||||||
|
if hostname in localhost:
|
||||||
|
hostname = 'localhost'
|
||||||
|
nt = _common.suser(user, tty, hostname, tstamp, pid)
|
||||||
|
retlist.append(nt)
|
||||||
|
return retlist
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- processes
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def pids():
|
||||||
|
"""Returns a list of PIDs currently running on the system."""
|
||||||
|
return [int(x) for x in os.listdir(get_procfs_path()) if x.isdigit()]
|
||||||
|
|
||||||
|
|
||||||
|
def pid_exists(pid):
|
||||||
|
"""Check for the existence of a unix pid."""
|
||||||
|
return os.path.exists(os.path.join(get_procfs_path(), str(pid), "psinfo"))
|
||||||
|
|
||||||
|
|
||||||
|
def wrap_exceptions(fun):
|
||||||
|
"""Call callable into a try/except clause and translate ENOENT,
|
||||||
|
EACCES and EPERM in NoSuchProcess or AccessDenied exceptions.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def wrapper(self, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
return fun(self, *args, **kwargs)
|
||||||
|
except EnvironmentError as err:
|
||||||
|
# support for private module import
|
||||||
|
if (NoSuchProcess is None or AccessDenied is None or
|
||||||
|
ZombieProcess is None):
|
||||||
|
raise
|
||||||
|
# ENOENT (no such file or directory) gets raised on open().
|
||||||
|
# ESRCH (no such process) can get raised on read() if
|
||||||
|
# process is gone in meantime.
|
||||||
|
if err.errno in (errno.ENOENT, errno.ESRCH):
|
||||||
|
if not pid_exists(self.pid):
|
||||||
|
raise NoSuchProcess(self.pid, self._name)
|
||||||
|
else:
|
||||||
|
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||||
|
if err.errno in (errno.EPERM, errno.EACCES):
|
||||||
|
raise AccessDenied(self.pid, self._name)
|
||||||
|
raise
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
class Process(object):
|
||||||
|
"""Wrapper class around underlying C implementation."""
|
||||||
|
|
||||||
|
__slots__ = ["pid", "_name", "_ppid", "_procfs_path"]
|
||||||
|
|
||||||
|
def __init__(self, pid):
|
||||||
|
self.pid = pid
|
||||||
|
self._name = None
|
||||||
|
self._ppid = None
|
||||||
|
self._procfs_path = get_procfs_path()
|
||||||
|
|
||||||
|
def oneshot_enter(self):
|
||||||
|
self._proc_name_and_args.cache_activate()
|
||||||
|
self._proc_basic_info.cache_activate()
|
||||||
|
self._proc_cred.cache_activate()
|
||||||
|
|
||||||
|
def oneshot_exit(self):
|
||||||
|
self._proc_name_and_args.cache_deactivate()
|
||||||
|
self._proc_basic_info.cache_deactivate()
|
||||||
|
self._proc_cred.cache_deactivate()
|
||||||
|
|
||||||
|
@memoize_when_activated
|
||||||
|
def _proc_name_and_args(self):
|
||||||
|
return cext.proc_name_and_args(self.pid, self._procfs_path)
|
||||||
|
|
||||||
|
@memoize_when_activated
|
||||||
|
def _proc_basic_info(self):
|
||||||
|
return cext.proc_basic_info(self.pid, self._procfs_path)
|
||||||
|
|
||||||
|
@memoize_when_activated
|
||||||
|
def _proc_cred(self):
|
||||||
|
return cext.proc_cred(self.pid, self._procfs_path)
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def name(self):
|
||||||
|
if self.pid == 0:
|
||||||
|
return "swapper"
|
||||||
|
# note: this is limited to 15 characters
|
||||||
|
return self._proc_name_and_args()[0].rstrip("\x00")
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def exe(self):
|
||||||
|
# there is no way to get executable path in AIX other than to guess,
|
||||||
|
# and guessing is more complex than what's in the wrapping class
|
||||||
|
exe = self.cmdline()[0]
|
||||||
|
if os.path.sep in exe:
|
||||||
|
# relative or absolute path
|
||||||
|
if not os.path.isabs(exe):
|
||||||
|
# if cwd has changed, we're out of luck - this may be wrong!
|
||||||
|
exe = os.path.abspath(os.path.join(self.cwd(), exe))
|
||||||
|
if (os.path.isabs(exe) and
|
||||||
|
os.path.isfile(exe) and
|
||||||
|
os.access(exe, os.X_OK)):
|
||||||
|
return exe
|
||||||
|
# not found, move to search in PATH using basename only
|
||||||
|
exe = os.path.basename(exe)
|
||||||
|
# search for exe name PATH
|
||||||
|
for path in os.environ["PATH"].split(":"):
|
||||||
|
possible_exe = os.path.abspath(os.path.join(path, exe))
|
||||||
|
if (os.path.isfile(possible_exe) and
|
||||||
|
os.access(possible_exe, os.X_OK)):
|
||||||
|
return possible_exe
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def cmdline(self):
|
||||||
|
return self._proc_name_and_args()[1].split(' ')
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def create_time(self):
|
||||||
|
return self._proc_basic_info()[proc_info_map['create_time']]
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def num_threads(self):
|
||||||
|
return self._proc_basic_info()[proc_info_map['num_threads']]
|
||||||
|
|
||||||
|
if HAS_THREADS:
|
||||||
|
@wrap_exceptions
|
||||||
|
def threads(self):
|
||||||
|
rawlist = cext.proc_threads(self.pid)
|
||||||
|
retlist = []
|
||||||
|
for thread_id, utime, stime in rawlist:
|
||||||
|
ntuple = _common.pthread(thread_id, utime, stime)
|
||||||
|
retlist.append(ntuple)
|
||||||
|
# The underlying C implementation retrieves all OS threads
|
||||||
|
# and filters them by PID. At this point we can't tell whether
|
||||||
|
# an empty list means there were no connections for process or
|
||||||
|
# process is no longer active so we force NSP in case the PID
|
||||||
|
# is no longer there.
|
||||||
|
if not retlist:
|
||||||
|
# will raise NSP if process is gone
|
||||||
|
os.stat('%s/%s' % (self._procfs_path, self.pid))
|
||||||
|
return retlist
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def connections(self, kind='inet'):
|
||||||
|
ret = net_connections(kind, _pid=self.pid)
|
||||||
|
# The underlying C implementation retrieves all OS connections
|
||||||
|
# and filters them by PID. At this point we can't tell whether
|
||||||
|
# an empty list means there were no connections for process or
|
||||||
|
# process is no longer active so we force NSP in case the PID
|
||||||
|
# is no longer there.
|
||||||
|
if not ret:
|
||||||
|
# will raise NSP if process is gone
|
||||||
|
os.stat('%s/%s' % (self._procfs_path, self.pid))
|
||||||
|
return ret
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def nice_get(self):
|
||||||
|
return cext_posix.getpriority(self.pid)
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def nice_set(self, value):
|
||||||
|
return cext_posix.setpriority(self.pid, value)
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def ppid(self):
|
||||||
|
self._ppid = self._proc_basic_info()[proc_info_map['ppid']]
|
||||||
|
return self._ppid
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def uids(self):
|
||||||
|
real, effective, saved, _, _, _ = self._proc_cred()
|
||||||
|
return _common.puids(real, effective, saved)
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def gids(self):
|
||||||
|
_, _, _, real, effective, saved = self._proc_cred()
|
||||||
|
return _common.puids(real, effective, saved)
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def cpu_times(self):
|
||||||
|
cpu_times = cext.proc_cpu_times(self.pid, self._procfs_path)
|
||||||
|
return _common.pcputimes(*cpu_times)
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def terminal(self):
|
||||||
|
ttydev = self._proc_basic_info()[proc_info_map['ttynr']]
|
||||||
|
# convert from 64-bit dev_t to 32-bit dev_t and then map the device
|
||||||
|
ttydev = (((ttydev & 0x0000FFFF00000000) >> 16) | (ttydev & 0xFFFF))
|
||||||
|
# try to match rdev of /dev/pts/* files ttydev
|
||||||
|
for dev in glob.glob("/dev/**/*"):
|
||||||
|
if os.stat(dev).st_rdev == ttydev:
|
||||||
|
return dev
|
||||||
|
return None
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def cwd(self):
|
||||||
|
procfs_path = self._procfs_path
|
||||||
|
try:
|
||||||
|
result = os.readlink("%s/%s/cwd" % (procfs_path, self.pid))
|
||||||
|
return result.rstrip('/')
|
||||||
|
except OSError as err:
|
||||||
|
if err.errno == errno.ENOENT:
|
||||||
|
os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD
|
||||||
|
return None
|
||||||
|
raise
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def memory_info(self):
|
||||||
|
ret = self._proc_basic_info()
|
||||||
|
rss = ret[proc_info_map['rss']] * 1024
|
||||||
|
vms = ret[proc_info_map['vms']] * 1024
|
||||||
|
return pmem(rss, vms)
|
||||||
|
|
||||||
|
memory_full_info = memory_info
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def status(self):
|
||||||
|
code = self._proc_basic_info()[proc_info_map['status']]
|
||||||
|
# XXX is '?' legit? (we're not supposed to return it anyway)
|
||||||
|
return PROC_STATUSES.get(code, '?')
|
||||||
|
|
||||||
|
def open_files(self):
|
||||||
|
# TODO rewrite without using procfiles (stat /proc/pid/fd/* and then
|
||||||
|
# find matching name of the inode)
|
||||||
|
p = subprocess.Popen(["/usr/bin/procfiles", "-n", str(self.pid)],
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
stdout, stderr = p.communicate()
|
||||||
|
if PY3:
|
||||||
|
stdout, stderr = [x.decode(sys.stdout.encoding)
|
||||||
|
for x in (stdout, stderr)]
|
||||||
|
if "no such process" in stderr.lower():
|
||||||
|
raise NoSuchProcess(self.pid, self._name)
|
||||||
|
procfiles = re.findall("(\d+): S_IFREG.*\s*.*name:(.*)\n", stdout)
|
||||||
|
retlist = []
|
||||||
|
for fd, path in procfiles:
|
||||||
|
path = path.strip()
|
||||||
|
if path.startswith("//"):
|
||||||
|
path = path[1:]
|
||||||
|
if path.lower() == "cannot be retrieved":
|
||||||
|
continue
|
||||||
|
retlist.append(_common.popenfile(path, int(fd)))
|
||||||
|
return retlist
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def num_fds(self):
|
||||||
|
if self.pid == 0: # no /proc/0/fd
|
||||||
|
return 0
|
||||||
|
return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid)))
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def num_ctx_switches(self):
|
||||||
|
return _common.pctxsw(
|
||||||
|
*cext.proc_num_ctx_switches(self.pid))
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def wait(self, timeout=None):
|
||||||
|
return _psposix.wait_pid(self.pid, timeout, self._name)
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def io_counters(self):
|
||||||
|
try:
|
||||||
|
rc, wc, rb, wb = cext.proc_io_counters(self.pid)
|
||||||
|
except OSError:
|
||||||
|
# if process is terminated, proc_io_counters returns OSError
|
||||||
|
# instead of NSP
|
||||||
|
if not pid_exists(self.pid):
|
||||||
|
raise NoSuchProcess(self.pid, self._name)
|
||||||
|
raise
|
||||||
|
return _common.pio(rc, wc, rb, wb)
|
|
@ -1,38 +1,86 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||||
# Use of this source code is governed by a BSD-style license that can be
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
# found in the LICENSE file.
|
# found in the LICENSE file.
|
||||||
|
|
||||||
"""FreeBSD platform implementation."""
|
"""FreeBSD, OpenBSD and NetBSD platforms implementation."""
|
||||||
|
|
||||||
|
import contextlib
|
||||||
import errno
|
import errno
|
||||||
import functools
|
import functools
|
||||||
import os
|
import os
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from socket import AF_INET
|
||||||
|
|
||||||
from . import _common
|
from . import _common
|
||||||
from . import _psposix
|
from . import _psposix
|
||||||
from . import _psutil_bsd as cext
|
from . import _psutil_bsd as cext
|
||||||
from . import _psutil_posix as cext_posix
|
from . import _psutil_posix as cext_posix
|
||||||
from ._common import conn_tmap, usage_percent, sockfam_to_enum
|
from ._common import AF_INET6
|
||||||
|
from ._common import conn_tmap
|
||||||
|
from ._common import FREEBSD
|
||||||
|
from ._common import memoize
|
||||||
|
from ._common import memoize_when_activated
|
||||||
|
from ._common import NETBSD
|
||||||
|
from ._common import OPENBSD
|
||||||
|
from ._common import sockfam_to_enum
|
||||||
from ._common import socktype_to_enum
|
from ._common import socktype_to_enum
|
||||||
|
from ._common import usage_percent
|
||||||
|
from ._compat import which
|
||||||
|
from ._exceptions import AccessDenied
|
||||||
|
from ._exceptions import NoSuchProcess
|
||||||
|
from ._exceptions import ZombieProcess
|
||||||
|
|
||||||
__extra__all__ = []
|
__extra__all__ = []
|
||||||
|
|
||||||
# --- constants
|
|
||||||
|
|
||||||
PROC_STATUSES = {
|
# =====================================================================
|
||||||
cext.SSTOP: _common.STATUS_STOPPED,
|
# --- globals
|
||||||
cext.SSLEEP: _common.STATUS_SLEEPING,
|
# =====================================================================
|
||||||
cext.SRUN: _common.STATUS_RUNNING,
|
|
||||||
cext.SIDL: _common.STATUS_IDLE,
|
|
||||||
cext.SWAIT: _common.STATUS_WAITING,
|
if FREEBSD:
|
||||||
cext.SLOCK: _common.STATUS_LOCKED,
|
PROC_STATUSES = {
|
||||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
cext.SIDL: _common.STATUS_IDLE,
|
||||||
}
|
cext.SRUN: _common.STATUS_RUNNING,
|
||||||
|
cext.SSLEEP: _common.STATUS_SLEEPING,
|
||||||
|
cext.SSTOP: _common.STATUS_STOPPED,
|
||||||
|
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||||
|
cext.SWAIT: _common.STATUS_WAITING,
|
||||||
|
cext.SLOCK: _common.STATUS_LOCKED,
|
||||||
|
}
|
||||||
|
elif OPENBSD or NETBSD:
|
||||||
|
PROC_STATUSES = {
|
||||||
|
cext.SIDL: _common.STATUS_IDLE,
|
||||||
|
cext.SSLEEP: _common.STATUS_SLEEPING,
|
||||||
|
cext.SSTOP: _common.STATUS_STOPPED,
|
||||||
|
# According to /usr/include/sys/proc.h SZOMB is unused.
|
||||||
|
# test_zombie_process() shows that SDEAD is the right
|
||||||
|
# equivalent. Also it appears there's no equivalent of
|
||||||
|
# psutil.STATUS_DEAD. SDEAD really means STATUS_ZOMBIE.
|
||||||
|
# cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||||
|
cext.SDEAD: _common.STATUS_ZOMBIE,
|
||||||
|
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||||
|
# From http://www.eecs.harvard.edu/~margo/cs161/videos/proc.h.txt
|
||||||
|
# OpenBSD has SRUN and SONPROC: SRUN indicates that a process
|
||||||
|
# is runnable but *not* yet running, i.e. is on a run queue.
|
||||||
|
# SONPROC indicates that the process is actually executing on
|
||||||
|
# a CPU, i.e. it is no longer on a run queue.
|
||||||
|
# As such we'll map SRUN to STATUS_WAKING and SONPROC to
|
||||||
|
# STATUS_RUNNING
|
||||||
|
cext.SRUN: _common.STATUS_WAKING,
|
||||||
|
cext.SONPROC: _common.STATUS_RUNNING,
|
||||||
|
}
|
||||||
|
elif NETBSD:
|
||||||
|
PROC_STATUSES = {
|
||||||
|
cext.SIDL: _common.STATUS_IDLE,
|
||||||
|
cext.SACTIVE: _common.STATUS_RUNNING,
|
||||||
|
cext.SDYING: _common.STATUS_ZOMBIE,
|
||||||
|
cext.SSTOP: _common.STATUS_STOPPED,
|
||||||
|
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||||
|
cext.SDEAD: _common.STATUS_DEAD,
|
||||||
|
cext.SSUSPENDED: _common.STATUS_SUSPENDED, # unique to NetBSD
|
||||||
|
}
|
||||||
|
|
||||||
TCP_STATUSES = {
|
TCP_STATUSES = {
|
||||||
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
||||||
|
@ -49,32 +97,95 @@ TCP_STATUSES = {
|
||||||
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
|
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
|
||||||
}
|
}
|
||||||
|
|
||||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
if NETBSD:
|
||||||
|
PAGESIZE = os.sysconf("SC_PAGESIZE")
|
||||||
|
else:
|
||||||
|
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
||||||
AF_LINK = cext_posix.AF_LINK
|
AF_LINK = cext_posix.AF_LINK
|
||||||
|
|
||||||
# extend base mem ntuple with BSD-specific memory metrics
|
kinfo_proc_map = dict(
|
||||||
|
ppid=0,
|
||||||
|
status=1,
|
||||||
|
real_uid=2,
|
||||||
|
effective_uid=3,
|
||||||
|
saved_uid=4,
|
||||||
|
real_gid=5,
|
||||||
|
effective_gid=6,
|
||||||
|
saved_gid=7,
|
||||||
|
ttynr=8,
|
||||||
|
create_time=9,
|
||||||
|
ctx_switches_vol=10,
|
||||||
|
ctx_switches_unvol=11,
|
||||||
|
read_io_count=12,
|
||||||
|
write_io_count=13,
|
||||||
|
user_time=14,
|
||||||
|
sys_time=15,
|
||||||
|
ch_user_time=16,
|
||||||
|
ch_sys_time=17,
|
||||||
|
rss=18,
|
||||||
|
vms=19,
|
||||||
|
memtext=20,
|
||||||
|
memdata=21,
|
||||||
|
memstack=22,
|
||||||
|
cpunum=23,
|
||||||
|
name=24,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- named tuples
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
# psutil.virtual_memory()
|
||||||
svmem = namedtuple(
|
svmem = namedtuple(
|
||||||
'svmem', ['total', 'available', 'percent', 'used', 'free',
|
'svmem', ['total', 'available', 'percent', 'used', 'free',
|
||||||
'active', 'inactive', 'buffers', 'cached', 'shared', 'wired'])
|
'active', 'inactive', 'buffers', 'cached', 'shared', 'wired'])
|
||||||
|
# psutil.cpu_times()
|
||||||
scputimes = namedtuple(
|
scputimes = namedtuple(
|
||||||
'scputimes', ['user', 'nice', 'system', 'idle', 'irq'])
|
'scputimes', ['user', 'nice', 'system', 'idle', 'irq'])
|
||||||
pextmem = namedtuple('pextmem', ['rss', 'vms', 'text', 'data', 'stack'])
|
# psutil.Process.memory_info()
|
||||||
|
pmem = namedtuple('pmem', ['rss', 'vms', 'text', 'data', 'stack'])
|
||||||
|
# psutil.Process.memory_full_info()
|
||||||
|
pfullmem = pmem
|
||||||
|
# psutil.Process.cpu_times()
|
||||||
|
pcputimes = namedtuple('pcputimes',
|
||||||
|
['user', 'system', 'children_user', 'children_system'])
|
||||||
|
# psutil.Process.memory_maps(grouped=True)
|
||||||
pmmap_grouped = namedtuple(
|
pmmap_grouped = namedtuple(
|
||||||
'pmmap_grouped', 'path rss, private, ref_count, shadow_count')
|
'pmmap_grouped', 'path rss, private, ref_count, shadow_count')
|
||||||
|
# psutil.Process.memory_maps(grouped=False)
|
||||||
pmmap_ext = namedtuple(
|
pmmap_ext = namedtuple(
|
||||||
'pmmap_ext', 'addr, perms path rss, private, ref_count, shadow_count')
|
'pmmap_ext', 'addr, perms path rss, private, ref_count, shadow_count')
|
||||||
|
# psutil.disk_io_counters()
|
||||||
|
if FREEBSD:
|
||||||
|
sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
|
||||||
|
'read_bytes', 'write_bytes',
|
||||||
|
'read_time', 'write_time',
|
||||||
|
'busy_time'])
|
||||||
|
else:
|
||||||
|
sdiskio = namedtuple('sdiskio', ['read_count', 'write_count',
|
||||||
|
'read_bytes', 'write_bytes'])
|
||||||
|
|
||||||
# set later from __init__.py
|
|
||||||
NoSuchProcess = None
|
# =====================================================================
|
||||||
ZombieProcess = None
|
# --- memory
|
||||||
AccessDenied = None
|
# =====================================================================
|
||||||
TimeoutExpired = None
|
|
||||||
|
|
||||||
|
|
||||||
def virtual_memory():
|
def virtual_memory():
|
||||||
"""System virtual memory as a namedtuple."""
|
"""System virtual memory as a namedtuple."""
|
||||||
mem = cext.virtual_mem()
|
mem = cext.virtual_mem()
|
||||||
total, free, active, inactive, wired, cached, buffers, shared = mem
|
total, free, active, inactive, wired, cached, buffers, shared = mem
|
||||||
|
if NETBSD:
|
||||||
|
# On NetBSD buffers and shared mem is determined via /proc.
|
||||||
|
# The C ext set them to 0.
|
||||||
|
with open('/proc/meminfo', 'rb') as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith(b'Buffers:'):
|
||||||
|
buffers = int(line.split()[1]) * 1024
|
||||||
|
elif line.startswith(b'MemShared:'):
|
||||||
|
shared = int(line.split()[1]) * 1024
|
||||||
avail = inactive + cached + free
|
avail = inactive + cached + free
|
||||||
used = active + wired + cached
|
used = active + wired + cached
|
||||||
percent = usage_percent((total - avail), total, _round=1)
|
percent = usage_percent((total - avail), total, _round=1)
|
||||||
|
@ -84,11 +195,16 @@ def virtual_memory():
|
||||||
|
|
||||||
def swap_memory():
|
def swap_memory():
|
||||||
"""System swap memory as (total, used, free, sin, sout) namedtuple."""
|
"""System swap memory as (total, used, free, sin, sout) namedtuple."""
|
||||||
total, used, free, sin, sout = [x * PAGESIZE for x in cext.swap_mem()]
|
total, used, free, sin, sout = cext.swap_mem()
|
||||||
percent = usage_percent(used, total, _round=1)
|
percent = usage_percent(used, total, _round=1)
|
||||||
return _common.sswap(total, used, free, percent, sin, sout)
|
return _common.sswap(total, used, free, percent, sin, sout)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- CPU
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
def cpu_times():
|
def cpu_times():
|
||||||
"""Return system per-CPU times as a namedtuple"""
|
"""Return system per-CPU times as a namedtuple"""
|
||||||
user, nice, system, idle, irq = cext.cpu_times()
|
user, nice, system, idle, irq = cext.cpu_times()
|
||||||
|
@ -113,6 +229,7 @@ else:
|
||||||
# crash at psutil import time.
|
# crash at psutil import time.
|
||||||
# Next calls will fail with NotImplementedError
|
# Next calls will fail with NotImplementedError
|
||||||
def per_cpu_times():
|
def per_cpu_times():
|
||||||
|
"""Return system CPU times as a namedtuple"""
|
||||||
if cpu_count_logical() == 1:
|
if cpu_count_logical() == 1:
|
||||||
return [cpu_times()]
|
return [cpu_times()]
|
||||||
if per_cpu_times.__called__:
|
if per_cpu_times.__called__:
|
||||||
|
@ -128,73 +245,140 @@ def cpu_count_logical():
|
||||||
return cext.cpu_count_logical()
|
return cext.cpu_count_logical()
|
||||||
|
|
||||||
|
|
||||||
def cpu_count_physical():
|
if OPENBSD or NETBSD:
|
||||||
"""Return the number of physical CPUs in the system."""
|
def cpu_count_physical():
|
||||||
# From the C module we'll get an XML string similar to this:
|
# OpenBSD and NetBSD do not implement this.
|
||||||
# http://manpages.ubuntu.com/manpages/precise/man4/smp.4freebsd.html
|
return 1 if cpu_count_logical() == 1 else None
|
||||||
# We may get None in case "sysctl kern.sched.topology_spec"
|
else:
|
||||||
# is not supported on this BSD version, in which case we'll mimic
|
def cpu_count_physical():
|
||||||
# os.cpu_count() and return None.
|
"""Return the number of physical CPUs in the system."""
|
||||||
ret = None
|
# From the C module we'll get an XML string similar to this:
|
||||||
s = cext.cpu_count_phys()
|
# http://manpages.ubuntu.com/manpages/precise/man4/smp.4freebsd.html
|
||||||
if s is not None:
|
# We may get None in case "sysctl kern.sched.topology_spec"
|
||||||
# get rid of padding chars appended at the end of the string
|
# is not supported on this BSD version, in which case we'll mimic
|
||||||
index = s.rfind("</groups>")
|
# os.cpu_count() and return None.
|
||||||
if index != -1:
|
ret = None
|
||||||
s = s[:index + 9]
|
s = cext.cpu_count_phys()
|
||||||
root = ET.fromstring(s)
|
if s is not None:
|
||||||
try:
|
# get rid of padding chars appended at the end of the string
|
||||||
ret = len(root.findall('group/children/group/cpu')) or None
|
index = s.rfind("</groups>")
|
||||||
finally:
|
if index != -1:
|
||||||
# needed otherwise it will memleak
|
s = s[:index + 9]
|
||||||
root.clear()
|
root = ET.fromstring(s)
|
||||||
if not ret:
|
try:
|
||||||
# If logical CPUs are 1 it's obvious we'll have only 1
|
ret = len(root.findall('group/children/group/cpu')) or None
|
||||||
# physical CPU.
|
finally:
|
||||||
if cpu_count_logical() == 1:
|
# needed otherwise it will memleak
|
||||||
return 1
|
root.clear()
|
||||||
return ret
|
if not ret:
|
||||||
|
# If logical CPUs are 1 it's obvious we'll have only 1
|
||||||
|
# physical CPU.
|
||||||
|
if cpu_count_logical() == 1:
|
||||||
|
return 1
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def boot_time():
|
def cpu_stats():
|
||||||
"""The system boot time expressed in seconds since the epoch."""
|
"""Return various CPU stats as a named tuple."""
|
||||||
return cext.boot_time()
|
if FREEBSD:
|
||||||
|
# Note: the C ext is returning some metrics we are not exposing:
|
||||||
|
# traps.
|
||||||
|
ctxsw, intrs, soft_intrs, syscalls, traps = cext.cpu_stats()
|
||||||
|
elif NETBSD:
|
||||||
|
# XXX
|
||||||
|
# Note about intrs: the C extension returns 0. intrs
|
||||||
|
# can be determined via /proc/stat; it has the same value as
|
||||||
|
# soft_intrs thought so the kernel is faking it (?).
|
||||||
|
#
|
||||||
|
# Note about syscalls: the C extension always sets it to 0 (?).
|
||||||
|
#
|
||||||
|
# Note: the C ext is returning some metrics we are not exposing:
|
||||||
|
# traps, faults and forks.
|
||||||
|
ctxsw, intrs, soft_intrs, syscalls, traps, faults, forks = \
|
||||||
|
cext.cpu_stats()
|
||||||
|
with open('/proc/stat', 'rb') as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith(b'intr'):
|
||||||
|
intrs = int(line.split()[1])
|
||||||
|
elif OPENBSD:
|
||||||
|
# Note: the C ext is returning some metrics we are not exposing:
|
||||||
|
# traps, faults and forks.
|
||||||
|
ctxsw, intrs, soft_intrs, syscalls, traps, faults, forks = \
|
||||||
|
cext.cpu_stats()
|
||||||
|
return _common.scpustats(ctxsw, intrs, soft_intrs, syscalls)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- disks
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
def disk_partitions(all=False):
|
def disk_partitions(all=False):
|
||||||
|
"""Return mounted disk partitions as a list of namedtuples.
|
||||||
|
'all' argument is ignored, see:
|
||||||
|
https://github.com/giampaolo/psutil/issues/906
|
||||||
|
"""
|
||||||
retlist = []
|
retlist = []
|
||||||
partitions = cext.disk_partitions()
|
partitions = cext.disk_partitions()
|
||||||
for partition in partitions:
|
for partition in partitions:
|
||||||
device, mountpoint, fstype, opts = partition
|
device, mountpoint, fstype, opts = partition
|
||||||
if device == 'none':
|
|
||||||
device = ''
|
|
||||||
if not all:
|
|
||||||
if not os.path.isabs(device) or not os.path.exists(device):
|
|
||||||
continue
|
|
||||||
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
|
ntuple = _common.sdiskpart(device, mountpoint, fstype, opts)
|
||||||
retlist.append(ntuple)
|
retlist.append(ntuple)
|
||||||
return retlist
|
return retlist
|
||||||
|
|
||||||
|
|
||||||
def users():
|
disk_usage = _psposix.disk_usage
|
||||||
retlist = []
|
disk_io_counters = cext.disk_io_counters
|
||||||
rawlist = cext.users()
|
|
||||||
for item in rawlist:
|
|
||||||
user, tty, hostname, tstamp = item
|
# =====================================================================
|
||||||
if tty == '~':
|
# --- network
|
||||||
continue # reboot or shutdown
|
# =====================================================================
|
||||||
nt = _common.suser(user, tty or None, hostname, tstamp)
|
|
||||||
retlist.append(nt)
|
|
||||||
return retlist
|
net_io_counters = cext.net_io_counters
|
||||||
|
net_if_addrs = cext_posix.net_if_addrs
|
||||||
|
|
||||||
|
|
||||||
|
def net_if_stats():
|
||||||
|
"""Get NIC stats (isup, duplex, speed, mtu)."""
|
||||||
|
names = net_io_counters().keys()
|
||||||
|
ret = {}
|
||||||
|
for name in names:
|
||||||
|
mtu = cext_posix.net_if_mtu(name)
|
||||||
|
isup = cext_posix.net_if_flags(name)
|
||||||
|
duplex, speed = cext_posix.net_if_duplex_speed(name)
|
||||||
|
if hasattr(_common, 'NicDuplex'):
|
||||||
|
duplex = _common.NicDuplex(duplex)
|
||||||
|
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def net_connections(kind):
|
def net_connections(kind):
|
||||||
|
"""System-wide network connections."""
|
||||||
|
if OPENBSD:
|
||||||
|
ret = []
|
||||||
|
for pid in pids():
|
||||||
|
try:
|
||||||
|
cons = Process(pid).connections(kind)
|
||||||
|
except (NoSuchProcess, ZombieProcess):
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
for conn in cons:
|
||||||
|
conn = list(conn)
|
||||||
|
conn.append(pid)
|
||||||
|
ret.append(_common.sconn(*conn))
|
||||||
|
return ret
|
||||||
|
|
||||||
if kind not in _common.conn_tmap:
|
if kind not in _common.conn_tmap:
|
||||||
raise ValueError("invalid %r kind argument; choose between %s"
|
raise ValueError("invalid %r kind argument; choose between %s"
|
||||||
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
||||||
families, types = conn_tmap[kind]
|
families, types = conn_tmap[kind]
|
||||||
ret = set()
|
ret = set()
|
||||||
rawlist = cext.net_connections()
|
if NETBSD:
|
||||||
|
rawlist = cext.net_connections(-1)
|
||||||
|
else:
|
||||||
|
rawlist = cext.net_connections()
|
||||||
for item in rawlist:
|
for item in rawlist:
|
||||||
fd, fam, type, laddr, raddr, status, pid = item
|
fd, fam, type, laddr, raddr, status, pid = item
|
||||||
# TODO: apply filter at C level
|
# TODO: apply filter at C level
|
||||||
|
@ -207,6 +391,11 @@ def net_connections(kind):
|
||||||
# have a very short lifetime so maybe the kernel
|
# have a very short lifetime so maybe the kernel
|
||||||
# can't initialize their status?
|
# can't initialize their status?
|
||||||
status = TCP_STATUSES[cext.PSUTIL_CONN_NONE]
|
status = TCP_STATUSES[cext.PSUTIL_CONN_NONE]
|
||||||
|
if fam in (AF_INET, AF_INET6):
|
||||||
|
if laddr:
|
||||||
|
laddr = _common.addr(*laddr)
|
||||||
|
if raddr:
|
||||||
|
raddr = _common.addr(*raddr)
|
||||||
fam = sockfam_to_enum(fam)
|
fam = sockfam_to_enum(fam)
|
||||||
type = socktype_to_enum(type)
|
type = socktype_to_enum(type)
|
||||||
nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid)
|
nt = _common.sconn(fd, fam, type, laddr, raddr, status, pid)
|
||||||
|
@ -214,24 +403,95 @@ def net_connections(kind):
|
||||||
return list(ret)
|
return list(ret)
|
||||||
|
|
||||||
|
|
||||||
def net_if_stats():
|
# =====================================================================
|
||||||
"""Get NIC stats (isup, duplex, speed, mtu)."""
|
# --- sensors
|
||||||
names = net_io_counters().keys()
|
# =====================================================================
|
||||||
ret = {}
|
|
||||||
for name in names:
|
|
||||||
isup, duplex, speed, mtu = cext_posix.net_if_stats(name)
|
if FREEBSD:
|
||||||
if hasattr(_common, 'NicDuplex'):
|
|
||||||
duplex = _common.NicDuplex(duplex)
|
def sensors_battery():
|
||||||
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
|
"""Return battery info."""
|
||||||
|
try:
|
||||||
|
percent, minsleft, power_plugged = cext.sensors_battery()
|
||||||
|
except NotImplementedError:
|
||||||
|
# See: https://github.com/giampaolo/psutil/issues/1074
|
||||||
|
return None
|
||||||
|
power_plugged = power_plugged == 1
|
||||||
|
if power_plugged:
|
||||||
|
secsleft = _common.POWER_TIME_UNLIMITED
|
||||||
|
elif minsleft == -1:
|
||||||
|
secsleft = _common.POWER_TIME_UNKNOWN
|
||||||
|
else:
|
||||||
|
secsleft = minsleft * 60
|
||||||
|
return _common.sbattery(percent, secsleft, power_plugged)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- other system functions
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def boot_time():
|
||||||
|
"""The system boot time expressed in seconds since the epoch."""
|
||||||
|
return cext.boot_time()
|
||||||
|
|
||||||
|
|
||||||
|
def users():
|
||||||
|
"""Return currently connected users as a list of namedtuples."""
|
||||||
|
retlist = []
|
||||||
|
rawlist = cext.users()
|
||||||
|
for item in rawlist:
|
||||||
|
user, tty, hostname, tstamp, pid = item
|
||||||
|
if pid == -1:
|
||||||
|
assert OPENBSD
|
||||||
|
pid = None
|
||||||
|
if tty == '~':
|
||||||
|
continue # reboot or shutdown
|
||||||
|
nt = _common.suser(user, tty or None, hostname, tstamp, pid)
|
||||||
|
retlist.append(nt)
|
||||||
|
return retlist
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- processes
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
@memoize
|
||||||
|
def _pid_0_exists():
|
||||||
|
try:
|
||||||
|
Process(0).name()
|
||||||
|
except NoSuchProcess:
|
||||||
|
return False
|
||||||
|
except AccessDenied:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def pids():
|
||||||
|
"""Returns a list of PIDs currently running on the system."""
|
||||||
|
ret = cext.pids()
|
||||||
|
if OPENBSD and (0 not in ret) and _pid_0_exists():
|
||||||
|
# On OpenBSD the kernel does not return PID 0 (neither does
|
||||||
|
# ps) but it's actually querable (Process(0) will succeed).
|
||||||
|
ret.insert(0, 0)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
pids = cext.pids
|
if OPENBSD or NETBSD:
|
||||||
pid_exists = _psposix.pid_exists
|
def pid_exists(pid):
|
||||||
disk_usage = _psposix.disk_usage
|
"""Return True if pid exists."""
|
||||||
net_io_counters = cext.net_io_counters
|
exists = _psposix.pid_exists(pid)
|
||||||
disk_io_counters = cext.disk_io_counters
|
if not exists:
|
||||||
net_if_addrs = cext_posix.net_if_addrs
|
# We do this because _psposix.pid_exists() lies in case of
|
||||||
|
# zombie processes.
|
||||||
|
return pid in pids()
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
pid_exists = _psposix.pid_exists
|
||||||
|
|
||||||
|
|
||||||
def wrap_exceptions(fun):
|
def wrap_exceptions(fun):
|
||||||
|
@ -243,10 +503,11 @@ def wrap_exceptions(fun):
|
||||||
try:
|
try:
|
||||||
return fun(self, *args, **kwargs)
|
return fun(self, *args, **kwargs)
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
# support for private module import
|
if self.pid == 0:
|
||||||
if (NoSuchProcess is None or AccessDenied is None or
|
if 0 in pids():
|
||||||
ZombieProcess is None):
|
raise AccessDenied(self.pid, self._name)
|
||||||
raise
|
else:
|
||||||
|
raise
|
||||||
if err.errno == errno.ESRCH:
|
if err.errno == errno.ESRCH:
|
||||||
if not pid_exists(self.pid):
|
if not pid_exists(self.pid):
|
||||||
raise NoSuchProcess(self.pid, self._name)
|
raise NoSuchProcess(self.pid, self._name)
|
||||||
|
@ -258,6 +519,25 @@ def wrap_exceptions(fun):
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def wrap_exceptions_procfs(inst):
|
||||||
|
"""Same as above, for routines relying on reading /proc fs."""
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except EnvironmentError as err:
|
||||||
|
# ENOENT (no such file or directory) gets raised on open().
|
||||||
|
# ESRCH (no such process) can get raised on read() if
|
||||||
|
# process is gone in meantime.
|
||||||
|
if err.errno in (errno.ENOENT, errno.ESRCH):
|
||||||
|
if not pid_exists(inst.pid):
|
||||||
|
raise NoSuchProcess(inst.pid, inst._name)
|
||||||
|
else:
|
||||||
|
raise ZombieProcess(inst.pid, inst._name, inst._ppid)
|
||||||
|
if err.errno in (errno.EPERM, errno.EACCES):
|
||||||
|
raise AccessDenied(inst.pid, inst._name)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
class Process(object):
|
class Process(object):
|
||||||
"""Wrapper class around underlying C implementation."""
|
"""Wrapper class around underlying C implementation."""
|
||||||
|
|
||||||
|
@ -268,22 +548,72 @@ class Process(object):
|
||||||
self._name = None
|
self._name = None
|
||||||
self._ppid = None
|
self._ppid = None
|
||||||
|
|
||||||
|
@memoize_when_activated
|
||||||
|
def oneshot(self):
|
||||||
|
"""Retrieves multiple process info in one shot as a raw tuple."""
|
||||||
|
ret = cext.proc_oneshot_info(self.pid)
|
||||||
|
assert len(ret) == len(kinfo_proc_map)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def oneshot_enter(self):
|
||||||
|
self.oneshot.cache_activate()
|
||||||
|
|
||||||
|
def oneshot_exit(self):
|
||||||
|
self.oneshot.cache_deactivate()
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def name(self):
|
def name(self):
|
||||||
return cext.proc_name(self.pid)
|
name = self.oneshot()[kinfo_proc_map['name']]
|
||||||
|
return name if name is not None else cext.proc_name(self.pid)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def exe(self):
|
def exe(self):
|
||||||
return cext.proc_exe(self.pid)
|
if FREEBSD:
|
||||||
|
return cext.proc_exe(self.pid)
|
||||||
|
elif NETBSD:
|
||||||
|
if self.pid == 0:
|
||||||
|
# /proc/0 dir exists but /proc/0/exe doesn't
|
||||||
|
return ""
|
||||||
|
with wrap_exceptions_procfs(self):
|
||||||
|
return os.readlink("/proc/%s/exe" % self.pid)
|
||||||
|
else:
|
||||||
|
# OpenBSD: exe cannot be determined; references:
|
||||||
|
# https://chromium.googlesource.com/chromium/src/base/+/
|
||||||
|
# master/base_paths_posix.cc
|
||||||
|
# We try our best guess by using which against the first
|
||||||
|
# cmdline arg (may return None).
|
||||||
|
cmdline = self.cmdline()
|
||||||
|
if cmdline:
|
||||||
|
return which(cmdline[0])
|
||||||
|
else:
|
||||||
|
return ""
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def cmdline(self):
|
def cmdline(self):
|
||||||
return cext.proc_cmdline(self.pid)
|
if OPENBSD and self.pid == 0:
|
||||||
|
return [] # ...else it crashes
|
||||||
|
elif NETBSD:
|
||||||
|
# XXX - most of the times the underlying sysctl() call on Net
|
||||||
|
# and Open BSD returns a truncated string.
|
||||||
|
# Also /proc/pid/cmdline behaves the same so it looks
|
||||||
|
# like this is a kernel bug.
|
||||||
|
try:
|
||||||
|
return cext.proc_cmdline(self.pid)
|
||||||
|
except OSError as err:
|
||||||
|
if err.errno == errno.EINVAL:
|
||||||
|
if not pid_exists(self.pid):
|
||||||
|
raise NoSuchProcess(self.pid, self._name)
|
||||||
|
else:
|
||||||
|
raise ZombieProcess(self.pid, self._name, self._ppid)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
return cext.proc_cmdline(self.pid)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def terminal(self):
|
def terminal(self):
|
||||||
tty_nr = cext.proc_tty_nr(self.pid)
|
tty_nr = self.oneshot()[kinfo_proc_map['ttynr']]
|
||||||
tmap = _psposix._get_terminal_map()
|
tmap = _psposix.get_terminal_map()
|
||||||
try:
|
try:
|
||||||
return tmap[tty_nr]
|
return tmap[tty_nr]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -291,51 +621,83 @@ class Process(object):
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def ppid(self):
|
def ppid(self):
|
||||||
return cext.proc_ppid(self.pid)
|
self._ppid = self.oneshot()[kinfo_proc_map['ppid']]
|
||||||
|
return self._ppid
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def uids(self):
|
def uids(self):
|
||||||
real, effective, saved = cext.proc_uids(self.pid)
|
rawtuple = self.oneshot()
|
||||||
return _common.puids(real, effective, saved)
|
return _common.puids(
|
||||||
|
rawtuple[kinfo_proc_map['real_uid']],
|
||||||
|
rawtuple[kinfo_proc_map['effective_uid']],
|
||||||
|
rawtuple[kinfo_proc_map['saved_uid']])
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def gids(self):
|
def gids(self):
|
||||||
real, effective, saved = cext.proc_gids(self.pid)
|
rawtuple = self.oneshot()
|
||||||
return _common.pgids(real, effective, saved)
|
return _common.pgids(
|
||||||
|
rawtuple[kinfo_proc_map['real_gid']],
|
||||||
|
rawtuple[kinfo_proc_map['effective_gid']],
|
||||||
|
rawtuple[kinfo_proc_map['saved_gid']])
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def cpu_times(self):
|
def cpu_times(self):
|
||||||
user, system = cext.proc_cpu_times(self.pid)
|
rawtuple = self.oneshot()
|
||||||
return _common.pcputimes(user, system)
|
return _common.pcputimes(
|
||||||
|
rawtuple[kinfo_proc_map['user_time']],
|
||||||
|
rawtuple[kinfo_proc_map['sys_time']],
|
||||||
|
rawtuple[kinfo_proc_map['ch_user_time']],
|
||||||
|
rawtuple[kinfo_proc_map['ch_sys_time']])
|
||||||
|
|
||||||
|
if FREEBSD:
|
||||||
|
@wrap_exceptions
|
||||||
|
def cpu_num(self):
|
||||||
|
return self.oneshot()[kinfo_proc_map['cpunum']]
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def memory_info(self):
|
def memory_info(self):
|
||||||
rss, vms = cext.proc_memory_info(self.pid)[:2]
|
rawtuple = self.oneshot()
|
||||||
return _common.pmem(rss, vms)
|
return pmem(
|
||||||
|
rawtuple[kinfo_proc_map['rss']],
|
||||||
|
rawtuple[kinfo_proc_map['vms']],
|
||||||
|
rawtuple[kinfo_proc_map['memtext']],
|
||||||
|
rawtuple[kinfo_proc_map['memdata']],
|
||||||
|
rawtuple[kinfo_proc_map['memstack']])
|
||||||
|
|
||||||
@wrap_exceptions
|
memory_full_info = memory_info
|
||||||
def memory_info_ex(self):
|
|
||||||
return pextmem(*cext.proc_memory_info(self.pid))
|
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def create_time(self):
|
def create_time(self):
|
||||||
return cext.proc_create_time(self.pid)
|
return self.oneshot()[kinfo_proc_map['create_time']]
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def num_threads(self):
|
def num_threads(self):
|
||||||
return cext.proc_num_threads(self.pid)
|
if hasattr(cext, "proc_num_threads"):
|
||||||
|
# FreeBSD
|
||||||
|
return cext.proc_num_threads(self.pid)
|
||||||
|
else:
|
||||||
|
return len(self.threads())
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def num_ctx_switches(self):
|
def num_ctx_switches(self):
|
||||||
return _common.pctxsw(*cext.proc_num_ctx_switches(self.pid))
|
rawtuple = self.oneshot()
|
||||||
|
return _common.pctxsw(
|
||||||
|
rawtuple[kinfo_proc_map['ctx_switches_vol']],
|
||||||
|
rawtuple[kinfo_proc_map['ctx_switches_unvol']])
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def threads(self):
|
def threads(self):
|
||||||
|
# Note: on OpenSBD this (/dev/mem) requires root access.
|
||||||
rawlist = cext.proc_threads(self.pid)
|
rawlist = cext.proc_threads(self.pid)
|
||||||
retlist = []
|
retlist = []
|
||||||
for thread_id, utime, stime in rawlist:
|
for thread_id, utime, stime in rawlist:
|
||||||
ntuple = _common.pthread(thread_id, utime, stime)
|
ntuple = _common.pthread(thread_id, utime, stime)
|
||||||
retlist.append(ntuple)
|
retlist.append(ntuple)
|
||||||
|
if OPENBSD:
|
||||||
|
# On OpenBSD the underlying C function does not raise NSP
|
||||||
|
# in case the process is gone (and the returned list may
|
||||||
|
# incomplete).
|
||||||
|
self.name() # raise NSP if the process disappeared on us
|
||||||
return retlist
|
return retlist
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
|
@ -343,27 +705,59 @@ class Process(object):
|
||||||
if kind not in conn_tmap:
|
if kind not in conn_tmap:
|
||||||
raise ValueError("invalid %r kind argument; choose between %s"
|
raise ValueError("invalid %r kind argument; choose between %s"
|
||||||
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
||||||
|
|
||||||
|
if NETBSD:
|
||||||
|
families, types = conn_tmap[kind]
|
||||||
|
ret = set()
|
||||||
|
rawlist = cext.net_connections(self.pid)
|
||||||
|
for item in rawlist:
|
||||||
|
fd, fam, type, laddr, raddr, status, pid = item
|
||||||
|
assert pid == self.pid
|
||||||
|
if fam in families and type in types:
|
||||||
|
try:
|
||||||
|
status = TCP_STATUSES[status]
|
||||||
|
except KeyError:
|
||||||
|
status = TCP_STATUSES[cext.PSUTIL_CONN_NONE]
|
||||||
|
if fam in (AF_INET, AF_INET6):
|
||||||
|
if laddr:
|
||||||
|
laddr = _common.addr(*laddr)
|
||||||
|
if raddr:
|
||||||
|
raddr = _common.addr(*raddr)
|
||||||
|
fam = sockfam_to_enum(fam)
|
||||||
|
type = socktype_to_enum(type)
|
||||||
|
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
|
||||||
|
ret.add(nt)
|
||||||
|
# On NetBSD the underlying C function does not raise NSP
|
||||||
|
# in case the process is gone (and the returned list may
|
||||||
|
# incomplete).
|
||||||
|
self.name() # raise NSP if the process disappeared on us
|
||||||
|
return list(ret)
|
||||||
|
|
||||||
families, types = conn_tmap[kind]
|
families, types = conn_tmap[kind]
|
||||||
rawlist = cext.proc_connections(self.pid, families, types)
|
rawlist = cext.proc_connections(self.pid, families, types)
|
||||||
ret = []
|
ret = []
|
||||||
for item in rawlist:
|
for item in rawlist:
|
||||||
fd, fam, type, laddr, raddr, status = item
|
fd, fam, type, laddr, raddr, status = item
|
||||||
|
if fam in (AF_INET, AF_INET6):
|
||||||
|
if laddr:
|
||||||
|
laddr = _common.addr(*laddr)
|
||||||
|
if raddr:
|
||||||
|
raddr = _common.addr(*raddr)
|
||||||
fam = sockfam_to_enum(fam)
|
fam = sockfam_to_enum(fam)
|
||||||
type = socktype_to_enum(type)
|
type = socktype_to_enum(type)
|
||||||
status = TCP_STATUSES[status]
|
status = TCP_STATUSES[status]
|
||||||
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
|
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
|
||||||
ret.append(nt)
|
ret.append(nt)
|
||||||
|
if OPENBSD:
|
||||||
|
# On OpenBSD the underlying C function does not raise NSP
|
||||||
|
# in case the process is gone (and the returned list may
|
||||||
|
# incomplete).
|
||||||
|
self.name() # raise NSP if the process disappeared on us
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def wait(self, timeout=None):
|
def wait(self, timeout=None):
|
||||||
try:
|
return _psposix.wait_pid(self.pid, timeout, self._name)
|
||||||
return _psposix.wait_pid(self.pid, timeout)
|
|
||||||
except _psposix.TimeoutExpired:
|
|
||||||
# support for private module import
|
|
||||||
if TimeoutExpired is None:
|
|
||||||
raise
|
|
||||||
raise TimeoutExpired(timeout, self.pid, self._name)
|
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def nice_get(self):
|
def nice_get(self):
|
||||||
|
@ -375,81 +769,105 @@ class Process(object):
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def status(self):
|
def status(self):
|
||||||
code = cext.proc_status(self.pid)
|
code = self.oneshot()[kinfo_proc_map['status']]
|
||||||
if code in PROC_STATUSES:
|
# XXX is '?' legit? (we're not supposed to return it anyway)
|
||||||
return PROC_STATUSES[code]
|
return PROC_STATUSES.get(code, '?')
|
||||||
# XXX is this legit? will we even ever get here?
|
|
||||||
return "?"
|
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def io_counters(self):
|
def io_counters(self):
|
||||||
rc, wc, rb, wb = cext.proc_io_counters(self.pid)
|
rawtuple = self.oneshot()
|
||||||
return _common.pio(rc, wc, rb, wb)
|
return _common.pio(
|
||||||
|
rawtuple[kinfo_proc_map['read_io_count']],
|
||||||
|
rawtuple[kinfo_proc_map['write_io_count']],
|
||||||
|
-1,
|
||||||
|
-1)
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def cwd(self):
|
||||||
|
"""Return process current working directory."""
|
||||||
|
# sometimes we get an empty string, in which case we turn
|
||||||
|
# it into None
|
||||||
|
if OPENBSD and self.pid == 0:
|
||||||
|
return None # ...else it would raise EINVAL
|
||||||
|
elif NETBSD:
|
||||||
|
with wrap_exceptions_procfs(self):
|
||||||
|
return os.readlink("/proc/%s/cwd" % self.pid)
|
||||||
|
elif hasattr(cext, 'proc_open_files'):
|
||||||
|
# FreeBSD < 8 does not support functions based on
|
||||||
|
# kinfo_getfile() and kinfo_getvmmap()
|
||||||
|
return cext.proc_cwd(self.pid) or None
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(
|
||||||
|
"supported only starting from FreeBSD 8" if
|
||||||
|
FREEBSD else "")
|
||||||
|
|
||||||
nt_mmap_grouped = namedtuple(
|
nt_mmap_grouped = namedtuple(
|
||||||
'mmap', 'path rss, private, ref_count, shadow_count')
|
'mmap', 'path rss, private, ref_count, shadow_count')
|
||||||
nt_mmap_ext = namedtuple(
|
nt_mmap_ext = namedtuple(
|
||||||
'mmap', 'addr, perms path rss, private, ref_count, shadow_count')
|
'mmap', 'addr, perms path rss, private, ref_count, shadow_count')
|
||||||
|
|
||||||
|
def _not_implemented(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
# FreeBSD < 8 does not support functions based on kinfo_getfile()
|
# FreeBSD < 8 does not support functions based on kinfo_getfile()
|
||||||
# and kinfo_getvmmap()
|
# and kinfo_getvmmap()
|
||||||
if hasattr(cext, 'proc_open_files'):
|
if hasattr(cext, 'proc_open_files'):
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def open_files(self):
|
def open_files(self):
|
||||||
"""Return files opened by process as a list of namedtuples."""
|
"""Return files opened by process as a list of namedtuples."""
|
||||||
rawlist = cext.proc_open_files(self.pid)
|
rawlist = cext.proc_open_files(self.pid)
|
||||||
return [_common.popenfile(path, fd) for path, fd in rawlist]
|
return [_common.popenfile(path, fd) for path, fd in rawlist]
|
||||||
|
else:
|
||||||
|
open_files = _not_implemented
|
||||||
|
|
||||||
|
# FreeBSD < 8 does not support functions based on kinfo_getfile()
|
||||||
|
# and kinfo_getvmmap()
|
||||||
|
if hasattr(cext, 'proc_num_fds'):
|
||||||
|
@wrap_exceptions
|
||||||
|
def num_fds(self):
|
||||||
|
"""Return the number of file descriptors opened by this process."""
|
||||||
|
ret = cext.proc_num_fds(self.pid)
|
||||||
|
if NETBSD:
|
||||||
|
# On NetBSD the underlying C function does not raise NSP
|
||||||
|
# in case the process is gone.
|
||||||
|
self.name() # raise NSP if the process disappeared on us
|
||||||
|
return ret
|
||||||
|
else:
|
||||||
|
num_fds = _not_implemented
|
||||||
|
|
||||||
|
# --- FreeBSD only APIs
|
||||||
|
|
||||||
|
if FREEBSD:
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def cwd(self):
|
def cpu_affinity_get(self):
|
||||||
"""Return process current working directory."""
|
return cext.proc_cpu_affinity_get(self.pid)
|
||||||
# sometimes we get an empty string, in which case we turn
|
|
||||||
# it into None
|
@wrap_exceptions
|
||||||
return cext.proc_cwd(self.pid) or None
|
def cpu_affinity_set(self, cpus):
|
||||||
|
# Pre-emptively check if CPUs are valid because the C
|
||||||
|
# function has a weird behavior in case of invalid CPUs,
|
||||||
|
# see: https://github.com/giampaolo/psutil/issues/586
|
||||||
|
allcpus = tuple(range(len(per_cpu_times())))
|
||||||
|
for cpu in cpus:
|
||||||
|
if cpu not in allcpus:
|
||||||
|
raise ValueError("invalid CPU #%i (choose between %s)"
|
||||||
|
% (cpu, allcpus))
|
||||||
|
try:
|
||||||
|
cext.proc_cpu_affinity_set(self.pid, cpus)
|
||||||
|
except OSError as err:
|
||||||
|
# 'man cpuset_setaffinity' about EDEADLK:
|
||||||
|
# <<the call would leave a thread without a valid CPU to run
|
||||||
|
# on because the set does not overlap with the thread's
|
||||||
|
# anonymous mask>>
|
||||||
|
if err.errno in (errno.EINVAL, errno.EDEADLK):
|
||||||
|
for cpu in cpus:
|
||||||
|
if cpu not in allcpus:
|
||||||
|
raise ValueError(
|
||||||
|
"invalid CPU #%i (choose between %s)" % (
|
||||||
|
cpu, allcpus))
|
||||||
|
raise
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def memory_maps(self):
|
def memory_maps(self):
|
||||||
return cext.proc_memory_maps(self.pid)
|
return cext.proc_memory_maps(self.pid)
|
||||||
|
|
||||||
@wrap_exceptions
|
|
||||||
def num_fds(self):
|
|
||||||
"""Return the number of file descriptors opened by this process."""
|
|
||||||
return cext.proc_num_fds(self.pid)
|
|
||||||
|
|
||||||
else:
|
|
||||||
def _not_implemented(self):
|
|
||||||
raise NotImplementedError("supported only starting from FreeBSD 8")
|
|
||||||
|
|
||||||
open_files = _not_implemented
|
|
||||||
proc_cwd = _not_implemented
|
|
||||||
memory_maps = _not_implemented
|
|
||||||
num_fds = _not_implemented
|
|
||||||
|
|
||||||
@wrap_exceptions
|
|
||||||
def cpu_affinity_get(self):
|
|
||||||
return cext.proc_cpu_affinity_get(self.pid)
|
|
||||||
|
|
||||||
@wrap_exceptions
|
|
||||||
def cpu_affinity_set(self, cpus):
|
|
||||||
# Pre-emptively check if CPUs are valid because the C
|
|
||||||
# function has a weird behavior in case of invalid CPUs,
|
|
||||||
# see: https://github.com/giampaolo/psutil/issues/586
|
|
||||||
allcpus = tuple(range(len(per_cpu_times())))
|
|
||||||
for cpu in cpus:
|
|
||||||
if cpu not in allcpus:
|
|
||||||
raise ValueError("invalid CPU #%i (choose between %s)"
|
|
||||||
% (cpu, allcpus))
|
|
||||||
try:
|
|
||||||
cext.proc_cpu_affinity_set(self.pid, cpus)
|
|
||||||
except OSError as err:
|
|
||||||
# 'man cpuset_setaffinity' about EDEADLK:
|
|
||||||
# <<the call would leave a thread without a valid CPU to run
|
|
||||||
# on because the set does not overlap with the thread's
|
|
||||||
# anonymous mask>>
|
|
||||||
if err.errno in (errno.EINVAL, errno.EDEADLK):
|
|
||||||
for cpu in cpus:
|
|
||||||
if cpu not in allcpus:
|
|
||||||
raise ValueError("invalid CPU #%i (choose between %s)"
|
|
||||||
% (cpu, allcpus))
|
|
||||||
raise
|
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,32 +1,44 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||||
# Use of this source code is governed by a BSD-style license that can be
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
# found in the LICENSE file.
|
# found in the LICENSE file.
|
||||||
|
|
||||||
"""OSX platform implementation."""
|
"""OSX platform implementation."""
|
||||||
|
|
||||||
|
import contextlib
|
||||||
import errno
|
import errno
|
||||||
import functools
|
import functools
|
||||||
import os
|
import os
|
||||||
|
from socket import AF_INET
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from . import _common
|
from . import _common
|
||||||
from . import _psposix
|
from . import _psposix
|
||||||
from . import _psutil_osx as cext
|
from . import _psutil_osx as cext
|
||||||
from . import _psutil_posix as cext_posix
|
from . import _psutil_posix as cext_posix
|
||||||
from ._common import conn_tmap, usage_percent, isfile_strict
|
from ._common import AF_INET6
|
||||||
from ._common import sockfam_to_enum, socktype_to_enum
|
from ._common import conn_tmap
|
||||||
|
from ._common import isfile_strict
|
||||||
|
from ._common import memoize_when_activated
|
||||||
|
from ._common import parse_environ_block
|
||||||
|
from ._common import sockfam_to_enum
|
||||||
|
from ._common import socktype_to_enum
|
||||||
|
from ._common import usage_percent
|
||||||
|
from ._exceptions import AccessDenied
|
||||||
|
from ._exceptions import NoSuchProcess
|
||||||
|
from ._exceptions import ZombieProcess
|
||||||
|
|
||||||
|
|
||||||
__extra__all__ = []
|
__extra__all__ = []
|
||||||
|
|
||||||
# --- constants
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- globals
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
||||||
AF_LINK = cext_posix.AF_LINK
|
AF_LINK = cext_posix.AF_LINK
|
||||||
|
|
||||||
# http://students.mimuw.edu.pl/lxr/source/include/net/tcp_states.h
|
|
||||||
TCP_STATUSES = {
|
TCP_STATUSES = {
|
||||||
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
cext.TCPS_ESTABLISHED: _common.CONN_ESTABLISHED,
|
||||||
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
|
cext.TCPS_SYN_SENT: _common.CONN_SYN_SENT,
|
||||||
|
@ -50,29 +62,60 @@ PROC_STATUSES = {
|
||||||
cext.SZOMB: _common.STATUS_ZOMBIE,
|
cext.SZOMB: _common.STATUS_ZOMBIE,
|
||||||
}
|
}
|
||||||
|
|
||||||
scputimes = namedtuple('scputimes', ['user', 'nice', 'system', 'idle'])
|
kinfo_proc_map = dict(
|
||||||
|
ppid=0,
|
||||||
|
ruid=1,
|
||||||
|
euid=2,
|
||||||
|
suid=3,
|
||||||
|
rgid=4,
|
||||||
|
egid=5,
|
||||||
|
sgid=6,
|
||||||
|
ttynr=7,
|
||||||
|
ctime=8,
|
||||||
|
status=9,
|
||||||
|
name=10,
|
||||||
|
)
|
||||||
|
|
||||||
|
pidtaskinfo_map = dict(
|
||||||
|
cpuutime=0,
|
||||||
|
cpustime=1,
|
||||||
|
rss=2,
|
||||||
|
vms=3,
|
||||||
|
pfaults=4,
|
||||||
|
pageins=5,
|
||||||
|
numthreads=6,
|
||||||
|
volctxsw=7,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- named tuples
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
# psutil.cpu_times()
|
||||||
|
scputimes = namedtuple('scputimes', ['user', 'nice', 'system', 'idle'])
|
||||||
|
# psutil.virtual_memory()
|
||||||
svmem = namedtuple(
|
svmem = namedtuple(
|
||||||
'svmem', ['total', 'available', 'percent', 'used', 'free',
|
'svmem', ['total', 'available', 'percent', 'used', 'free',
|
||||||
'active', 'inactive', 'wired'])
|
'active', 'inactive', 'wired'])
|
||||||
|
# psutil.Process.memory_info()
|
||||||
pextmem = namedtuple('pextmem', ['rss', 'vms', 'pfaults', 'pageins'])
|
pmem = namedtuple('pmem', ['rss', 'vms', 'pfaults', 'pageins'])
|
||||||
|
# psutil.Process.memory_full_info()
|
||||||
|
pfullmem = namedtuple('pfullmem', pmem._fields + ('uss', ))
|
||||||
|
# psutil.Process.memory_maps(grouped=True)
|
||||||
pmmap_grouped = namedtuple(
|
pmmap_grouped = namedtuple(
|
||||||
'pmmap_grouped',
|
'pmmap_grouped',
|
||||||
'path rss private swapped dirtied ref_count shadow_depth')
|
'path rss private swapped dirtied ref_count shadow_depth')
|
||||||
|
# psutil.Process.memory_maps(grouped=False)
|
||||||
pmmap_ext = namedtuple(
|
pmmap_ext = namedtuple(
|
||||||
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
|
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
|
||||||
|
|
||||||
# set later from __init__.py
|
|
||||||
NoSuchProcess = None
|
|
||||||
ZombieProcess = None
|
|
||||||
AccessDenied = None
|
|
||||||
TimeoutExpired = None
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- memory
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
# --- functions
|
|
||||||
|
|
||||||
def virtual_memory():
|
def virtual_memory():
|
||||||
"""System virtual memory as a namedtuple."""
|
"""System virtual memory as a namedtuple."""
|
||||||
|
@ -91,6 +134,11 @@ def swap_memory():
|
||||||
return _common.sswap(total, used, free, percent, sin, sout)
|
return _common.sswap(total, used, free, percent, sin, sout)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- CPU
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
def cpu_times():
|
def cpu_times():
|
||||||
"""Return system CPU times as a namedtuple."""
|
"""Return system CPU times as a namedtuple."""
|
||||||
user, nice, system, idle = cext.cpu_times()
|
user, nice, system, idle = cext.cpu_times()
|
||||||
|
@ -117,12 +165,34 @@ def cpu_count_physical():
|
||||||
return cext.cpu_count_phys()
|
return cext.cpu_count_phys()
|
||||||
|
|
||||||
|
|
||||||
def boot_time():
|
def cpu_stats():
|
||||||
"""The system boot time expressed in seconds since the epoch."""
|
ctx_switches, interrupts, soft_interrupts, syscalls, traps = \
|
||||||
return cext.boot_time()
|
cext.cpu_stats()
|
||||||
|
return _common.scpustats(
|
||||||
|
ctx_switches, interrupts, soft_interrupts, syscalls)
|
||||||
|
|
||||||
|
|
||||||
|
def cpu_freq():
|
||||||
|
"""Return CPU frequency.
|
||||||
|
On OSX per-cpu frequency is not supported.
|
||||||
|
Also, the returned frequency never changes, see:
|
||||||
|
https://arstechnica.com/civis/viewtopic.php?f=19&t=465002
|
||||||
|
"""
|
||||||
|
curr, min_, max_ = cext.cpu_freq()
|
||||||
|
return [_common.scpufreq(curr, min_, max_)]
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- disks
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
disk_usage = _psposix.disk_usage
|
||||||
|
disk_io_counters = cext.disk_io_counters
|
||||||
|
|
||||||
|
|
||||||
def disk_partitions(all=False):
|
def disk_partitions(all=False):
|
||||||
|
"""Return mounted disk partitions as a list of namedtuples."""
|
||||||
retlist = []
|
retlist = []
|
||||||
partitions = cext.disk_partitions()
|
partitions = cext.disk_partitions()
|
||||||
for partition in partitions:
|
for partition in partitions:
|
||||||
|
@ -137,21 +207,40 @@ def disk_partitions(all=False):
|
||||||
return retlist
|
return retlist
|
||||||
|
|
||||||
|
|
||||||
def users():
|
# =====================================================================
|
||||||
retlist = []
|
# --- sensors
|
||||||
rawlist = cext.users()
|
# =====================================================================
|
||||||
for item in rawlist:
|
|
||||||
user, tty, hostname, tstamp = item
|
|
||||||
if tty == '~':
|
def sensors_battery():
|
||||||
continue # reboot or shutdown
|
"""Return battery information.
|
||||||
if not tstamp:
|
"""
|
||||||
continue
|
try:
|
||||||
nt = _common.suser(user, tty or None, hostname or None, tstamp)
|
percent, minsleft, power_plugged = cext.sensors_battery()
|
||||||
retlist.append(nt)
|
except NotImplementedError:
|
||||||
return retlist
|
# no power source - return None according to interface
|
||||||
|
return None
|
||||||
|
power_plugged = power_plugged == 1
|
||||||
|
if power_plugged:
|
||||||
|
secsleft = _common.POWER_TIME_UNLIMITED
|
||||||
|
elif minsleft == -1:
|
||||||
|
secsleft = _common.POWER_TIME_UNKNOWN
|
||||||
|
else:
|
||||||
|
secsleft = minsleft * 60
|
||||||
|
return _common.sbattery(percent, secsleft, power_plugged)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- network
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
net_io_counters = cext.net_io_counters
|
||||||
|
net_if_addrs = cext_posix.net_if_addrs
|
||||||
|
|
||||||
|
|
||||||
def net_connections(kind='inet'):
|
def net_connections(kind='inet'):
|
||||||
|
"""System-wide network connections."""
|
||||||
# Note: on OSX this will fail with AccessDenied unless
|
# Note: on OSX this will fail with AccessDenied unless
|
||||||
# the process is owned by root.
|
# the process is owned by root.
|
||||||
ret = []
|
ret = []
|
||||||
|
@ -173,19 +262,62 @@ def net_if_stats():
|
||||||
names = net_io_counters().keys()
|
names = net_io_counters().keys()
|
||||||
ret = {}
|
ret = {}
|
||||||
for name in names:
|
for name in names:
|
||||||
isup, duplex, speed, mtu = cext_posix.net_if_stats(name)
|
mtu = cext_posix.net_if_mtu(name)
|
||||||
|
isup = cext_posix.net_if_flags(name)
|
||||||
|
duplex, speed = cext_posix.net_if_duplex_speed(name)
|
||||||
if hasattr(_common, 'NicDuplex'):
|
if hasattr(_common, 'NicDuplex'):
|
||||||
duplex = _common.NicDuplex(duplex)
|
duplex = _common.NicDuplex(duplex)
|
||||||
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
|
ret[name] = _common.snicstats(isup, duplex, speed, mtu)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
pids = cext.pids
|
# =====================================================================
|
||||||
|
# --- other system functions
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def boot_time():
|
||||||
|
"""The system boot time expressed in seconds since the epoch."""
|
||||||
|
return cext.boot_time()
|
||||||
|
|
||||||
|
|
||||||
|
def users():
|
||||||
|
"""Return currently connected users as a list of namedtuples."""
|
||||||
|
retlist = []
|
||||||
|
rawlist = cext.users()
|
||||||
|
for item in rawlist:
|
||||||
|
user, tty, hostname, tstamp, pid = item
|
||||||
|
if tty == '~':
|
||||||
|
continue # reboot or shutdown
|
||||||
|
if not tstamp:
|
||||||
|
continue
|
||||||
|
nt = _common.suser(user, tty or None, hostname or None, tstamp, pid)
|
||||||
|
retlist.append(nt)
|
||||||
|
return retlist
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- processes
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def pids():
|
||||||
|
ls = cext.pids()
|
||||||
|
if 0 not in ls:
|
||||||
|
# On certain OSX versions pids() C doesn't return PID 0 but
|
||||||
|
# "ps" does and the process is querable via sysctl():
|
||||||
|
# https://travis-ci.org/giampaolo/psutil/jobs/309619941
|
||||||
|
try:
|
||||||
|
Process(0).create_time()
|
||||||
|
ls.append(0)
|
||||||
|
except NoSuchProcess:
|
||||||
|
pass
|
||||||
|
except AccessDenied:
|
||||||
|
ls.append(0)
|
||||||
|
return ls
|
||||||
|
|
||||||
|
|
||||||
pid_exists = _psposix.pid_exists
|
pid_exists = _psposix.pid_exists
|
||||||
disk_usage = _psposix.disk_usage
|
|
||||||
net_io_counters = cext.net_io_counters
|
|
||||||
disk_io_counters = cext.disk_io_counters
|
|
||||||
net_if_addrs = cext_posix.net_if_addrs
|
|
||||||
|
|
||||||
|
|
||||||
def wrap_exceptions(fun):
|
def wrap_exceptions(fun):
|
||||||
|
@ -197,21 +329,40 @@ def wrap_exceptions(fun):
|
||||||
try:
|
try:
|
||||||
return fun(self, *args, **kwargs)
|
return fun(self, *args, **kwargs)
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
# support for private module import
|
|
||||||
if (NoSuchProcess is None or AccessDenied is None or
|
|
||||||
ZombieProcess is None):
|
|
||||||
raise
|
|
||||||
if err.errno == errno.ESRCH:
|
if err.errno == errno.ESRCH:
|
||||||
if not pid_exists(self.pid):
|
raise NoSuchProcess(self.pid, self._name)
|
||||||
raise NoSuchProcess(self.pid, self._name)
|
|
||||||
else:
|
|
||||||
raise ZombieProcess(self.pid, self._name, self._ppid)
|
|
||||||
if err.errno in (errno.EPERM, errno.EACCES):
|
if err.errno in (errno.EPERM, errno.EACCES):
|
||||||
raise AccessDenied(self.pid, self._name)
|
raise AccessDenied(self.pid, self._name)
|
||||||
raise
|
raise
|
||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def catch_zombie(proc):
|
||||||
|
"""There are some poor C APIs which incorrectly raise ESRCH when
|
||||||
|
the process is still alive or it's a zombie, or even RuntimeError
|
||||||
|
(those who don't set errno). This is here in order to solve:
|
||||||
|
https://github.com/giampaolo/psutil/issues/1044
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except (OSError, RuntimeError) as err:
|
||||||
|
if isinstance(err, RuntimeError) or err.errno == errno.ESRCH:
|
||||||
|
try:
|
||||||
|
# status() is not supposed to lie and correctly detect
|
||||||
|
# zombies so if it raises ESRCH it's true.
|
||||||
|
status = proc.status()
|
||||||
|
except NoSuchProcess:
|
||||||
|
raise err
|
||||||
|
else:
|
||||||
|
if status == _common.STATUS_ZOMBIE:
|
||||||
|
raise ZombieProcess(proc.pid, proc._name, proc._ppid)
|
||||||
|
else:
|
||||||
|
raise AccessDenied(proc.pid, proc._name)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
class Process(object):
|
class Process(object):
|
||||||
"""Wrapper class around underlying C implementation."""
|
"""Wrapper class around underlying C implementation."""
|
||||||
|
|
||||||
|
@ -222,42 +373,79 @@ class Process(object):
|
||||||
self._name = None
|
self._name = None
|
||||||
self._ppid = None
|
self._ppid = None
|
||||||
|
|
||||||
|
@memoize_when_activated
|
||||||
|
def _get_kinfo_proc(self):
|
||||||
|
# Note: should work with all PIDs without permission issues.
|
||||||
|
ret = cext.proc_kinfo_oneshot(self.pid)
|
||||||
|
assert len(ret) == len(kinfo_proc_map)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
@memoize_when_activated
|
||||||
|
def _get_pidtaskinfo(self):
|
||||||
|
# Note: should work for PIDs owned by user only.
|
||||||
|
with catch_zombie(self):
|
||||||
|
ret = cext.proc_pidtaskinfo_oneshot(self.pid)
|
||||||
|
assert len(ret) == len(pidtaskinfo_map)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def oneshot_enter(self):
|
||||||
|
self._get_kinfo_proc.cache_activate()
|
||||||
|
self._get_pidtaskinfo.cache_activate()
|
||||||
|
|
||||||
|
def oneshot_exit(self):
|
||||||
|
self._get_kinfo_proc.cache_deactivate()
|
||||||
|
self._get_pidtaskinfo.cache_deactivate()
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def name(self):
|
def name(self):
|
||||||
return cext.proc_name(self.pid)
|
name = self._get_kinfo_proc()[kinfo_proc_map['name']]
|
||||||
|
return name if name is not None else cext.proc_name(self.pid)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def exe(self):
|
def exe(self):
|
||||||
return cext.proc_exe(self.pid)
|
with catch_zombie(self):
|
||||||
|
return cext.proc_exe(self.pid)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def cmdline(self):
|
def cmdline(self):
|
||||||
if not pid_exists(self.pid):
|
with catch_zombie(self):
|
||||||
raise NoSuchProcess(self.pid, self._name)
|
return cext.proc_cmdline(self.pid)
|
||||||
return cext.proc_cmdline(self.pid)
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def environ(self):
|
||||||
|
with catch_zombie(self):
|
||||||
|
return parse_environ_block(cext.proc_environ(self.pid))
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def ppid(self):
|
def ppid(self):
|
||||||
return cext.proc_ppid(self.pid)
|
self._ppid = self._get_kinfo_proc()[kinfo_proc_map['ppid']]
|
||||||
|
return self._ppid
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def cwd(self):
|
def cwd(self):
|
||||||
return cext.proc_cwd(self.pid)
|
with catch_zombie(self):
|
||||||
|
return cext.proc_cwd(self.pid)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def uids(self):
|
def uids(self):
|
||||||
real, effective, saved = cext.proc_uids(self.pid)
|
rawtuple = self._get_kinfo_proc()
|
||||||
return _common.puids(real, effective, saved)
|
return _common.puids(
|
||||||
|
rawtuple[kinfo_proc_map['ruid']],
|
||||||
|
rawtuple[kinfo_proc_map['euid']],
|
||||||
|
rawtuple[kinfo_proc_map['suid']])
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def gids(self):
|
def gids(self):
|
||||||
real, effective, saved = cext.proc_gids(self.pid)
|
rawtuple = self._get_kinfo_proc()
|
||||||
return _common.pgids(real, effective, saved)
|
return _common.puids(
|
||||||
|
rawtuple[kinfo_proc_map['rgid']],
|
||||||
|
rawtuple[kinfo_proc_map['egid']],
|
||||||
|
rawtuple[kinfo_proc_map['sgid']])
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def terminal(self):
|
def terminal(self):
|
||||||
tty_nr = cext.proc_tty_nr(self.pid)
|
tty_nr = self._get_kinfo_proc()[kinfo_proc_map['ttynr']]
|
||||||
tmap = _psposix._get_terminal_map()
|
tmap = _psposix.get_terminal_map()
|
||||||
try:
|
try:
|
||||||
return tmap[tty_nr]
|
return tmap[tty_nr]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -265,37 +453,52 @@ class Process(object):
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def memory_info(self):
|
def memory_info(self):
|
||||||
rss, vms = cext.proc_memory_info(self.pid)[:2]
|
rawtuple = self._get_pidtaskinfo()
|
||||||
return _common.pmem(rss, vms)
|
return pmem(
|
||||||
|
rawtuple[pidtaskinfo_map['rss']],
|
||||||
|
rawtuple[pidtaskinfo_map['vms']],
|
||||||
|
rawtuple[pidtaskinfo_map['pfaults']],
|
||||||
|
rawtuple[pidtaskinfo_map['pageins']],
|
||||||
|
)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def memory_info_ex(self):
|
def memory_full_info(self):
|
||||||
rss, vms, pfaults, pageins = cext.proc_memory_info(self.pid)
|
basic_mem = self.memory_info()
|
||||||
return pextmem(rss, vms, pfaults * PAGESIZE, pageins * PAGESIZE)
|
uss = cext.proc_memory_uss(self.pid)
|
||||||
|
return pfullmem(*basic_mem + (uss, ))
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def cpu_times(self):
|
def cpu_times(self):
|
||||||
user, system = cext.proc_cpu_times(self.pid)
|
rawtuple = self._get_pidtaskinfo()
|
||||||
return _common.pcputimes(user, system)
|
return _common.pcputimes(
|
||||||
|
rawtuple[pidtaskinfo_map['cpuutime']],
|
||||||
|
rawtuple[pidtaskinfo_map['cpustime']],
|
||||||
|
# children user / system times are not retrievable (set to 0)
|
||||||
|
0.0, 0.0)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def create_time(self):
|
def create_time(self):
|
||||||
return cext.proc_create_time(self.pid)
|
return self._get_kinfo_proc()[kinfo_proc_map['ctime']]
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def num_ctx_switches(self):
|
def num_ctx_switches(self):
|
||||||
return _common.pctxsw(*cext.proc_num_ctx_switches(self.pid))
|
# Unvoluntary value seems not to be available;
|
||||||
|
# getrusage() numbers seems to confirm this theory.
|
||||||
|
# We set it to 0.
|
||||||
|
vol = self._get_pidtaskinfo()[pidtaskinfo_map['volctxsw']]
|
||||||
|
return _common.pctxsw(vol, 0)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def num_threads(self):
|
def num_threads(self):
|
||||||
return cext.proc_num_threads(self.pid)
|
return self._get_pidtaskinfo()[pidtaskinfo_map['numthreads']]
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def open_files(self):
|
def open_files(self):
|
||||||
if self.pid == 0:
|
if self.pid == 0:
|
||||||
return []
|
return []
|
||||||
files = []
|
files = []
|
||||||
rawlist = cext.proc_open_files(self.pid)
|
with catch_zombie(self):
|
||||||
|
rawlist = cext.proc_open_files(self.pid)
|
||||||
for path, fd in rawlist:
|
for path, fd in rawlist:
|
||||||
if isfile_strict(path):
|
if isfile_strict(path):
|
||||||
ntuple = _common.popenfile(path, fd)
|
ntuple = _common.popenfile(path, fd)
|
||||||
|
@ -308,13 +511,19 @@ class Process(object):
|
||||||
raise ValueError("invalid %r kind argument; choose between %s"
|
raise ValueError("invalid %r kind argument; choose between %s"
|
||||||
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
% (kind, ', '.join([repr(x) for x in conn_tmap])))
|
||||||
families, types = conn_tmap[kind]
|
families, types = conn_tmap[kind]
|
||||||
rawlist = cext.proc_connections(self.pid, families, types)
|
with catch_zombie(self):
|
||||||
|
rawlist = cext.proc_connections(self.pid, families, types)
|
||||||
ret = []
|
ret = []
|
||||||
for item in rawlist:
|
for item in rawlist:
|
||||||
fd, fam, type, laddr, raddr, status = item
|
fd, fam, type, laddr, raddr, status = item
|
||||||
status = TCP_STATUSES[status]
|
status = TCP_STATUSES[status]
|
||||||
fam = sockfam_to_enum(fam)
|
fam = sockfam_to_enum(fam)
|
||||||
type = socktype_to_enum(type)
|
type = socktype_to_enum(type)
|
||||||
|
if fam in (AF_INET, AF_INET6):
|
||||||
|
if laddr:
|
||||||
|
laddr = _common.addr(*laddr)
|
||||||
|
if raddr:
|
||||||
|
raddr = _common.addr(*raddr)
|
||||||
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
|
nt = _common.pconn(fd, fam, type, laddr, raddr, status)
|
||||||
ret.append(nt)
|
ret.append(nt)
|
||||||
return ret
|
return ret
|
||||||
|
@ -323,35 +532,33 @@ class Process(object):
|
||||||
def num_fds(self):
|
def num_fds(self):
|
||||||
if self.pid == 0:
|
if self.pid == 0:
|
||||||
return 0
|
return 0
|
||||||
return cext.proc_num_fds(self.pid)
|
with catch_zombie(self):
|
||||||
|
return cext.proc_num_fds(self.pid)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def wait(self, timeout=None):
|
def wait(self, timeout=None):
|
||||||
try:
|
return _psposix.wait_pid(self.pid, timeout, self._name)
|
||||||
return _psposix.wait_pid(self.pid, timeout)
|
|
||||||
except _psposix.TimeoutExpired:
|
|
||||||
# support for private module import
|
|
||||||
if TimeoutExpired is None:
|
|
||||||
raise
|
|
||||||
raise TimeoutExpired(timeout, self.pid, self._name)
|
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def nice_get(self):
|
def nice_get(self):
|
||||||
return cext_posix.getpriority(self.pid)
|
with catch_zombie(self):
|
||||||
|
return cext_posix.getpriority(self.pid)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def nice_set(self, value):
|
def nice_set(self, value):
|
||||||
return cext_posix.setpriority(self.pid, value)
|
with catch_zombie(self):
|
||||||
|
return cext_posix.setpriority(self.pid, value)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def status(self):
|
def status(self):
|
||||||
code = cext.proc_status(self.pid)
|
code = self._get_kinfo_proc()[kinfo_proc_map['status']]
|
||||||
# XXX is '?' legit? (we're not supposed to return it anyway)
|
# XXX is '?' legit? (we're not supposed to return it anyway)
|
||||||
return PROC_STATUSES.get(code, '?')
|
return PROC_STATUSES.get(code, '?')
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def threads(self):
|
def threads(self):
|
||||||
rawlist = cext.proc_threads(self.pid)
|
with catch_zombie(self):
|
||||||
|
rawlist = cext.proc_threads(self.pid)
|
||||||
retlist = []
|
retlist = []
|
||||||
for thread_id, utime, stime in rawlist:
|
for thread_id, utime, stime in rawlist:
|
||||||
ntuple = _common.pthread(thread_id, utime, stime)
|
ntuple = _common.pthread(thread_id, utime, stime)
|
||||||
|
@ -360,4 +567,5 @@ class Process(object):
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def memory_maps(self):
|
def memory_maps(self):
|
||||||
return cext.proc_memory_maps(self.pid)
|
with catch_zombie(self):
|
||||||
|
return cext.proc_memory_maps(self.pid)
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||||
# Use of this source code is governed by a BSD-style license that can be
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
# found in the LICENSE file.
|
# found in the LICENSE file.
|
||||||
|
@ -12,12 +10,15 @@ import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from ._common import sdiskusage, usage_percent, memoize
|
from ._common import memoize
|
||||||
from ._compat import PY3, unicode
|
from ._common import sdiskusage
|
||||||
|
from ._common import usage_percent
|
||||||
|
from ._compat import PY3
|
||||||
|
from ._compat import unicode
|
||||||
|
from ._exceptions import TimeoutExpired
|
||||||
|
|
||||||
|
|
||||||
class TimeoutExpired(Exception):
|
__all__ = ['pid_exists', 'wait_pid', 'disk_usage', 'get_terminal_map']
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def pid_exists(pid):
|
def pid_exists(pid):
|
||||||
|
@ -48,7 +49,7 @@ def pid_exists(pid):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def wait_pid(pid, timeout=None):
|
def wait_pid(pid, timeout=None, proc_name=None):
|
||||||
"""Wait for process with pid 'pid' to terminate and return its
|
"""Wait for process with pid 'pid' to terminate and return its
|
||||||
exit status code as an integer.
|
exit status code as an integer.
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@ def wait_pid(pid, timeout=None):
|
||||||
def check_timeout(delay):
|
def check_timeout(delay):
|
||||||
if timeout is not None:
|
if timeout is not None:
|
||||||
if timer() >= stop_at:
|
if timer() >= stop_at:
|
||||||
raise TimeoutExpired()
|
raise TimeoutExpired(timeout, pid=pid, name=proc_name)
|
||||||
time.sleep(delay)
|
time.sleep(delay)
|
||||||
return min(delay * 2, 0.04)
|
return min(delay * 2, 0.04)
|
||||||
|
|
||||||
|
@ -105,49 +106,74 @@ def wait_pid(pid, timeout=None):
|
||||||
# process exited due to a signal; return the integer of
|
# process exited due to a signal; return the integer of
|
||||||
# that signal
|
# that signal
|
||||||
if os.WIFSIGNALED(status):
|
if os.WIFSIGNALED(status):
|
||||||
return os.WTERMSIG(status)
|
return -os.WTERMSIG(status)
|
||||||
# process exited using exit(2) system call; return the
|
# process exited using exit(2) system call; return the
|
||||||
# integer exit(2) system call has been called with
|
# integer exit(2) system call has been called with
|
||||||
elif os.WIFEXITED(status):
|
elif os.WIFEXITED(status):
|
||||||
return os.WEXITSTATUS(status)
|
return os.WEXITSTATUS(status)
|
||||||
else:
|
else:
|
||||||
# should never happen
|
# should never happen
|
||||||
raise RuntimeError("unknown process exit status")
|
raise ValueError("unknown process exit status %r" % status)
|
||||||
|
|
||||||
|
|
||||||
def disk_usage(path):
|
def disk_usage(path):
|
||||||
"""Return disk usage associated with path."""
|
"""Return disk usage associated with path.
|
||||||
try:
|
Note: UNIX usually reserves 5% disk space which is not accessible
|
||||||
|
by user. In this function "total" and "used" values reflect the
|
||||||
|
total and used disk space whereas "free" and "percent" represent
|
||||||
|
the "free" and "used percent" user disk space.
|
||||||
|
"""
|
||||||
|
if PY3:
|
||||||
st = os.statvfs(path)
|
st = os.statvfs(path)
|
||||||
except UnicodeEncodeError:
|
else:
|
||||||
if not PY3 and isinstance(path, unicode):
|
# os.statvfs() does not support unicode on Python 2:
|
||||||
# this is a bug with os.statvfs() and unicode on
|
# - https://github.com/giampaolo/psutil/issues/416
|
||||||
# Python 2, see:
|
# - http://bugs.python.org/issue18695
|
||||||
# - https://github.com/giampaolo/psutil/issues/416
|
try:
|
||||||
# - http://bugs.python.org/issue18695
|
|
||||||
try:
|
|
||||||
path = path.encode(sys.getfilesystemencoding())
|
|
||||||
except UnicodeEncodeError:
|
|
||||||
pass
|
|
||||||
st = os.statvfs(path)
|
st = os.statvfs(path)
|
||||||
else:
|
except UnicodeEncodeError:
|
||||||
raise
|
if isinstance(path, unicode):
|
||||||
free = (st.f_bavail * st.f_frsize)
|
try:
|
||||||
|
path = path.encode(sys.getfilesystemencoding())
|
||||||
|
except UnicodeEncodeError:
|
||||||
|
pass
|
||||||
|
st = os.statvfs(path)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
# Total space which is only available to root (unless changed
|
||||||
|
# at system level).
|
||||||
total = (st.f_blocks * st.f_frsize)
|
total = (st.f_blocks * st.f_frsize)
|
||||||
used = (st.f_blocks - st.f_bfree) * st.f_frsize
|
# Remaining free space usable by root.
|
||||||
percent = usage_percent(used, total, _round=1)
|
avail_to_root = (st.f_bfree * st.f_frsize)
|
||||||
|
# Remaining free space usable by user.
|
||||||
|
avail_to_user = (st.f_bavail * st.f_frsize)
|
||||||
|
# Total space being used in general.
|
||||||
|
used = (total - avail_to_root)
|
||||||
|
# Total space which is available to user (same as 'total' but
|
||||||
|
# for the user).
|
||||||
|
total_user = used + avail_to_user
|
||||||
|
# User usage percent compared to the total amount of space
|
||||||
|
# the user can use. This number would be higher if compared
|
||||||
|
# to root's because the user has less space (usually -5%).
|
||||||
|
usage_percent_user = usage_percent(used, total_user, _round=1)
|
||||||
|
|
||||||
# NB: the percentage is -5% than what shown by df due to
|
# NB: the percentage is -5% than what shown by df due to
|
||||||
# reserved blocks that we are currently not considering:
|
# reserved blocks that we are currently not considering:
|
||||||
# http://goo.gl/sWGbH
|
# https://github.com/giampaolo/psutil/issues/829#issuecomment-223750462
|
||||||
return sdiskusage(total, used, free, percent)
|
return sdiskusage(
|
||||||
|
total=total, used=used, free=avail_to_user, percent=usage_percent_user)
|
||||||
|
|
||||||
|
|
||||||
@memoize
|
@memoize
|
||||||
def _get_terminal_map():
|
def get_terminal_map():
|
||||||
|
"""Get a map of device-id -> path as a dict.
|
||||||
|
Used by Process.terminal()
|
||||||
|
"""
|
||||||
ret = {}
|
ret = {}
|
||||||
ls = glob.glob('/dev/tty*') + glob.glob('/dev/pts/*')
|
ls = glob.glob('/dev/tty*') + glob.glob('/dev/pts/*')
|
||||||
for name in ls:
|
for name in ls:
|
||||||
assert name not in ret
|
assert name not in ret, name
|
||||||
try:
|
try:
|
||||||
ret[os.stat(name).st_rdev] = name
|
ret[os.stat(name).st_rdev] = name
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||||
# Use of this source code is governed by a BSD-style license that can be
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
# found in the LICENSE file.
|
# found in the LICENSE file.
|
||||||
|
@ -12,20 +10,36 @@ import socket
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from socket import AF_INET
|
||||||
|
|
||||||
from . import _common
|
from . import _common
|
||||||
from . import _psposix
|
from . import _psposix
|
||||||
from . import _psutil_posix as cext_posix
|
from . import _psutil_posix as cext_posix
|
||||||
from . import _psutil_sunos as cext
|
from . import _psutil_sunos as cext
|
||||||
from ._common import isfile_strict, socktype_to_enum, sockfam_to_enum
|
from ._common import AF_INET6
|
||||||
|
from ._common import isfile_strict
|
||||||
|
from ._common import memoize_when_activated
|
||||||
|
from ._common import sockfam_to_enum
|
||||||
|
from ._common import socktype_to_enum
|
||||||
from ._common import usage_percent
|
from ._common import usage_percent
|
||||||
|
from ._compat import b
|
||||||
from ._compat import PY3
|
from ._compat import PY3
|
||||||
|
from ._exceptions import AccessDenied
|
||||||
|
from ._exceptions import NoSuchProcess
|
||||||
|
from ._exceptions import ZombieProcess
|
||||||
|
|
||||||
|
|
||||||
__extra__all__ = ["CONN_IDLE", "CONN_BOUND"]
|
__extra__all__ = ["CONN_IDLE", "CONN_BOUND", "PROCFS_PATH"]
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- globals
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
PAGE_SIZE = os.sysconf('SC_PAGE_SIZE')
|
PAGE_SIZE = os.sysconf('SC_PAGE_SIZE')
|
||||||
AF_LINK = cext_posix.AF_LINK
|
AF_LINK = cext_posix.AF_LINK
|
||||||
|
IS_64_BIT = sys.maxsize > 2**32
|
||||||
|
|
||||||
CONN_IDLE = "IDLE"
|
CONN_IDLE = "IDLE"
|
||||||
CONN_BOUND = "BOUND"
|
CONN_BOUND = "BOUND"
|
||||||
|
@ -57,29 +71,58 @@ TCP_STATUSES = {
|
||||||
cext.TCPS_BOUND: CONN_BOUND, # sunos specific
|
cext.TCPS_BOUND: CONN_BOUND, # sunos specific
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proc_info_map = dict(
|
||||||
|
ppid=0,
|
||||||
|
rss=1,
|
||||||
|
vms=2,
|
||||||
|
create_time=3,
|
||||||
|
nice=4,
|
||||||
|
num_threads=5,
|
||||||
|
status=6,
|
||||||
|
ttynr=7)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- named tuples
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
# psutil.cpu_times()
|
||||||
scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait'])
|
scputimes = namedtuple('scputimes', ['user', 'system', 'idle', 'iowait'])
|
||||||
|
# psutil.cpu_times(percpu=True)
|
||||||
|
pcputimes = namedtuple('pcputimes',
|
||||||
|
['user', 'system', 'children_user', 'children_system'])
|
||||||
|
# psutil.virtual_memory()
|
||||||
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
|
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
|
||||||
pextmem = namedtuple('pextmem', ['rss', 'vms'])
|
# psutil.Process.memory_info()
|
||||||
pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss', 'anon', 'locked'])
|
pmem = namedtuple('pmem', ['rss', 'vms'])
|
||||||
|
pfullmem = pmem
|
||||||
|
# psutil.Process.memory_maps(grouped=True)
|
||||||
|
pmmap_grouped = namedtuple('pmmap_grouped',
|
||||||
|
['path', 'rss', 'anonymous', 'locked'])
|
||||||
|
# psutil.Process.memory_maps(grouped=False)
|
||||||
pmmap_ext = namedtuple(
|
pmmap_ext = namedtuple(
|
||||||
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
|
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
|
||||||
|
|
||||||
# set later from __init__.py
|
|
||||||
NoSuchProcess = None
|
|
||||||
ZombieProcess = None
|
|
||||||
AccessDenied = None
|
|
||||||
TimeoutExpired = None
|
|
||||||
|
|
||||||
# --- functions
|
# =====================================================================
|
||||||
|
# --- utils
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
disk_io_counters = cext.disk_io_counters
|
|
||||||
net_io_counters = cext.net_io_counters
|
def get_procfs_path():
|
||||||
disk_usage = _psposix.disk_usage
|
"""Return updated psutil.PROCFS_PATH constant."""
|
||||||
net_if_addrs = cext_posix.net_if_addrs
|
return sys.modules['psutil'].PROCFS_PATH
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- memory
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
def virtual_memory():
|
def virtual_memory():
|
||||||
# we could have done this with kstat, but imho this is good enough
|
"""Report virtual memory metrics."""
|
||||||
|
# we could have done this with kstat, but IMHO this is good enough
|
||||||
total = os.sysconf('SC_PHYS_PAGES') * PAGE_SIZE
|
total = os.sysconf('SC_PHYS_PAGES') * PAGE_SIZE
|
||||||
# note: there's no difference on Solaris
|
# note: there's no difference on Solaris
|
||||||
free = avail = os.sysconf('SC_AVPHYS_PAGES') * PAGE_SIZE
|
free = avail = os.sysconf('SC_AVPHYS_PAGES') * PAGE_SIZE
|
||||||
|
@ -89,6 +132,7 @@ def virtual_memory():
|
||||||
|
|
||||||
|
|
||||||
def swap_memory():
|
def swap_memory():
|
||||||
|
"""Report swap memory metrics."""
|
||||||
sin, sout = cext.swap_mem()
|
sin, sout = cext.swap_mem()
|
||||||
# XXX
|
# XXX
|
||||||
# we are supposed to get total/free by doing so:
|
# we are supposed to get total/free by doing so:
|
||||||
|
@ -97,13 +141,13 @@ def swap_memory():
|
||||||
# ...nevertheless I can't manage to obtain the same numbers as 'swap'
|
# ...nevertheless I can't manage to obtain the same numbers as 'swap'
|
||||||
# cmdline utility, so let's parse its output (sigh!)
|
# cmdline utility, so let's parse its output (sigh!)
|
||||||
p = subprocess.Popen(['/usr/bin/env', 'PATH=/usr/sbin:/sbin:%s' %
|
p = subprocess.Popen(['/usr/bin/env', 'PATH=/usr/sbin:/sbin:%s' %
|
||||||
os.environ['PATH'], 'swap', '-l', '-k'],
|
os.environ['PATH'], 'swap', '-l'],
|
||||||
stdout=subprocess.PIPE)
|
stdout=subprocess.PIPE)
|
||||||
stdout, stderr = p.communicate()
|
stdout, stderr = p.communicate()
|
||||||
if PY3:
|
if PY3:
|
||||||
stdout = stdout.decode(sys.stdout.encoding)
|
stdout = stdout.decode(sys.stdout.encoding)
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
raise RuntimeError("'swap -l -k' failed (retcode=%s)" % p.returncode)
|
raise RuntimeError("'swap -l' failed (retcode=%s)" % p.returncode)
|
||||||
|
|
||||||
lines = stdout.strip().split('\n')[1:]
|
lines = stdout.strip().split('\n')[1:]
|
||||||
if not lines:
|
if not lines:
|
||||||
|
@ -112,24 +156,17 @@ def swap_memory():
|
||||||
for line in lines:
|
for line in lines:
|
||||||
line = line.split()
|
line = line.split()
|
||||||
t, f = line[-2:]
|
t, f = line[-2:]
|
||||||
t = t.replace('K', '')
|
total += int(int(t) * 512)
|
||||||
f = f.replace('K', '')
|
free += int(int(f) * 512)
|
||||||
total += int(int(t) * 1024)
|
|
||||||
free += int(int(f) * 1024)
|
|
||||||
used = total - free
|
used = total - free
|
||||||
percent = usage_percent(used, total, _round=1)
|
percent = usage_percent(used, total, _round=1)
|
||||||
return _common.sswap(total, used, free, percent,
|
return _common.sswap(total, used, free, percent,
|
||||||
sin * PAGE_SIZE, sout * PAGE_SIZE)
|
sin * PAGE_SIZE, sout * PAGE_SIZE)
|
||||||
|
|
||||||
|
|
||||||
def pids():
|
# =====================================================================
|
||||||
"""Returns a list of PIDs currently running on the system."""
|
# --- CPU
|
||||||
return [int(x) for x in os.listdir('/proc') if x.isdigit()]
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
def pid_exists(pid):
|
|
||||||
"""Check for the existence of a unix pid."""
|
|
||||||
return _psposix.pid_exists(pid)
|
|
||||||
|
|
||||||
|
|
||||||
def cpu_times():
|
def cpu_times():
|
||||||
|
@ -158,28 +195,21 @@ def cpu_count_physical():
|
||||||
return cext.cpu_count_phys()
|
return cext.cpu_count_phys()
|
||||||
|
|
||||||
|
|
||||||
def boot_time():
|
def cpu_stats():
|
||||||
"""The system boot time expressed in seconds since the epoch."""
|
"""Return various CPU stats as a named tuple."""
|
||||||
return cext.boot_time()
|
ctx_switches, interrupts, syscalls, traps = cext.cpu_stats()
|
||||||
|
soft_interrupts = 0
|
||||||
|
return _common.scpustats(ctx_switches, interrupts, soft_interrupts,
|
||||||
|
syscalls)
|
||||||
|
|
||||||
|
|
||||||
def users():
|
# =====================================================================
|
||||||
"""Return currently connected users as a list of namedtuples."""
|
# --- disks
|
||||||
retlist = []
|
# =====================================================================
|
||||||
rawlist = cext.users()
|
|
||||||
localhost = (':0.0', ':0')
|
|
||||||
for item in rawlist:
|
disk_io_counters = cext.disk_io_counters
|
||||||
user, tty, hostname, tstamp, user_process = item
|
disk_usage = _psposix.disk_usage
|
||||||
# note: the underlying C function includes entries about
|
|
||||||
# system boot, run level and others. We might want
|
|
||||||
# to use them in the future.
|
|
||||||
if not user_process:
|
|
||||||
continue
|
|
||||||
if hostname in localhost:
|
|
||||||
hostname = 'localhost'
|
|
||||||
nt = _common.suser(user, tty, hostname, tstamp)
|
|
||||||
retlist.append(nt)
|
|
||||||
return retlist
|
|
||||||
|
|
||||||
|
|
||||||
def disk_partitions(all=False):
|
def disk_partitions(all=False):
|
||||||
|
@ -203,6 +233,15 @@ def disk_partitions(all=False):
|
||||||
return retlist
|
return retlist
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- network
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
net_io_counters = cext.net_io_counters
|
||||||
|
net_if_addrs = cext_posix.net_if_addrs
|
||||||
|
|
||||||
|
|
||||||
def net_connections(kind, _pid=-1):
|
def net_connections(kind, _pid=-1):
|
||||||
"""Return socket connections. If pid == -1 return system-wide
|
"""Return socket connections. If pid == -1 return system-wide
|
||||||
connections (as opposed to connections opened by one process only).
|
connections (as opposed to connections opened by one process only).
|
||||||
|
@ -215,7 +254,7 @@ def net_connections(kind, _pid=-1):
|
||||||
raise ValueError("invalid %r kind argument; choose between %s"
|
raise ValueError("invalid %r kind argument; choose between %s"
|
||||||
% (kind, ', '.join([repr(x) for x in cmap])))
|
% (kind, ', '.join([repr(x) for x in cmap])))
|
||||||
families, types = _common.conn_tmap[kind]
|
families, types = _common.conn_tmap[kind]
|
||||||
rawlist = cext.net_connections(_pid, families, types)
|
rawlist = cext.net_connections(_pid)
|
||||||
ret = set()
|
ret = set()
|
||||||
for item in rawlist:
|
for item in rawlist:
|
||||||
fd, fam, type_, laddr, raddr, status, pid = item
|
fd, fam, type_, laddr, raddr, status, pid = item
|
||||||
|
@ -223,6 +262,11 @@ def net_connections(kind, _pid=-1):
|
||||||
continue
|
continue
|
||||||
if type_ not in types:
|
if type_ not in types:
|
||||||
continue
|
continue
|
||||||
|
if fam in (AF_INET, AF_INET6):
|
||||||
|
if laddr:
|
||||||
|
laddr = _common.addr(*laddr)
|
||||||
|
if raddr:
|
||||||
|
raddr = _common.addr(*raddr)
|
||||||
status = TCP_STATUSES[status]
|
status = TCP_STATUSES[status]
|
||||||
fam = sockfam_to_enum(fam)
|
fam = sockfam_to_enum(fam)
|
||||||
type_ = socktype_to_enum(type_)
|
type_ = socktype_to_enum(type_)
|
||||||
|
@ -245,18 +289,64 @@ def net_if_stats():
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- other system functions
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def boot_time():
|
||||||
|
"""The system boot time expressed in seconds since the epoch."""
|
||||||
|
return cext.boot_time()
|
||||||
|
|
||||||
|
|
||||||
|
def users():
|
||||||
|
"""Return currently connected users as a list of namedtuples."""
|
||||||
|
retlist = []
|
||||||
|
rawlist = cext.users()
|
||||||
|
localhost = (':0.0', ':0')
|
||||||
|
for item in rawlist:
|
||||||
|
user, tty, hostname, tstamp, user_process, pid = item
|
||||||
|
# note: the underlying C function includes entries about
|
||||||
|
# system boot, run level and others. We might want
|
||||||
|
# to use them in the future.
|
||||||
|
if not user_process:
|
||||||
|
continue
|
||||||
|
if hostname in localhost:
|
||||||
|
hostname = 'localhost'
|
||||||
|
nt = _common.suser(user, tty, hostname, tstamp, pid)
|
||||||
|
retlist.append(nt)
|
||||||
|
return retlist
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- processes
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def pids():
|
||||||
|
"""Returns a list of PIDs currently running on the system."""
|
||||||
|
return [int(x) for x in os.listdir(b(get_procfs_path())) if x.isdigit()]
|
||||||
|
|
||||||
|
|
||||||
|
def pid_exists(pid):
|
||||||
|
"""Check for the existence of a unix pid."""
|
||||||
|
return _psposix.pid_exists(pid)
|
||||||
|
|
||||||
|
|
||||||
def wrap_exceptions(fun):
|
def wrap_exceptions(fun):
|
||||||
"""Call callable into a try/except clause and translate ENOENT,
|
"""Call callable into a try/except clause and translate ENOENT,
|
||||||
EACCES and EPERM in NoSuchProcess or AccessDenied exceptions.
|
EACCES and EPERM in NoSuchProcess or AccessDenied exceptions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def wrapper(self, *args, **kwargs):
|
def wrapper(self, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
return fun(self, *args, **kwargs)
|
return fun(self, *args, **kwargs)
|
||||||
except EnvironmentError as err:
|
except EnvironmentError as err:
|
||||||
# support for private module import
|
if self.pid == 0:
|
||||||
if (NoSuchProcess is None or AccessDenied is None or
|
if 0 in pids():
|
||||||
ZombieProcess is None):
|
raise AccessDenied(self.pid, self._name)
|
||||||
raise
|
else:
|
||||||
|
raise
|
||||||
# ENOENT (no such file or directory) gets raised on open().
|
# ENOENT (no such file or directory) gets raised on open().
|
||||||
# ESRCH (no such process) can get raised on read() if
|
# ESRCH (no such process) can get raised on read() if
|
||||||
# process is gone in meantime.
|
# process is gone in meantime.
|
||||||
|
@ -274,21 +364,51 @@ def wrap_exceptions(fun):
|
||||||
class Process(object):
|
class Process(object):
|
||||||
"""Wrapper class around underlying C implementation."""
|
"""Wrapper class around underlying C implementation."""
|
||||||
|
|
||||||
__slots__ = ["pid", "_name", "_ppid"]
|
__slots__ = ["pid", "_name", "_ppid", "_procfs_path"]
|
||||||
|
|
||||||
def __init__(self, pid):
|
def __init__(self, pid):
|
||||||
self.pid = pid
|
self.pid = pid
|
||||||
self._name = None
|
self._name = None
|
||||||
self._ppid = None
|
self._ppid = None
|
||||||
|
self._procfs_path = get_procfs_path()
|
||||||
|
|
||||||
|
def oneshot_enter(self):
|
||||||
|
self._proc_name_and_args.cache_activate()
|
||||||
|
self._proc_basic_info.cache_activate()
|
||||||
|
self._proc_cred.cache_activate()
|
||||||
|
|
||||||
|
def oneshot_exit(self):
|
||||||
|
self._proc_name_and_args.cache_deactivate()
|
||||||
|
self._proc_basic_info.cache_deactivate()
|
||||||
|
self._proc_cred.cache_deactivate()
|
||||||
|
|
||||||
|
@memoize_when_activated
|
||||||
|
def _proc_name_and_args(self):
|
||||||
|
return cext.proc_name_and_args(self.pid, self._procfs_path)
|
||||||
|
|
||||||
|
@memoize_when_activated
|
||||||
|
def _proc_basic_info(self):
|
||||||
|
ret = cext.proc_basic_info(self.pid, self._procfs_path)
|
||||||
|
assert len(ret) == len(proc_info_map)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
@memoize_when_activated
|
||||||
|
def _proc_cred(self):
|
||||||
|
return cext.proc_cred(self.pid, self._procfs_path)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def name(self):
|
def name(self):
|
||||||
# note: max len == 15
|
# note: max len == 15
|
||||||
return cext.proc_name_and_args(self.pid)[0]
|
return self._proc_name_and_args()[0]
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def exe(self):
|
def exe(self):
|
||||||
# Will be guess later from cmdline but we want to explicitly
|
try:
|
||||||
|
return os.readlink(
|
||||||
|
"%s/%s/path/a.out" % (self._procfs_path, self.pid))
|
||||||
|
except OSError:
|
||||||
|
pass # continue and guess the exe name from the cmdline
|
||||||
|
# Will be guessed later from cmdline but we want to explicitly
|
||||||
# invoke cmdline here in order to get an AccessDenied
|
# invoke cmdline here in order to get an AccessDenied
|
||||||
# exception if the user has not enough privileges.
|
# exception if the user has not enough privileges.
|
||||||
self.cmdline()
|
self.cmdline()
|
||||||
|
@ -296,25 +416,34 @@ class Process(object):
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def cmdline(self):
|
def cmdline(self):
|
||||||
return cext.proc_name_and_args(self.pid)[1].split(' ')
|
return self._proc_name_and_args()[1].split(' ')
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def environ(self):
|
||||||
|
return cext.proc_environ(self.pid, self._procfs_path)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def create_time(self):
|
def create_time(self):
|
||||||
return cext.proc_basic_info(self.pid)[3]
|
return self._proc_basic_info()[proc_info_map['create_time']]
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def num_threads(self):
|
def num_threads(self):
|
||||||
return cext.proc_basic_info(self.pid)[5]
|
return self._proc_basic_info()[proc_info_map['num_threads']]
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def nice_get(self):
|
def nice_get(self):
|
||||||
# For some reason getpriority(3) return ESRCH (no such process)
|
# Note #1: for some reason getpriority(3) return ESRCH (no such
|
||||||
# for certain low-pid processes, no matter what (even as root).
|
# process) for certain low-pid processes, no matter what (even
|
||||||
|
# as root).
|
||||||
# The process actually exists though, as it has a name,
|
# The process actually exists though, as it has a name,
|
||||||
# creation time, etc.
|
# creation time, etc.
|
||||||
# The best thing we can do here appears to be raising AD.
|
# The best thing we can do here appears to be raising AD.
|
||||||
# Note: tested on Solaris 11; on Open Solaris 5 everything is
|
# Note: tested on Solaris 11; on Open Solaris 5 everything is
|
||||||
# fine.
|
# fine.
|
||||||
|
#
|
||||||
|
# Note #2: we also can get niceness from /proc/pid/psinfo
|
||||||
|
# but it's wrong, see:
|
||||||
|
# https://github.com/giampaolo/psutil/issues/1082
|
||||||
try:
|
try:
|
||||||
return cext_posix.getpriority(self.pid)
|
return cext_posix.getpriority(self.pid)
|
||||||
except EnvironmentError as err:
|
except EnvironmentError as err:
|
||||||
|
@ -337,32 +466,52 @@ class Process(object):
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def ppid(self):
|
def ppid(self):
|
||||||
return cext.proc_basic_info(self.pid)[0]
|
self._ppid = self._proc_basic_info()[proc_info_map['ppid']]
|
||||||
|
return self._ppid
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def uids(self):
|
def uids(self):
|
||||||
real, effective, saved, _, _, _ = cext.proc_cred(self.pid)
|
real, effective, saved, _, _, _ = self._proc_cred()
|
||||||
return _common.puids(real, effective, saved)
|
return _common.puids(real, effective, saved)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def gids(self):
|
def gids(self):
|
||||||
_, _, _, real, effective, saved = cext.proc_cred(self.pid)
|
_, _, _, real, effective, saved = self._proc_cred()
|
||||||
return _common.puids(real, effective, saved)
|
return _common.puids(real, effective, saved)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def cpu_times(self):
|
def cpu_times(self):
|
||||||
user, system = cext.proc_cpu_times(self.pid)
|
try:
|
||||||
return _common.pcputimes(user, system)
|
times = cext.proc_cpu_times(self.pid, self._procfs_path)
|
||||||
|
except OSError as err:
|
||||||
|
if err.errno == errno.EOVERFLOW and not IS_64_BIT:
|
||||||
|
# We may get here if we attempt to query a 64bit process
|
||||||
|
# with a 32bit python.
|
||||||
|
# Error originates from read() and also tools like "cat"
|
||||||
|
# fail in the same way (!).
|
||||||
|
# Since there simply is no way to determine CPU times we
|
||||||
|
# return 0.0 as a fallback. See:
|
||||||
|
# https://github.com/giampaolo/psutil/issues/857
|
||||||
|
times = (0.0, 0.0, 0.0, 0.0)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
return _common.pcputimes(*times)
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def cpu_num(self):
|
||||||
|
return cext.proc_cpu_num(self.pid, self._procfs_path)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def terminal(self):
|
def terminal(self):
|
||||||
|
procfs_path = self._procfs_path
|
||||||
hit_enoent = False
|
hit_enoent = False
|
||||||
tty = wrap_exceptions(
|
tty = wrap_exceptions(
|
||||||
cext.proc_basic_info(self.pid)[0])
|
self._proc_basic_info()[proc_info_map['ttynr']])
|
||||||
if tty != cext.PRNODEV:
|
if tty != cext.PRNODEV:
|
||||||
for x in (0, 1, 2, 255):
|
for x in (0, 1, 2, 255):
|
||||||
try:
|
try:
|
||||||
return os.readlink('/proc/%d/path/%d' % (self.pid, x))
|
return os.readlink(
|
||||||
|
'%s/%d/path/%d' % (procfs_path, self.pid, x))
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
if err.errno == errno.ENOENT:
|
if err.errno == errno.ENOENT:
|
||||||
hit_enoent = True
|
hit_enoent = True
|
||||||
|
@ -370,7 +519,7 @@ class Process(object):
|
||||||
raise
|
raise
|
||||||
if hit_enoent:
|
if hit_enoent:
|
||||||
# raise NSP if the process disappeared on us
|
# raise NSP if the process disappeared on us
|
||||||
os.stat('/proc/%s' % self.pid)
|
os.stat('%s/%s' % (procfs_path, self.pid))
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def cwd(self):
|
def cwd(self):
|
||||||
|
@ -378,40 +527,51 @@ class Process(object):
|
||||||
# it exists (ls shows it). If that's the case and the process
|
# it exists (ls shows it). If that's the case and the process
|
||||||
# is still alive return None (we can return None also on BSD).
|
# is still alive return None (we can return None also on BSD).
|
||||||
# Reference: http://goo.gl/55XgO
|
# Reference: http://goo.gl/55XgO
|
||||||
|
procfs_path = self._procfs_path
|
||||||
try:
|
try:
|
||||||
return os.readlink("/proc/%s/path/cwd" % self.pid)
|
return os.readlink("%s/%s/path/cwd" % (procfs_path, self.pid))
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
if err.errno == errno.ENOENT:
|
if err.errno == errno.ENOENT:
|
||||||
os.stat("/proc/%s" % self.pid)
|
os.stat("%s/%s" % (procfs_path, self.pid)) # raise NSP or AD
|
||||||
return None
|
return None
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def memory_info(self):
|
def memory_info(self):
|
||||||
ret = cext.proc_basic_info(self.pid)
|
ret = self._proc_basic_info()
|
||||||
rss, vms = ret[1] * 1024, ret[2] * 1024
|
rss = ret[proc_info_map['rss']] * 1024
|
||||||
return _common.pmem(rss, vms)
|
vms = ret[proc_info_map['vms']] * 1024
|
||||||
|
return pmem(rss, vms)
|
||||||
|
|
||||||
# it seems Solaris uses rss and vms only
|
memory_full_info = memory_info
|
||||||
memory_info_ex = memory_info
|
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def status(self):
|
def status(self):
|
||||||
code = cext.proc_basic_info(self.pid)[6]
|
code = self._proc_basic_info()[proc_info_map['status']]
|
||||||
# XXX is '?' legit? (we're not supposed to return it anyway)
|
# XXX is '?' legit? (we're not supposed to return it anyway)
|
||||||
return PROC_STATUSES.get(code, '?')
|
return PROC_STATUSES.get(code, '?')
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def threads(self):
|
def threads(self):
|
||||||
|
procfs_path = self._procfs_path
|
||||||
ret = []
|
ret = []
|
||||||
tids = os.listdir('/proc/%d/lwp' % self.pid)
|
tids = os.listdir('%s/%d/lwp' % (procfs_path, self.pid))
|
||||||
hit_enoent = False
|
hit_enoent = False
|
||||||
for tid in tids:
|
for tid in tids:
|
||||||
tid = int(tid)
|
tid = int(tid)
|
||||||
try:
|
try:
|
||||||
utime, stime = cext.query_process_thread(
|
utime, stime = cext.query_process_thread(
|
||||||
self.pid, tid)
|
self.pid, tid, procfs_path)
|
||||||
except EnvironmentError as err:
|
except EnvironmentError as err:
|
||||||
|
if err.errno == errno.EOVERFLOW and not IS_64_BIT:
|
||||||
|
# We may get here if we attempt to query a 64bit process
|
||||||
|
# with a 32bit python.
|
||||||
|
# Error originates from read() and also tools like "cat"
|
||||||
|
# fail in the same way (!).
|
||||||
|
# Since there simply is no way to determine CPU times we
|
||||||
|
# return 0.0 as a fallback. See:
|
||||||
|
# https://github.com/giampaolo/psutil/issues/857
|
||||||
|
continue
|
||||||
# ENOENT == thread gone in meantime
|
# ENOENT == thread gone in meantime
|
||||||
if err.errno == errno.ENOENT:
|
if err.errno == errno.ENOENT:
|
||||||
hit_enoent = True
|
hit_enoent = True
|
||||||
|
@ -422,15 +582,16 @@ class Process(object):
|
||||||
ret.append(nt)
|
ret.append(nt)
|
||||||
if hit_enoent:
|
if hit_enoent:
|
||||||
# raise NSP if the process disappeared on us
|
# raise NSP if the process disappeared on us
|
||||||
os.stat('/proc/%s' % self.pid)
|
os.stat('%s/%s' % (procfs_path, self.pid))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def open_files(self):
|
def open_files(self):
|
||||||
retlist = []
|
retlist = []
|
||||||
hit_enoent = False
|
hit_enoent = False
|
||||||
pathdir = '/proc/%d/path' % self.pid
|
procfs_path = self._procfs_path
|
||||||
for fd in os.listdir('/proc/%d/fd' % self.pid):
|
pathdir = '%s/%d/path' % (procfs_path, self.pid)
|
||||||
|
for fd in os.listdir('%s/%d/fd' % (procfs_path, self.pid)):
|
||||||
path = os.path.join(pathdir, fd)
|
path = os.path.join(pathdir, fd)
|
||||||
if os.path.islink(path):
|
if os.path.islink(path):
|
||||||
try:
|
try:
|
||||||
|
@ -446,7 +607,7 @@ class Process(object):
|
||||||
retlist.append(_common.popenfile(file, int(fd)))
|
retlist.append(_common.popenfile(file, int(fd)))
|
||||||
if hit_enoent:
|
if hit_enoent:
|
||||||
# raise NSP if the process disappeared on us
|
# raise NSP if the process disappeared on us
|
||||||
os.stat('/proc/%s' % self.pid)
|
os.stat('%s/%s' % (procfs_path, self.pid))
|
||||||
return retlist
|
return retlist
|
||||||
|
|
||||||
def _get_unix_sockets(self, pid):
|
def _get_unix_sockets(self, pid):
|
||||||
|
@ -490,7 +651,8 @@ class Process(object):
|
||||||
# process is no longer active so we force NSP in case the PID
|
# process is no longer active so we force NSP in case the PID
|
||||||
# is no longer there.
|
# is no longer there.
|
||||||
if not ret:
|
if not ret:
|
||||||
os.stat('/proc/%s' % self.pid) # will raise NSP if process is gone
|
# will raise NSP if process is gone
|
||||||
|
os.stat('%s/%s' % (self._procfs_path, self.pid))
|
||||||
|
|
||||||
# UNIX sockets
|
# UNIX sockets
|
||||||
if kind in ('all', 'unix'):
|
if kind in ('all', 'unix'):
|
||||||
|
@ -507,15 +669,30 @@ class Process(object):
|
||||||
return '%s-%s' % (hex(start)[2:].strip('L'),
|
return '%s-%s' % (hex(start)[2:].strip('L'),
|
||||||
hex(end)[2:].strip('L'))
|
hex(end)[2:].strip('L'))
|
||||||
|
|
||||||
|
procfs_path = self._procfs_path
|
||||||
retlist = []
|
retlist = []
|
||||||
rawlist = cext.proc_memory_maps(self.pid)
|
try:
|
||||||
|
rawlist = cext.proc_memory_maps(self.pid, procfs_path)
|
||||||
|
except OSError as err:
|
||||||
|
if err.errno == errno.EOVERFLOW and not IS_64_BIT:
|
||||||
|
# We may get here if we attempt to query a 64bit process
|
||||||
|
# with a 32bit python.
|
||||||
|
# Error originates from read() and also tools like "cat"
|
||||||
|
# fail in the same way (!).
|
||||||
|
# Since there simply is no way to determine CPU times we
|
||||||
|
# return 0.0 as a fallback. See:
|
||||||
|
# https://github.com/giampaolo/psutil/issues/857
|
||||||
|
return []
|
||||||
|
else:
|
||||||
|
raise
|
||||||
hit_enoent = False
|
hit_enoent = False
|
||||||
for item in rawlist:
|
for item in rawlist:
|
||||||
addr, addrsize, perm, name, rss, anon, locked = item
|
addr, addrsize, perm, name, rss, anon, locked = item
|
||||||
addr = toaddr(addr, addrsize)
|
addr = toaddr(addr, addrsize)
|
||||||
if not name.startswith('['):
|
if not name.startswith('['):
|
||||||
try:
|
try:
|
||||||
name = os.readlink('/proc/%s/path/%s' % (self.pid, name))
|
name = os.readlink(
|
||||||
|
'%s/%s/path/%s' % (procfs_path, self.pid, name))
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
if err.errno == errno.ENOENT:
|
if err.errno == errno.ENOENT:
|
||||||
# sometimes the link may not be resolved by
|
# sometimes the link may not be resolved by
|
||||||
|
@ -524,30 +701,25 @@ class Process(object):
|
||||||
# unresolved link path.
|
# unresolved link path.
|
||||||
# This seems an incosistency with /proc similar
|
# This seems an incosistency with /proc similar
|
||||||
# to: http://goo.gl/55XgO
|
# to: http://goo.gl/55XgO
|
||||||
name = '/proc/%s/path/%s' % (self.pid, name)
|
name = '%s/%s/path/%s' % (procfs_path, self.pid, name)
|
||||||
hit_enoent = True
|
hit_enoent = True
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
retlist.append((addr, perm, name, rss, anon, locked))
|
retlist.append((addr, perm, name, rss, anon, locked))
|
||||||
if hit_enoent:
|
if hit_enoent:
|
||||||
# raise NSP if the process disappeared on us
|
# raise NSP if the process disappeared on us
|
||||||
os.stat('/proc/%s' % self.pid)
|
os.stat('%s/%s' % (procfs_path, self.pid))
|
||||||
return retlist
|
return retlist
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def num_fds(self):
|
def num_fds(self):
|
||||||
return len(os.listdir("/proc/%s/fd" % self.pid))
|
return len(os.listdir("%s/%s/fd" % (self._procfs_path, self.pid)))
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def num_ctx_switches(self):
|
def num_ctx_switches(self):
|
||||||
return _common.pctxsw(*cext.proc_num_ctx_switches(self.pid))
|
return _common.pctxsw(
|
||||||
|
*cext.proc_num_ctx_switches(self.pid, self._procfs_path))
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def wait(self, timeout=None):
|
def wait(self, timeout=None):
|
||||||
try:
|
return _psposix.wait_pid(self.pid, timeout, self._name)
|
||||||
return _psposix.wait_pid(self.pid, timeout)
|
|
||||||
except _psposix.TimeoutExpired:
|
|
||||||
# support for private module import
|
|
||||||
if TimeoutExpired is None:
|
|
||||||
raise
|
|
||||||
raise TimeoutExpired(timeout, self.pid, self._name)
|
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <Python.h>
|
|
||||||
|
|
||||||
// --- per-process functions
|
|
||||||
|
|
||||||
static PyObject* psutil_proc_cmdline(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_connections(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_cpu_times(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_create_time(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_exe(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_gids(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_io_counters(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_memory_info(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_name(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_num_ctx_switches(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_num_fds(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_ppid(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_status(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_threads(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_tty_nr(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_uids(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args);
|
|
||||||
|
|
||||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
|
|
||||||
static PyObject* psutil_proc_open_files(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_cwd(PyObject* self, PyObject* args);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// --- system-related functions
|
|
||||||
|
|
||||||
static PyObject* psutil_boot_time(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_cpu_count_logical(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_cpu_times(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_net_io_counters(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_pids(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_swap_mem(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_users(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_virtual_mem(PyObject* self, PyObject* args);
|
|
||||||
|
|
||||||
#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000
|
|
||||||
static PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args);
|
|
||||||
#endif
|
|
|
@ -7,16 +7,43 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Global vars.
|
||||||
|
int PSUTIL_DEBUG = 0;
|
||||||
|
int PSUTIL_TESTING = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Backport of unicode FS APIs from Python 3.
|
||||||
|
* On Python 2 we just return a plain byte string
|
||||||
|
* which is never supposed to raise decoding errors.
|
||||||
|
* See: https://github.com/giampaolo/psutil/issues/1040
|
||||||
|
*/
|
||||||
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
PyObject *
|
||||||
|
PyUnicode_DecodeFSDefault(char *s) {
|
||||||
|
return PyString_FromString(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
PyUnicode_DecodeFSDefaultAndSize(char *s, Py_ssize_t size) {
|
||||||
|
return PyString_FromStringAndSize(s, size);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set OSError(errno=ESRCH, strerror="No such process") Python exception.
|
* Set OSError(errno=ESRCH, strerror="No such process") Python exception.
|
||||||
|
* If msg != "" the exception message will change in accordance.
|
||||||
*/
|
*/
|
||||||
PyObject *
|
PyObject *
|
||||||
NoSuchProcess(void) {
|
NoSuchProcess(char *msg) {
|
||||||
PyObject *exc;
|
PyObject *exc;
|
||||||
char *msg = strerror(ESRCH);
|
exc = PyObject_CallFunction(
|
||||||
exc = PyObject_CallFunction(PyExc_OSError, "(is)", ESRCH, msg);
|
PyExc_OSError, "(is)", ESRCH, strlen(msg) ? msg : strerror(ESRCH));
|
||||||
PyErr_SetObject(PyExc_OSError, exc);
|
PyErr_SetObject(PyExc_OSError, exc);
|
||||||
Py_XDECREF(exc);
|
Py_XDECREF(exc);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -25,13 +52,53 @@ NoSuchProcess(void) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set OSError(errno=EACCES, strerror="Permission denied") Python exception.
|
* Set OSError(errno=EACCES, strerror="Permission denied") Python exception.
|
||||||
|
* If msg != "" the exception message will change in accordance.
|
||||||
*/
|
*/
|
||||||
PyObject *
|
PyObject *
|
||||||
AccessDenied(void) {
|
AccessDenied(char *msg) {
|
||||||
PyObject *exc;
|
PyObject *exc;
|
||||||
char *msg = strerror(EACCES);
|
exc = PyObject_CallFunction(
|
||||||
exc = PyObject_CallFunction(PyExc_OSError, "(is)", EACCES, msg);
|
PyExc_OSError, "(is)", EACCES, strlen(msg) ? msg : strerror(EACCES));
|
||||||
PyErr_SetObject(PyExc_OSError, exc);
|
PyErr_SetObject(PyExc_OSError, exc);
|
||||||
Py_XDECREF(exc);
|
Py_XDECREF(exc);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable testing mode. This has the same effect as setting PSUTIL_TESTING
|
||||||
|
* env var. This dual method exists because updating os.environ on
|
||||||
|
* Windows has no effect. Called on unit tests setup.
|
||||||
|
*/
|
||||||
|
PyObject *
|
||||||
|
psutil_set_testing(PyObject *self, PyObject *args) {
|
||||||
|
PSUTIL_TESTING = 1;
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print a debug message on stderr. No-op if PSUTIL_DEBUG env var is not set.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
psutil_debug(const char* format, ...) {
|
||||||
|
va_list argptr;
|
||||||
|
va_start(argptr, format);
|
||||||
|
fprintf(stderr, "psutil-dubug> ");
|
||||||
|
vfprintf(stderr, format, argptr);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
va_end(argptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Called on module import on all platforms.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
psutil_setup(void) {
|
||||||
|
if (getenv("PSUTIL_DEBUG") != NULL)
|
||||||
|
PSUTIL_DEBUG = 1;
|
||||||
|
if (getenv("PSUTIL_TESTING") != NULL)
|
||||||
|
PSUTIL_TESTING = 1;
|
||||||
|
}
|
||||||
|
|
|
@ -6,5 +6,20 @@
|
||||||
|
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
|
|
||||||
PyObject* AccessDenied(void);
|
extern int PSUTIL_TESTING;
|
||||||
PyObject* NoSuchProcess(void);
|
extern int PSUTIL_DEBUG;
|
||||||
|
|
||||||
|
// a signaler for connections without an actual status
|
||||||
|
static const int PSUTIL_CONN_NONE = 128;
|
||||||
|
|
||||||
|
#if PY_MAJOR_VERSION < 3
|
||||||
|
PyObject* PyUnicode_DecodeFSDefault(char *s);
|
||||||
|
PyObject* PyUnicode_DecodeFSDefaultAndSize(char *s, Py_ssize_t size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PyObject* AccessDenied(char *msg);
|
||||||
|
PyObject* NoSuchProcess(char *msg);
|
||||||
|
|
||||||
|
PyObject* psutil_set_testing(PyObject *self, PyObject *args);
|
||||||
|
void psutil_debug(const char* format, ...);
|
||||||
|
void psutil_setup(void);
|
||||||
|
|
|
@ -23,9 +23,18 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <linux/sockios.h>
|
#include <linux/sockios.h>
|
||||||
#include <linux/if.h>
|
#include <linux/if.h>
|
||||||
#include <linux/ethtool.h>
|
|
||||||
|
|
||||||
#include "_psutil_linux.h"
|
// see: https://github.com/giampaolo/psutil/issues/659
|
||||||
|
#ifdef PSUTIL_ETHTOOL_MISSING_TYPES
|
||||||
|
#include <linux/types.h>
|
||||||
|
typedef __u64 u64;
|
||||||
|
typedef __u32 u32;
|
||||||
|
typedef __u16 u16;
|
||||||
|
typedef __u8 u8;
|
||||||
|
#endif
|
||||||
|
/* Avoid redefinition of struct sysinfo with musl libc */
|
||||||
|
#define _LINUX_SYSINFO_H
|
||||||
|
#include <linux/ethtool.h>
|
||||||
|
|
||||||
/* The minimum number of CPUs allocated in a cpu_set_t */
|
/* The minimum number of CPUs allocated in a cpu_set_t */
|
||||||
static const int NCPUS_START = sizeof(unsigned long) * CHAR_BIT;
|
static const int NCPUS_START = sizeof(unsigned long) * CHAR_BIT;
|
||||||
|
@ -45,11 +54,8 @@ static const int NCPUS_START = sizeof(unsigned long) * CHAR_BIT;
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "_psutil_common.h"
|
||||||
#if PSUTIL_HAVE_IOPRIO
|
#include "_psutil_posix.h"
|
||||||
enum {
|
|
||||||
IOPRIO_WHO_PROCESS = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
// May happen on old RedHat versions, see:
|
// May happen on old RedHat versions, see:
|
||||||
// https://github.com/giampaolo/psutil/issues/607
|
// https://github.com/giampaolo/psutil/issues/607
|
||||||
|
@ -57,15 +63,19 @@ enum {
|
||||||
#define DUPLEX_UNKNOWN 0xff
|
#define DUPLEX_UNKNOWN 0xff
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if PSUTIL_HAVE_IOPRIO
|
||||||
|
enum {
|
||||||
|
IOPRIO_WHO_PROCESS = 1,
|
||||||
|
};
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
ioprio_get(int which, int who)
|
ioprio_get(int which, int who) {
|
||||||
{
|
|
||||||
return syscall(__NR_ioprio_get, which, who);
|
return syscall(__NR_ioprio_get, which, who);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
ioprio_set(int which, int who, int ioprio)
|
ioprio_set(int which, int who, int ioprio) {
|
||||||
{
|
|
||||||
return syscall(__NR_ioprio_set, which, who, ioprio);
|
return syscall(__NR_ioprio_set, which, who, ioprio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,8 +91,7 @@ ioprio_set(int which, int who, int ioprio)
|
||||||
* Return a (ioclass, iodata) Python tuple representing process I/O priority.
|
* Return a (ioclass, iodata) Python tuple representing process I/O priority.
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psutil_proc_ioprio_get(PyObject *self, PyObject *args)
|
psutil_proc_ioprio_get(PyObject *self, PyObject *args) {
|
||||||
{
|
|
||||||
long pid;
|
long pid;
|
||||||
int ioprio, ioclass, iodata;
|
int ioprio, ioclass, iodata;
|
||||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||||
|
@ -102,8 +111,7 @@ psutil_proc_ioprio_get(PyObject *self, PyObject *args)
|
||||||
* or 0. iodata goes from 0 to 7 depending on ioclass specified.
|
* or 0. iodata goes from 0 to 7 depending on ioclass specified.
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psutil_proc_ioprio_set(PyObject *self, PyObject *args)
|
psutil_proc_ioprio_set(PyObject *self, PyObject *args) {
|
||||||
{
|
|
||||||
long pid;
|
long pid;
|
||||||
int ioprio, ioclass, iodata;
|
int ioprio, ioclass, iodata;
|
||||||
int retval;
|
int retval;
|
||||||
|
@ -126,20 +134,19 @@ psutil_proc_ioprio_set(PyObject *self, PyObject *args)
|
||||||
* 'soft' and 'hard' args must be provided.
|
* 'soft' and 'hard' args must be provided.
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psutil_linux_prlimit(PyObject *self, PyObject *args)
|
psutil_linux_prlimit(PyObject *self, PyObject *args) {
|
||||||
{
|
|
||||||
long pid;
|
long pid;
|
||||||
int ret, resource;
|
int ret, resource;
|
||||||
struct rlimit old, new;
|
struct rlimit old, new;
|
||||||
struct rlimit *newp = NULL;
|
struct rlimit *newp = NULL;
|
||||||
PyObject *soft = NULL;
|
PyObject *py_soft = NULL;
|
||||||
PyObject *hard = NULL;
|
PyObject *py_hard = NULL;
|
||||||
|
|
||||||
if (! PyArg_ParseTuple(args, "li|OO", &pid, &resource, &soft, &hard))
|
if (! PyArg_ParseTuple(args, "li|OO", &pid, &resource, &py_soft, &py_hard))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// get
|
// get
|
||||||
if (soft == NULL && hard == NULL) {
|
if (py_soft == NULL && py_hard == NULL) {
|
||||||
ret = prlimit(pid, resource, NULL, &old);
|
ret = prlimit(pid, resource, NULL, &old);
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
return PyErr_SetFromErrno(PyExc_OSError);
|
return PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
@ -156,17 +163,17 @@ psutil_linux_prlimit(PyObject *self, PyObject *args)
|
||||||
// set
|
// set
|
||||||
else {
|
else {
|
||||||
#if defined(PSUTIL_HAVE_LARGEFILE_SUPPORT)
|
#if defined(PSUTIL_HAVE_LARGEFILE_SUPPORT)
|
||||||
new.rlim_cur = PyLong_AsLongLong(soft);
|
new.rlim_cur = PyLong_AsLongLong(py_soft);
|
||||||
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
|
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
|
||||||
return NULL;
|
return NULL;
|
||||||
new.rlim_max = PyLong_AsLongLong(hard);
|
new.rlim_max = PyLong_AsLongLong(py_hard);
|
||||||
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
|
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
|
||||||
return NULL;
|
return NULL;
|
||||||
#else
|
#else
|
||||||
new.rlim_cur = PyLong_AsLong(soft);
|
new.rlim_cur = PyLong_AsLong(py_soft);
|
||||||
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
|
if (new.rlim_cur == (rlim_t) - 1 && PyErr_Occurred())
|
||||||
return NULL;
|
return NULL;
|
||||||
new.rlim_max = PyLong_AsLong(hard);
|
new.rlim_max = PyLong_AsLong(py_hard);
|
||||||
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
|
if (new.rlim_max == (rlim_t) - 1 && PyErr_Occurred())
|
||||||
return NULL;
|
return NULL;
|
||||||
#endif
|
#endif
|
||||||
|
@ -185,12 +192,13 @@ psutil_linux_prlimit(PyObject *self, PyObject *args)
|
||||||
* mount point and filesystem type
|
* mount point and filesystem type
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psutil_disk_partitions(PyObject *self, PyObject *args)
|
psutil_disk_partitions(PyObject *self, PyObject *args) {
|
||||||
{
|
|
||||||
FILE *file = NULL;
|
FILE *file = NULL;
|
||||||
struct mntent *entry;
|
struct mntent *entry;
|
||||||
PyObject *py_retlist = PyList_New(0);
|
PyObject *py_dev = NULL;
|
||||||
|
PyObject *py_mountp = NULL;
|
||||||
PyObject *py_tuple = NULL;
|
PyObject *py_tuple = NULL;
|
||||||
|
PyObject *py_retlist = PyList_New(0);
|
||||||
|
|
||||||
if (py_retlist == NULL)
|
if (py_retlist == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -206,18 +214,26 @@ psutil_disk_partitions(PyObject *self, PyObject *args)
|
||||||
|
|
||||||
while ((entry = getmntent(file))) {
|
while ((entry = getmntent(file))) {
|
||||||
if (entry == NULL) {
|
if (entry == NULL) {
|
||||||
PyErr_Format(PyExc_RuntimeError, "getmntent() failed");
|
PyErr_Format(PyExc_RuntimeError, "getmntent() syscall failed");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
py_tuple = Py_BuildValue("(ssss)",
|
py_dev = PyUnicode_DecodeFSDefault(entry->mnt_fsname);
|
||||||
entry->mnt_fsname, // device
|
if (! py_dev)
|
||||||
entry->mnt_dir, // mount point
|
goto error;
|
||||||
|
py_mountp = PyUnicode_DecodeFSDefault(entry->mnt_dir);
|
||||||
|
if (! py_mountp)
|
||||||
|
goto error;
|
||||||
|
py_tuple = Py_BuildValue("(OOss)",
|
||||||
|
py_dev, // device
|
||||||
|
py_mountp, // mount point
|
||||||
entry->mnt_type, // fs type
|
entry->mnt_type, // fs type
|
||||||
entry->mnt_opts); // options
|
entry->mnt_opts); // options
|
||||||
if (! py_tuple)
|
if (! py_tuple)
|
||||||
goto error;
|
goto error;
|
||||||
if (PyList_Append(py_retlist, py_tuple))
|
if (PyList_Append(py_retlist, py_tuple))
|
||||||
goto error;
|
goto error;
|
||||||
|
Py_DECREF(py_dev);
|
||||||
|
Py_DECREF(py_mountp);
|
||||||
Py_DECREF(py_tuple);
|
Py_DECREF(py_tuple);
|
||||||
}
|
}
|
||||||
endmntent(file);
|
endmntent(file);
|
||||||
|
@ -226,6 +242,8 @@ psutil_disk_partitions(PyObject *self, PyObject *args)
|
||||||
error:
|
error:
|
||||||
if (file != NULL)
|
if (file != NULL)
|
||||||
endmntent(file);
|
endmntent(file);
|
||||||
|
Py_XDECREF(py_dev);
|
||||||
|
Py_XDECREF(py_mountp);
|
||||||
Py_XDECREF(py_tuple);
|
Py_XDECREF(py_tuple);
|
||||||
Py_DECREF(py_retlist);
|
Py_DECREF(py_retlist);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -236,21 +254,22 @@ error:
|
||||||
* A wrapper around sysinfo(), return system memory usage statistics.
|
* A wrapper around sysinfo(), return system memory usage statistics.
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psutil_linux_sysinfo(PyObject *self, PyObject *args)
|
psutil_linux_sysinfo(PyObject *self, PyObject *args) {
|
||||||
{
|
|
||||||
struct sysinfo info;
|
struct sysinfo info;
|
||||||
|
|
||||||
if (sysinfo(&info) != 0)
|
if (sysinfo(&info) != 0)
|
||||||
return PyErr_SetFromErrno(PyExc_OSError);
|
return PyErr_SetFromErrno(PyExc_OSError);
|
||||||
// note: boot time might also be determined from here
|
// note: boot time might also be determined from here
|
||||||
return Py_BuildValue(
|
return Py_BuildValue(
|
||||||
"(KKKKKK)",
|
"(kkkkkkI)",
|
||||||
(unsigned long long)info.totalram * info.mem_unit, // total
|
info.totalram, // total
|
||||||
(unsigned long long)info.freeram * info.mem_unit, // free
|
info.freeram, // free
|
||||||
(unsigned long long)info.bufferram * info.mem_unit, // buffer
|
info.bufferram, // buffer
|
||||||
(unsigned long long)info.sharedram * info.mem_unit, // shared
|
info.sharedram, // shared
|
||||||
(unsigned long long)info.totalswap * info.mem_unit, // swap tot
|
info.totalswap, // swap tot
|
||||||
(unsigned long long)info.freeswap * info.mem_unit); // swap free
|
info.freeswap, // swap free
|
||||||
|
info.mem_unit // multiplier
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -263,15 +282,14 @@ psutil_linux_sysinfo(PyObject *self, PyObject *args)
|
||||||
#ifdef CPU_ALLOC
|
#ifdef CPU_ALLOC
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
|
psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) {
|
||||||
{
|
|
||||||
int cpu, ncpus, count, cpucount_s;
|
int cpu, ncpus, count, cpucount_s;
|
||||||
long pid;
|
long pid;
|
||||||
size_t setsize;
|
size_t setsize;
|
||||||
cpu_set_t *mask = NULL;
|
cpu_set_t *mask = NULL;
|
||||||
PyObject *res = NULL;
|
PyObject *py_list = NULL;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "i", &pid))
|
if (!PyArg_ParseTuple(args, "l", &pid))
|
||||||
return NULL;
|
return NULL;
|
||||||
ncpus = NCPUS_START;
|
ncpus = NCPUS_START;
|
||||||
while (1) {
|
while (1) {
|
||||||
|
@ -292,8 +310,8 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
|
||||||
ncpus = ncpus * 2;
|
ncpus = ncpus * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = PyList_New(0);
|
py_list = PyList_New(0);
|
||||||
if (res == NULL)
|
if (py_list == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
cpucount_s = CPU_COUNT_S(setsize, mask);
|
cpucount_s = CPU_COUNT_S(setsize, mask);
|
||||||
|
@ -306,7 +324,7 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
|
||||||
#endif
|
#endif
|
||||||
if (cpu_num == NULL)
|
if (cpu_num == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
if (PyList_Append(res, cpu_num)) {
|
if (PyList_Append(py_list, cpu_num)) {
|
||||||
Py_DECREF(cpu_num);
|
Py_DECREF(cpu_num);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -315,12 +333,12 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CPU_FREE(mask);
|
CPU_FREE(mask);
|
||||||
return res;
|
return py_list;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (mask)
|
if (mask)
|
||||||
CPU_FREE(mask);
|
CPU_FREE(mask);
|
||||||
Py_XDECREF(res);
|
Py_XDECREF(py_list);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -330,8 +348,7 @@ error:
|
||||||
* Alternative implementation in case CPU_ALLOC is not defined.
|
* Alternative implementation in case CPU_ALLOC is not defined.
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
|
psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args) {
|
||||||
{
|
|
||||||
cpu_set_t cpuset;
|
cpu_set_t cpuset;
|
||||||
unsigned int len = sizeof(cpu_set_t);
|
unsigned int len = sizeof(cpu_set_t);
|
||||||
long pid;
|
long pid;
|
||||||
|
@ -339,7 +356,7 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
|
||||||
PyObject* py_retlist = NULL;
|
PyObject* py_retlist = NULL;
|
||||||
PyObject *py_cpu_num = NULL;
|
PyObject *py_cpu_num = NULL;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "i", &pid))
|
if (!PyArg_ParseTuple(args, "l", &pid))
|
||||||
return NULL;
|
return NULL;
|
||||||
CPU_ZERO(&cpuset);
|
CPU_ZERO(&cpuset);
|
||||||
if (sched_getaffinity(pid, len, &cpuset) < 0)
|
if (sched_getaffinity(pid, len, &cpuset) < 0)
|
||||||
|
@ -363,7 +380,7 @@ psutil_proc_cpu_affinity_get(PyObject *self, PyObject *args)
|
||||||
|
|
||||||
error:
|
error:
|
||||||
Py_XDECREF(py_cpu_num);
|
Py_XDECREF(py_cpu_num);
|
||||||
Py_DECREF(py_retlist);
|
Py_XDECREF(py_retlist);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -372,8 +389,7 @@ error:
|
||||||
* Set process CPU affinity; expects a bitmask
|
* Set process CPU affinity; expects a bitmask
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args)
|
psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args) {
|
||||||
{
|
|
||||||
cpu_set_t cpu_set;
|
cpu_set_t cpu_set;
|
||||||
size_t len;
|
size_t len;
|
||||||
long pid;
|
long pid;
|
||||||
|
@ -402,11 +418,15 @@ psutil_proc_cpu_affinity_set(PyObject *self, PyObject *args)
|
||||||
#else
|
#else
|
||||||
long value = PyInt_AsLong(item);
|
long value = PyInt_AsLong(item);
|
||||||
#endif
|
#endif
|
||||||
if (value == -1 && PyErr_Occurred())
|
if ((value == -1) || PyErr_Occurred()) {
|
||||||
|
if (!PyErr_Occurred())
|
||||||
|
PyErr_SetString(PyExc_ValueError, "invalid CPU value");
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
CPU_SET(value, &cpu_set);
|
CPU_SET(value, &cpu_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
len = sizeof(cpu_set);
|
len = sizeof(cpu_set);
|
||||||
if (sched_setaffinity(pid, len, &cpu_set)) {
|
if (sched_setaffinity(pid, len, &cpu_set)) {
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
@ -427,44 +447,61 @@ error:
|
||||||
* Return currently connected users as a list of tuples.
|
* Return currently connected users as a list of tuples.
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psutil_users(PyObject *self, PyObject *args)
|
psutil_users(PyObject *self, PyObject *args) {
|
||||||
{
|
|
||||||
PyObject *ret_list = PyList_New(0);
|
|
||||||
PyObject *tuple = NULL;
|
|
||||||
PyObject *user_proc = NULL;
|
|
||||||
struct utmp *ut;
|
struct utmp *ut;
|
||||||
|
PyObject *py_retlist = PyList_New(0);
|
||||||
|
PyObject *py_tuple = NULL;
|
||||||
|
PyObject *py_username = NULL;
|
||||||
|
PyObject *py_tty = NULL;
|
||||||
|
PyObject *py_hostname = NULL;
|
||||||
|
PyObject *py_user_proc = NULL;
|
||||||
|
|
||||||
if (ret_list == NULL)
|
if (py_retlist == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
setutent();
|
setutent();
|
||||||
while (NULL != (ut = getutent())) {
|
while (NULL != (ut = getutent())) {
|
||||||
tuple = NULL;
|
py_tuple = NULL;
|
||||||
user_proc = NULL;
|
py_user_proc = NULL;
|
||||||
if (ut->ut_type == USER_PROCESS)
|
if (ut->ut_type == USER_PROCESS)
|
||||||
user_proc = Py_True;
|
py_user_proc = Py_True;
|
||||||
else
|
else
|
||||||
user_proc = Py_False;
|
py_user_proc = Py_False;
|
||||||
tuple = Py_BuildValue(
|
py_username = PyUnicode_DecodeFSDefault(ut->ut_user);
|
||||||
"(sssfO)",
|
if (! py_username)
|
||||||
ut->ut_user, // username
|
goto error;
|
||||||
ut->ut_line, // tty
|
py_tty = PyUnicode_DecodeFSDefault(ut->ut_line);
|
||||||
ut->ut_host, // hostname
|
if (! py_tty)
|
||||||
|
goto error;
|
||||||
|
py_hostname = PyUnicode_DecodeFSDefault(ut->ut_host);
|
||||||
|
if (! py_hostname)
|
||||||
|
goto error;
|
||||||
|
py_tuple = Py_BuildValue(
|
||||||
|
"(OOOfOi)",
|
||||||
|
py_username, // username
|
||||||
|
py_tty, // tty
|
||||||
|
py_hostname, // hostname
|
||||||
(float)ut->ut_tv.tv_sec, // tstamp
|
(float)ut->ut_tv.tv_sec, // tstamp
|
||||||
user_proc // (bool) user process
|
py_user_proc, // (bool) user process
|
||||||
|
ut->ut_pid // process id
|
||||||
);
|
);
|
||||||
if (! tuple)
|
if (! py_tuple)
|
||||||
goto error;
|
goto error;
|
||||||
if (PyList_Append(ret_list, tuple))
|
if (PyList_Append(py_retlist, py_tuple))
|
||||||
goto error;
|
goto error;
|
||||||
Py_DECREF(tuple);
|
Py_DECREF(py_username);
|
||||||
|
Py_DECREF(py_tty);
|
||||||
|
Py_DECREF(py_hostname);
|
||||||
|
Py_DECREF(py_tuple);
|
||||||
}
|
}
|
||||||
endutent();
|
endutent();
|
||||||
return ret_list;
|
return py_retlist;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
Py_XDECREF(tuple);
|
Py_XDECREF(py_username);
|
||||||
Py_XDECREF(user_proc);
|
Py_XDECREF(py_tty);
|
||||||
Py_DECREF(ret_list);
|
Py_XDECREF(py_hostname);
|
||||||
|
Py_XDECREF(py_tuple);
|
||||||
|
Py_DECREF(py_retlist);
|
||||||
endutent();
|
endutent();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -477,18 +514,15 @@ error:
|
||||||
* http://www.i-scream.org/libstatgrab/
|
* http://www.i-scream.org/libstatgrab/
|
||||||
*/
|
*/
|
||||||
static PyObject*
|
static PyObject*
|
||||||
psutil_net_if_stats(PyObject* self, PyObject* args)
|
psutil_net_if_duplex_speed(PyObject* self, PyObject* args) {
|
||||||
{
|
|
||||||
char *nic_name;
|
char *nic_name;
|
||||||
int sock = 0;
|
int sock = 0;
|
||||||
int ret;
|
int ret;
|
||||||
int duplex;
|
int duplex;
|
||||||
int speed;
|
int speed;
|
||||||
int mtu;
|
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
struct ethtool_cmd ethcmd;
|
struct ethtool_cmd ethcmd;
|
||||||
PyObject *py_is_up = NULL;
|
PyObject *py_retlist = NULL;
|
||||||
PyObject *py_ret = NULL;
|
|
||||||
|
|
||||||
if (! PyArg_ParseTuple(args, "s", &nic_name))
|
if (! PyArg_ParseTuple(args, "s", &nic_name))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -498,26 +532,10 @@ psutil_net_if_stats(PyObject* self, PyObject* args)
|
||||||
goto error;
|
goto error;
|
||||||
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
|
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
|
||||||
|
|
||||||
// is up?
|
|
||||||
ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
|
|
||||||
if (ret == -1)
|
|
||||||
goto error;
|
|
||||||
if ((ifr.ifr_flags & IFF_UP) != 0)
|
|
||||||
py_is_up = Py_True;
|
|
||||||
else
|
|
||||||
py_is_up = Py_False;
|
|
||||||
Py_INCREF(py_is_up);
|
|
||||||
|
|
||||||
// MTU
|
|
||||||
ret = ioctl(sock, SIOCGIFMTU, &ifr);
|
|
||||||
if (ret == -1)
|
|
||||||
goto error;
|
|
||||||
mtu = ifr.ifr_mtu;
|
|
||||||
|
|
||||||
// duplex and speed
|
// duplex and speed
|
||||||
memset(ðcmd, 0, sizeof ethcmd);
|
memset(ðcmd, 0, sizeof ethcmd);
|
||||||
ethcmd.cmd = ETHTOOL_GSET;
|
ethcmd.cmd = ETHTOOL_GSET;
|
||||||
ifr.ifr_data = (caddr_t)ðcmd;
|
ifr.ifr_data = (void *)ðcmd;
|
||||||
ret = ioctl(sock, SIOCETHTOOL, &ifr);
|
ret = ioctl(sock, SIOCETHTOOL, &ifr);
|
||||||
|
|
||||||
if (ret != -1) {
|
if (ret != -1) {
|
||||||
|
@ -525,8 +543,11 @@ psutil_net_if_stats(PyObject* self, PyObject* args)
|
||||||
speed = ethcmd.speed;
|
speed = ethcmd.speed;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (errno == EOPNOTSUPP) {
|
if ((errno == EOPNOTSUPP) || (errno == EINVAL)) {
|
||||||
// we typically get here in case of wi-fi cards
|
// EOPNOTSUPP may occur in case of wi-fi cards.
|
||||||
|
// For EINVAL see:
|
||||||
|
// https://github.com/giampaolo/psutil/issues/797
|
||||||
|
// #issuecomment-202999532
|
||||||
duplex = DUPLEX_UNKNOWN;
|
duplex = DUPLEX_UNKNOWN;
|
||||||
speed = 0;
|
speed = 0;
|
||||||
}
|
}
|
||||||
|
@ -536,18 +557,15 @@ psutil_net_if_stats(PyObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
|
|
||||||
close(sock);
|
close(sock);
|
||||||
py_ret = Py_BuildValue("[Oiii]", py_is_up, duplex, speed, mtu);
|
py_retlist = Py_BuildValue("[ii]", duplex, speed);
|
||||||
if (!py_ret)
|
if (!py_retlist)
|
||||||
goto error;
|
goto error;
|
||||||
Py_DECREF(py_is_up);
|
return py_retlist;
|
||||||
return py_ret;
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
Py_XDECREF(py_is_up);
|
if (sock != -1)
|
||||||
if (sock != 0)
|
|
||||||
close(sock);
|
close(sock);
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
return PyErr_SetFromErrno(PyExc_OSError);
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -555,8 +573,7 @@ error:
|
||||||
* Define the psutil C module methods and initialize the module.
|
* Define the psutil C module methods and initialize the module.
|
||||||
*/
|
*/
|
||||||
static PyMethodDef
|
static PyMethodDef
|
||||||
PsutilMethods[] =
|
PsutilMethods[] = {
|
||||||
{
|
|
||||||
// --- per-process functions
|
// --- per-process functions
|
||||||
|
|
||||||
#if PSUTIL_HAVE_IOPRIO
|
#if PSUTIL_HAVE_IOPRIO
|
||||||
|
@ -577,8 +594,8 @@ PsutilMethods[] =
|
||||||
"device, mount point and filesystem type"},
|
"device, mount point and filesystem type"},
|
||||||
{"users", psutil_users, METH_VARARGS,
|
{"users", psutil_users, METH_VARARGS,
|
||||||
"Return currently connected users as a list of tuples"},
|
"Return currently connected users as a list of tuples"},
|
||||||
{"net_if_stats", psutil_net_if_stats, METH_VARARGS,
|
{"net_if_duplex_speed", psutil_net_if_duplex_speed, METH_VARARGS,
|
||||||
"Return NIC stats (isup, duplex, speed, mtu)"},
|
"Return duplex and speed info about a NIC"},
|
||||||
|
|
||||||
// --- linux specific
|
// --- linux specific
|
||||||
|
|
||||||
|
@ -589,6 +606,9 @@ PsutilMethods[] =
|
||||||
"Get or set process resource limits."},
|
"Get or set process resource limits."},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// --- others
|
||||||
|
{"set_testing", psutil_set_testing, METH_NOARGS,
|
||||||
|
"Set psutil in testing mode"},
|
||||||
|
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
@ -640,16 +660,15 @@ PyMODINIT_FUNC PyInit__psutil_linux(void)
|
||||||
void init_psutil_linux(void)
|
void init_psutil_linux(void)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
PyObject *v;
|
||||||
#if PY_MAJOR_VERSION >= 3
|
#if PY_MAJOR_VERSION >= 3
|
||||||
PyObject *module = PyModule_Create(&moduledef);
|
PyObject *module = PyModule_Create(&moduledef);
|
||||||
#else
|
#else
|
||||||
PyObject *module = Py_InitModule("_psutil_linux", PsutilMethods);
|
PyObject *module = Py_InitModule("_psutil_linux", PsutilMethods);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
PyModule_AddIntConstant(module, "version", PSUTIL_VERSION);
|
PyModule_AddIntConstant(module, "version", PSUTIL_VERSION);
|
||||||
#if PSUTIL_HAVE_PRLIMIT
|
#if PSUTIL_HAVE_PRLIMIT
|
||||||
PyModule_AddIntConstant(module, "RLIM_INFINITY", RLIM_INFINITY);
|
|
||||||
PyModule_AddIntConstant(module, "RLIMIT_AS", RLIMIT_AS);
|
PyModule_AddIntConstant(module, "RLIMIT_AS", RLIMIT_AS);
|
||||||
PyModule_AddIntConstant(module, "RLIMIT_CORE", RLIMIT_CORE);
|
PyModule_AddIntConstant(module, "RLIMIT_CORE", RLIMIT_CORE);
|
||||||
PyModule_AddIntConstant(module, "RLIMIT_CPU", RLIMIT_CPU);
|
PyModule_AddIntConstant(module, "RLIMIT_CPU", RLIMIT_CPU);
|
||||||
|
@ -661,6 +680,19 @@ void init_psutil_linux(void)
|
||||||
PyModule_AddIntConstant(module, "RLIMIT_NPROC", RLIMIT_NPROC);
|
PyModule_AddIntConstant(module, "RLIMIT_NPROC", RLIMIT_NPROC);
|
||||||
PyModule_AddIntConstant(module, "RLIMIT_RSS", RLIMIT_RSS);
|
PyModule_AddIntConstant(module, "RLIMIT_RSS", RLIMIT_RSS);
|
||||||
PyModule_AddIntConstant(module, "RLIMIT_STACK", RLIMIT_STACK);
|
PyModule_AddIntConstant(module, "RLIMIT_STACK", RLIMIT_STACK);
|
||||||
|
|
||||||
|
#if defined(HAVE_LONG_LONG)
|
||||||
|
if (sizeof(RLIM_INFINITY) > sizeof(long)) {
|
||||||
|
v = PyLong_FromLongLong((PY_LONG_LONG) RLIM_INFINITY);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
v = PyLong_FromLong((long) RLIM_INFINITY);
|
||||||
|
}
|
||||||
|
if (v) {
|
||||||
|
PyModule_AddObject(module, "RLIM_INFINITY", v);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef RLIMIT_MSGQUEUE
|
#ifdef RLIMIT_MSGQUEUE
|
||||||
PyModule_AddIntConstant(module, "RLIMIT_MSGQUEUE", RLIMIT_MSGQUEUE);
|
PyModule_AddIntConstant(module, "RLIMIT_MSGQUEUE", RLIMIT_MSGQUEUE);
|
||||||
#endif
|
#endif
|
||||||
|
@ -681,6 +713,8 @@ void init_psutil_linux(void)
|
||||||
PyModule_AddIntConstant(module, "DUPLEX_FULL", DUPLEX_FULL);
|
PyModule_AddIntConstant(module, "DUPLEX_FULL", DUPLEX_FULL);
|
||||||
PyModule_AddIntConstant(module, "DUPLEX_UNKNOWN", DUPLEX_UNKNOWN);
|
PyModule_AddIntConstant(module, "DUPLEX_UNKNOWN", DUPLEX_UNKNOWN);
|
||||||
|
|
||||||
|
psutil_setup();
|
||||||
|
|
||||||
if (module == NULL)
|
if (module == NULL)
|
||||||
INITERROR;
|
INITERROR;
|
||||||
#if PY_MAJOR_VERSION >= 3
|
#if PY_MAJOR_VERSION >= 3
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <Python.h>
|
|
||||||
|
|
||||||
// process
|
|
||||||
|
|
||||||
static PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_ioprio_get(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_ioprio_get(PyObject* self, PyObject* args);
|
|
||||||
|
|
||||||
// system
|
|
||||||
|
|
||||||
static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_linux_sysinfo(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_users(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args);
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <Python.h>
|
|
||||||
|
|
||||||
// --- per-process functions
|
|
||||||
static PyObject* psutil_proc_cmdline(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_connections(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_cpu_times(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_create_time(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_cwd(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_exe(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_gids(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_memory_info(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_name(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_num_fds(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_open_files(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_ppid(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_status(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_threads(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_tty_nr(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_uids(PyObject* self, PyObject* args);
|
|
||||||
|
|
||||||
// --- system-related functions
|
|
||||||
static PyObject* psutil_boot_time(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_cpu_count_logical(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_cpu_times(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_net_io_counters(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_pids(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_swap_mem(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_users(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_virtual_mem(PyObject* self, PyObject* args);
|
|
|
@ -11,40 +11,143 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <ifaddrs.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
|
||||||
#ifdef __linux
|
#ifdef PSUTIL_SUNOS10
|
||||||
#include <netdb.h>
|
#include "arch/solaris/v10/ifaddrs.h"
|
||||||
#include <linux/if_packet.h>
|
#elif PSUTIL_AIX
|
||||||
#endif // end linux
|
#include "arch/aix/ifaddrs.h"
|
||||||
|
#else
|
||||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
#include <ifaddrs.h>
|
||||||
#include <netdb.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <net/if_dl.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__sun)
|
#if defined(PSUTIL_LINUX)
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/if_packet.h>
|
||||||
|
#elif defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
#include <sys/sockio.h>
|
||||||
|
#include <net/if_media.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#elif defined(PSUTIL_SUNOS)
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/sockio.h>
|
||||||
|
#elif defined(PSUTIL_AIX)
|
||||||
|
#include <netdb.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "_psutil_posix.h"
|
#include "_psutil_common.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if PID exists. Return values:
|
||||||
|
* 1: exists
|
||||||
|
* 0: does not exist
|
||||||
|
* -1: error (Python exception is set)
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
psutil_pid_exists(long pid) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
// No negative PID exists, plus -1 is an alias for sending signal
|
||||||
|
// too all processes except system ones. Not what we want.
|
||||||
|
if (pid < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// As per "man 2 kill" PID 0 is an alias for sending the signal to
|
||||||
|
// every process in the process group of the calling process.
|
||||||
|
// Not what we want. Some platforms have PID 0, some do not.
|
||||||
|
// We decide that at runtime.
|
||||||
|
if (pid == 0) {
|
||||||
|
#if defined(PSUTIL_LINUX) || defined(PSUTIL_FREEBSD)
|
||||||
|
return 0;
|
||||||
|
#else
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(PSUTIL_OSX)
|
||||||
|
ret = kill((pid_t)pid , 0);
|
||||||
|
#else
|
||||||
|
ret = kill(pid , 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
return 1;
|
||||||
|
else {
|
||||||
|
if (errno == ESRCH) {
|
||||||
|
// ESRCH == No such process
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (errno == EPERM) {
|
||||||
|
// EPERM clearly indicates there's a process to deny
|
||||||
|
// access to.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// According to "man 2 kill" possible error values are
|
||||||
|
// (EINVAL, EPERM, ESRCH) therefore we should never get
|
||||||
|
// here. If we do let's be explicit in considering this
|
||||||
|
// an error.
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Utility used for those syscalls which do not return a meaningful
|
||||||
|
* error that we can translate into an exception which makes sense.
|
||||||
|
* As such, we'll have to guess.
|
||||||
|
* On UNIX, if errno is set, we return that one (OSError).
|
||||||
|
* Else, if PID does not exist we assume the syscall failed because
|
||||||
|
* of that so we raise NoSuchProcess.
|
||||||
|
* If none of this is true we giveup and raise RuntimeError(msg).
|
||||||
|
* This will always set a Python exception and return NULL.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
psutil_raise_for_pid(long pid, char *syscall_name) {
|
||||||
|
// Set exception to AccessDenied if pid exists else NoSuchProcess.
|
||||||
|
if (errno != 0) {
|
||||||
|
// Unlikely we get here.
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (psutil_pid_exists(pid) == 0) {
|
||||||
|
psutil_debug("%s syscall failed and PID %i no longer exists; "
|
||||||
|
"assume NoSuchProcess", syscall_name, pid);
|
||||||
|
NoSuchProcess("");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_Format(PyExc_RuntimeError, "%s syscall failed", syscall_name);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given a PID return process priority as a Python integer.
|
* Given a PID return process priority as a Python integer.
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psutil_posix_getpriority(PyObject *self, PyObject *args)
|
psutil_posix_getpriority(PyObject *self, PyObject *args) {
|
||||||
{
|
|
||||||
long pid;
|
long pid;
|
||||||
int priority;
|
int priority;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|
||||||
if (! PyArg_ParseTuple(args, "l", &pid))
|
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
#ifdef PSUTIL_OSX
|
||||||
|
priority = getpriority(PRIO_PROCESS, (id_t)pid);
|
||||||
|
#else
|
||||||
priority = getpriority(PRIO_PROCESS, pid);
|
priority = getpriority(PRIO_PROCESS, pid);
|
||||||
|
#endif
|
||||||
if (errno != 0)
|
if (errno != 0)
|
||||||
return PyErr_SetFromErrno(PyExc_OSError);
|
return PyErr_SetFromErrno(PyExc_OSError);
|
||||||
return Py_BuildValue("i", priority);
|
return Py_BuildValue("i", priority);
|
||||||
|
@ -55,15 +158,19 @@ psutil_posix_getpriority(PyObject *self, PyObject *args)
|
||||||
* Given a PID and a value change process priority.
|
* Given a PID and a value change process priority.
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psutil_posix_setpriority(PyObject *self, PyObject *args)
|
psutil_posix_setpriority(PyObject *self, PyObject *args) {
|
||||||
{
|
|
||||||
long pid;
|
long pid;
|
||||||
int priority;
|
int priority;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (! PyArg_ParseTuple(args, "li", &pid, &priority))
|
if (! PyArg_ParseTuple(args, "li", &pid, &priority))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
#ifdef PSUTIL_OSX
|
||||||
|
retval = setpriority(PRIO_PROCESS, (id_t)pid, priority);
|
||||||
|
#else
|
||||||
retval = setpriority(PRIO_PROCESS, pid, priority);
|
retval = setpriority(PRIO_PROCESS, pid, priority);
|
||||||
|
#endif
|
||||||
if (retval == -1)
|
if (retval == -1)
|
||||||
return PyErr_SetFromErrno(PyExc_OSError);
|
return PyErr_SetFromErrno(PyExc_OSError);
|
||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
|
@ -75,12 +182,11 @@ psutil_posix_setpriority(PyObject *self, PyObject *args)
|
||||||
* Return None if address family is not AF_INET* or AF_PACKET.
|
* Return None if address family is not AF_INET* or AF_PACKET.
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psutil_convert_ipaddr(struct sockaddr *addr, int family)
|
psutil_convert_ipaddr(struct sockaddr *addr, int family) {
|
||||||
{
|
|
||||||
char buf[NI_MAXHOST];
|
char buf[NI_MAXHOST];
|
||||||
int err;
|
int err;
|
||||||
int addrlen;
|
int addrlen;
|
||||||
int n;
|
size_t n;
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *data;
|
const char *data;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
@ -109,14 +215,13 @@ psutil_convert_ipaddr(struct sockaddr *addr, int family)
|
||||||
return Py_BuildValue("s", buf);
|
return Py_BuildValue("s", buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef __linux
|
#ifdef PSUTIL_LINUX
|
||||||
else if (family == AF_PACKET) {
|
else if (family == AF_PACKET) {
|
||||||
struct sockaddr_ll *lladdr = (struct sockaddr_ll *)addr;
|
struct sockaddr_ll *lladdr = (struct sockaddr_ll *)addr;
|
||||||
len = lladdr->sll_halen;
|
len = lladdr->sll_halen;
|
||||||
data = (const char *)lladdr->sll_addr;
|
data = (const char *)lladdr->sll_addr;
|
||||||
}
|
}
|
||||||
#endif
|
#elif defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
|
||||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
|
||||||
else if (addr->sa_family == AF_LINK) {
|
else if (addr->sa_family == AF_LINK) {
|
||||||
// Note: prior to Python 3.4 socket module does not expose
|
// Note: prior to Python 3.4 socket module does not expose
|
||||||
// AF_LINK so we'll do.
|
// AF_LINK so we'll do.
|
||||||
|
@ -153,8 +258,7 @@ psutil_convert_ipaddr(struct sockaddr *addr, int family)
|
||||||
* TODO: on Solaris we won't get any MAC address.
|
* TODO: on Solaris we won't get any MAC address.
|
||||||
*/
|
*/
|
||||||
static PyObject*
|
static PyObject*
|
||||||
psutil_net_if_addrs(PyObject* self, PyObject* args)
|
psutil_net_if_addrs(PyObject* self, PyObject* args) {
|
||||||
{
|
|
||||||
struct ifaddrs *ifaddr, *ifa;
|
struct ifaddrs *ifaddr, *ifa;
|
||||||
int family;
|
int family;
|
||||||
|
|
||||||
|
@ -163,6 +267,7 @@ psutil_net_if_addrs(PyObject* self, PyObject* args)
|
||||||
PyObject *py_address = NULL;
|
PyObject *py_address = NULL;
|
||||||
PyObject *py_netmask = NULL;
|
PyObject *py_netmask = NULL;
|
||||||
PyObject *py_broadcast = NULL;
|
PyObject *py_broadcast = NULL;
|
||||||
|
PyObject *py_ptp = NULL;
|
||||||
|
|
||||||
if (py_retlist == NULL)
|
if (py_retlist == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -185,20 +290,34 @@ psutil_net_if_addrs(PyObject* self, PyObject* args)
|
||||||
py_netmask = psutil_convert_ipaddr(ifa->ifa_netmask, family);
|
py_netmask = psutil_convert_ipaddr(ifa->ifa_netmask, family);
|
||||||
if (py_netmask == NULL)
|
if (py_netmask == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
#ifdef __linux
|
|
||||||
py_broadcast = psutil_convert_ipaddr(ifa->ifa_ifu.ifu_broadaddr, family);
|
if (ifa->ifa_flags & IFF_BROADCAST) {
|
||||||
#else
|
py_broadcast = psutil_convert_ipaddr(ifa->ifa_broadaddr, family);
|
||||||
py_broadcast = psutil_convert_ipaddr(ifa->ifa_broadaddr, family);
|
Py_INCREF(Py_None);
|
||||||
#endif
|
py_ptp = Py_None;
|
||||||
if (py_broadcast == NULL)
|
}
|
||||||
|
else if (ifa->ifa_flags & IFF_POINTOPOINT) {
|
||||||
|
py_ptp = psutil_convert_ipaddr(ifa->ifa_dstaddr, family);
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
py_broadcast = Py_None;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
py_broadcast = Py_None;
|
||||||
|
py_ptp = Py_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((py_broadcast == NULL) || (py_ptp == NULL))
|
||||||
goto error;
|
goto error;
|
||||||
py_tuple = Py_BuildValue(
|
py_tuple = Py_BuildValue(
|
||||||
"(siOOO)",
|
"(siOOOO)",
|
||||||
ifa->ifa_name,
|
ifa->ifa_name,
|
||||||
family,
|
family,
|
||||||
py_address,
|
py_address,
|
||||||
py_netmask,
|
py_netmask,
|
||||||
py_broadcast
|
py_broadcast,
|
||||||
|
py_ptp
|
||||||
);
|
);
|
||||||
|
|
||||||
if (! py_tuple)
|
if (! py_tuple)
|
||||||
|
@ -209,6 +328,7 @@ psutil_net_if_addrs(PyObject* self, PyObject* args)
|
||||||
Py_DECREF(py_address);
|
Py_DECREF(py_address);
|
||||||
Py_DECREF(py_netmask);
|
Py_DECREF(py_netmask);
|
||||||
Py_DECREF(py_broadcast);
|
Py_DECREF(py_broadcast);
|
||||||
|
Py_DECREF(py_ptp);
|
||||||
}
|
}
|
||||||
|
|
||||||
freeifaddrs(ifaddr);
|
freeifaddrs(ifaddr);
|
||||||
|
@ -222,19 +342,98 @@ error:
|
||||||
Py_XDECREF(py_address);
|
Py_XDECREF(py_address);
|
||||||
Py_XDECREF(py_netmask);
|
Py_XDECREF(py_netmask);
|
||||||
Py_XDECREF(py_broadcast);
|
Py_XDECREF(py_broadcast);
|
||||||
|
Py_XDECREF(py_ptp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* net_if_stats() implementation. This is here because it is common
|
* Return NIC MTU. References:
|
||||||
* to both OSX and FreeBSD and I didn't know where else to put it.
|
* http://www.i-scream.org/libstatgrab/
|
||||||
*/
|
*/
|
||||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
static PyObject *
|
||||||
|
psutil_net_if_mtu(PyObject *self, PyObject *args) {
|
||||||
|
char *nic_name;
|
||||||
|
int sock = 0;
|
||||||
|
int ret;
|
||||||
|
#ifdef PSUTIL_SUNOS10
|
||||||
|
struct lifreq lifr;
|
||||||
|
#else
|
||||||
|
struct ifreq ifr;
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <sys/sockio.h>
|
if (! PyArg_ParseTuple(args, "s", &nic_name))
|
||||||
#include <net/if_media.h>
|
return NULL;
|
||||||
#include <net/if.h>
|
|
||||||
|
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (sock == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
#ifdef PSUTIL_SUNOS10
|
||||||
|
strncpy(lifr.lifr_name, nic_name, sizeof(lifr.lifr_name));
|
||||||
|
ret = ioctl(sock, SIOCGIFMTU, &lifr);
|
||||||
|
#else
|
||||||
|
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
|
||||||
|
ret = ioctl(sock, SIOCGIFMTU, &ifr);
|
||||||
|
#endif
|
||||||
|
if (ret == -1)
|
||||||
|
goto error;
|
||||||
|
close(sock);
|
||||||
|
|
||||||
|
#ifdef PSUTIL_SUNOS10
|
||||||
|
return Py_BuildValue("i", lifr.lifr_mtu);
|
||||||
|
#else
|
||||||
|
return Py_BuildValue("i", ifr.ifr_mtu);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (sock != 0)
|
||||||
|
close(sock);
|
||||||
|
return PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inspect NIC flags, returns a bool indicating whether the NIC is
|
||||||
|
* running. References:
|
||||||
|
* http://www.i-scream.org/libstatgrab/
|
||||||
|
*/
|
||||||
|
static PyObject *
|
||||||
|
psutil_net_if_flags(PyObject *self, PyObject *args) {
|
||||||
|
char *nic_name;
|
||||||
|
int sock = 0;
|
||||||
|
int ret;
|
||||||
|
struct ifreq ifr;
|
||||||
|
|
||||||
|
if (! PyArg_ParseTuple(args, "s", &nic_name))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (sock == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
|
||||||
|
ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
|
||||||
|
if (ret == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
close(sock);
|
||||||
|
if ((ifr.ifr_flags & IFF_UP) != 0)
|
||||||
|
return Py_BuildValue("O", Py_True);
|
||||||
|
else
|
||||||
|
return Py_BuildValue("O", Py_False);
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (sock != 0)
|
||||||
|
close(sock);
|
||||||
|
return PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* net_if_stats() OSX/BSD implementation.
|
||||||
|
*/
|
||||||
|
#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
|
||||||
|
|
||||||
int psutil_get_nic_speed(int ifm_active) {
|
int psutil_get_nic_speed(int ifm_active) {
|
||||||
// Determine NIC speed. Taken from:
|
// Determine NIC speed. Taken from:
|
||||||
|
@ -267,8 +466,8 @@ int psutil_get_nic_speed(int ifm_active) {
|
||||||
case(IFM_1000_SX): // 1000BaseSX - multi-mode fiber
|
case(IFM_1000_SX): // 1000BaseSX - multi-mode fiber
|
||||||
case(IFM_1000_LX): // 1000baseLX - single-mode fiber
|
case(IFM_1000_LX): // 1000baseLX - single-mode fiber
|
||||||
case(IFM_1000_CX): // 1000baseCX - 150ohm STP
|
case(IFM_1000_CX): // 1000baseCX - 150ohm STP
|
||||||
#if defined(IFM_1000_TX) && !defined(OPENBSD)
|
#if defined(IFM_1000_TX) && !defined(PSUTIL_OPENBSD)
|
||||||
// FreeBSD 4 and others (but NOT OpenBSD)?
|
// FreeBSD 4 and others (but NOT OpenBSD) -> #define IFM_1000_T in net/if_media.h
|
||||||
case(IFM_1000_TX):
|
case(IFM_1000_TX):
|
||||||
#endif
|
#endif
|
||||||
#ifdef IFM_1000_FX
|
#ifdef IFM_1000_FX
|
||||||
|
@ -378,19 +577,15 @@ int psutil_get_nic_speed(int ifm_active) {
|
||||||
* http://www.i-scream.org/libstatgrab/
|
* http://www.i-scream.org/libstatgrab/
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
psutil_net_if_stats(PyObject *self, PyObject *args)
|
psutil_net_if_duplex_speed(PyObject *self, PyObject *args) {
|
||||||
{
|
|
||||||
char *nic_name;
|
char *nic_name;
|
||||||
int sock = 0;
|
int sock = 0;
|
||||||
int ret;
|
int ret;
|
||||||
int duplex;
|
int duplex;
|
||||||
int speed;
|
int speed;
|
||||||
int mtu;
|
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
struct ifmediareq ifmed;
|
struct ifmediareq ifmed;
|
||||||
|
|
||||||
PyObject *py_is_up = NULL;
|
|
||||||
|
|
||||||
if (! PyArg_ParseTuple(args, "s", &nic_name))
|
if (! PyArg_ParseTuple(args, "s", &nic_name))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -399,22 +594,6 @@ psutil_net_if_stats(PyObject *self, PyObject *args)
|
||||||
goto error;
|
goto error;
|
||||||
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
|
strncpy(ifr.ifr_name, nic_name, sizeof(ifr.ifr_name));
|
||||||
|
|
||||||
// is up?
|
|
||||||
ret = ioctl(sock, SIOCGIFFLAGS, &ifr);
|
|
||||||
if (ret == -1)
|
|
||||||
goto error;
|
|
||||||
if ((ifr.ifr_flags & IFF_UP) != 0)
|
|
||||||
py_is_up = Py_True;
|
|
||||||
else
|
|
||||||
py_is_up = Py_False;
|
|
||||||
Py_INCREF(py_is_up);
|
|
||||||
|
|
||||||
// MTU
|
|
||||||
ret = ioctl(sock, SIOCGIFMTU, &ifr);
|
|
||||||
if (ret == -1)
|
|
||||||
goto error;
|
|
||||||
mtu = ifr.ifr_mtu;
|
|
||||||
|
|
||||||
// speed / duplex
|
// speed / duplex
|
||||||
memset(&ifmed, 0, sizeof(struct ifmediareq));
|
memset(&ifmed, 0, sizeof(struct ifmediareq));
|
||||||
strlcpy(ifmed.ifm_name, nic_name, sizeof(ifmed.ifm_name));
|
strlcpy(ifmed.ifm_name, nic_name, sizeof(ifmed.ifm_name));
|
||||||
|
@ -434,34 +613,33 @@ psutil_net_if_stats(PyObject *self, PyObject *args)
|
||||||
}
|
}
|
||||||
|
|
||||||
close(sock);
|
close(sock);
|
||||||
Py_DECREF(py_is_up);
|
return Py_BuildValue("[ii]", duplex, speed);
|
||||||
|
|
||||||
return Py_BuildValue("[Oiii]", py_is_up, duplex, speed, mtu);
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
Py_XDECREF(py_is_up);
|
|
||||||
if (sock != 0)
|
if (sock != 0)
|
||||||
close(sock);
|
close(sock);
|
||||||
PyErr_SetFromErrno(PyExc_OSError);
|
return PyErr_SetFromErrno(PyExc_OSError);
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
#endif // net_if_stats() implementation
|
#endif // net_if_stats() OSX/BSD implementation
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* define the psutil C module methods and initialize the module.
|
* define the psutil C module methods and initialize the module.
|
||||||
*/
|
*/
|
||||||
static PyMethodDef
|
static PyMethodDef
|
||||||
PsutilMethods[] =
|
PsutilMethods[] = {
|
||||||
{
|
|
||||||
{"getpriority", psutil_posix_getpriority, METH_VARARGS,
|
{"getpriority", psutil_posix_getpriority, METH_VARARGS,
|
||||||
"Return process priority"},
|
"Return process priority"},
|
||||||
{"setpriority", psutil_posix_setpriority, METH_VARARGS,
|
{"setpriority", psutil_posix_setpriority, METH_VARARGS,
|
||||||
"Set process priority"},
|
"Set process priority"},
|
||||||
{"net_if_addrs", psutil_net_if_addrs, METH_VARARGS,
|
{"net_if_addrs", psutil_net_if_addrs, METH_VARARGS,
|
||||||
"Retrieve NICs information"},
|
"Retrieve NICs information"},
|
||||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
{"net_if_mtu", psutil_net_if_mtu, METH_VARARGS,
|
||||||
{"net_if_stats", psutil_net_if_stats, METH_VARARGS,
|
"Retrieve NIC MTU"},
|
||||||
|
{"net_if_flags", psutil_net_if_flags, METH_VARARGS,
|
||||||
|
"Retrieve NIC flags"},
|
||||||
|
#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX)
|
||||||
|
{"net_if_duplex_speed", psutil_net_if_duplex_speed, METH_VARARGS,
|
||||||
"Return NIC stats."},
|
"Return NIC stats."},
|
||||||
#endif
|
#endif
|
||||||
{NULL, NULL, 0, NULL}
|
{NULL, NULL, 0, NULL}
|
||||||
|
@ -485,6 +663,7 @@ psutil_posix_traverse(PyObject *m, visitproc visit, void *arg) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
psutil_posix_clear(PyObject *m) {
|
psutil_posix_clear(PyObject *m) {
|
||||||
Py_CLEAR(GETSTATE(m)->error);
|
Py_CLEAR(GETSTATE(m)->error);
|
||||||
|
@ -519,7 +698,7 @@ void init_psutil_posix(void)
|
||||||
PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods);
|
PyObject *module = Py_InitModule("_psutil_posix", PsutilMethods);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__sun)
|
#if defined(PSUTIL_BSD) || defined(PSUTIL_OSX) || defined(PSUTIL_SUNOS) || defined(PSUTIL_AIX)
|
||||||
PyModule_AddIntConstant(module, "AF_LINK", AF_LINK);
|
PyModule_AddIntConstant(module, "AF_LINK", AF_LINK);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,5 @@
|
||||||
* found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Python.h>
|
int psutil_pid_exists(long pid);
|
||||||
|
void psutil_raise_for_pid(long pid, char *msg);
|
||||||
static PyObject* psutil_net_if_addrs(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_posix_getpriority(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_posix_setpriority(PyObject* self, PyObject* args);
|
|
||||||
|
|
||||||
#if defined(__FreeBSD__) || defined(__APPLE__)
|
|
||||||
static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args);
|
|
||||||
#endif
|
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,28 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <Python.h>
|
|
||||||
|
|
||||||
// processes
|
|
||||||
static PyObject* psutil_proc_basic_info(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_cpu_times(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_cred(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_name_and_args(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_num_ctx_switches(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_query_thread(PyObject* self, PyObject* args);
|
|
||||||
|
|
||||||
// system
|
|
||||||
static PyObject* psutil_boot_time(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_net_io_counters(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_swap_mem(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_users(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_net_connections(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args);
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <Python.h>
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
// --- per-process functions
|
|
||||||
|
|
||||||
static PyObject* psutil_proc_cmdline(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_cpu_times(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_create_time(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_cwd(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_exe(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_info(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_io_counters(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_is_suspended(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_kill(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_memory_info(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_memory_info_2(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_name(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_num_handles(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_open_files(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_priority_get(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_priority_set(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_resume(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_suspend(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_threads(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_username(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_wait(PyObject* self, PyObject* args);
|
|
||||||
|
|
||||||
#if (PSUTIL_WINVER >= 0x0600) // Windows Vista
|
|
||||||
static PyObject* psutil_proc_io_priority_get(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_proc_io_priority_set(PyObject* self, PyObject* args);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// --- system-related functions
|
|
||||||
|
|
||||||
static PyObject* psutil_boot_time(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_cpu_count_logical(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_cpu_times(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_disk_partitions(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_disk_usage(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_net_connections(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_net_io_counters(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_pid_exists(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_pids(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_ppid_map(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_users(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_virtual_mem(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_net_if_addrs(PyObject* self, PyObject* args);
|
|
||||||
static PyObject* psutil_net_if_stats(PyObject* self, PyObject* args);
|
|
||||||
|
|
||||||
// --- windows API bindings
|
|
||||||
|
|
||||||
static PyObject* psutil_win32_QueryDosDevice(PyObject* self, PyObject* args);
|
|
||||||
|
|
||||||
// --- internal
|
|
||||||
|
|
||||||
int psutil_proc_suspend_or_resume(DWORD pid, int suspend);
|
|
|
@ -1,11 +1,10 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||||
# Use of this source code is governed by a BSD-style license that can be
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
# found in the LICENSE file.
|
# found in the LICENSE file.
|
||||||
|
|
||||||
"""Windows platform implementation."""
|
"""Windows platform implementation."""
|
||||||
|
|
||||||
|
import contextlib
|
||||||
import errno
|
import errno
|
||||||
import functools
|
import functools
|
||||||
import os
|
import os
|
||||||
|
@ -13,16 +12,49 @@ import sys
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
from . import _common
|
from . import _common
|
||||||
from . import _psutil_windows as cext
|
try:
|
||||||
from ._common import conn_tmap, usage_percent, isfile_strict
|
from . import _psutil_windows as cext
|
||||||
from ._common import sockfam_to_enum, socktype_to_enum
|
except ImportError as err:
|
||||||
from ._compat import PY3, xrange, lru_cache, long
|
if str(err).lower().startswith("dll load failed") and \
|
||||||
from ._psutil_windows import (ABOVE_NORMAL_PRIORITY_CLASS,
|
sys.getwindowsversion()[0] < 6:
|
||||||
BELOW_NORMAL_PRIORITY_CLASS,
|
# We may get here if:
|
||||||
HIGH_PRIORITY_CLASS,
|
# 1) we are on an old Windows version
|
||||||
IDLE_PRIORITY_CLASS,
|
# 2) psutil was installed via pip + wheel
|
||||||
NORMAL_PRIORITY_CLASS,
|
# See: https://github.com/giampaolo/psutil/issues/811
|
||||||
REALTIME_PRIORITY_CLASS)
|
# It must be noted that psutil can still (kind of) work
|
||||||
|
# on outdated systems if compiled / installed from sources,
|
||||||
|
# but if we get here it means this this was a wheel (or exe).
|
||||||
|
msg = "this Windows version is too old (< Windows Vista); "
|
||||||
|
msg += "psutil 3.4.2 is the latest version which supports Windows "
|
||||||
|
msg += "2000, XP and 2003 server; it may be possible that psutil "
|
||||||
|
msg += "will work if compiled from sources though"
|
||||||
|
raise RuntimeError(msg)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
from ._common import conn_tmap
|
||||||
|
from ._common import ENCODING
|
||||||
|
from ._common import ENCODING_ERRS
|
||||||
|
from ._common import isfile_strict
|
||||||
|
from ._common import memoize_when_activated
|
||||||
|
from ._common import parse_environ_block
|
||||||
|
from ._common import sockfam_to_enum
|
||||||
|
from ._common import socktype_to_enum
|
||||||
|
from ._common import usage_percent
|
||||||
|
from ._compat import long
|
||||||
|
from ._compat import lru_cache
|
||||||
|
from ._compat import PY3
|
||||||
|
from ._compat import unicode
|
||||||
|
from ._compat import xrange
|
||||||
|
from ._exceptions import AccessDenied
|
||||||
|
from ._exceptions import NoSuchProcess
|
||||||
|
from ._exceptions import TimeoutExpired
|
||||||
|
from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS
|
||||||
|
from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS
|
||||||
|
from ._psutil_windows import HIGH_PRIORITY_CLASS
|
||||||
|
from ._psutil_windows import IDLE_PRIORITY_CLASS
|
||||||
|
from ._psutil_windows import NORMAL_PRIORITY_CLASS
|
||||||
|
from ._psutil_windows import REALTIME_PRIORITY_CLASS
|
||||||
|
|
||||||
if sys.version_info >= (3, 4):
|
if sys.version_info >= (3, 4):
|
||||||
import enum
|
import enum
|
||||||
|
@ -31,19 +63,28 @@ else:
|
||||||
|
|
||||||
# process priority constants, import from __init__.py:
|
# process priority constants, import from __init__.py:
|
||||||
# http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx
|
# http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx
|
||||||
__extra__all__ = ["ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS",
|
__extra__all__ = [
|
||||||
"HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS",
|
"win_service_iter", "win_service_get",
|
||||||
"NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS",
|
"ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS",
|
||||||
"CONN_DELETE_TCB",
|
"HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS",
|
||||||
"AF_LINK",
|
"NORMAL_PRIORITY_CLASS", "REALTIME_PRIORITY_CLASS",
|
||||||
]
|
"CONN_DELETE_TCB",
|
||||||
|
"AF_LINK",
|
||||||
|
]
|
||||||
|
|
||||||
# --- module level constants (gets pushed up to psutil module)
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- globals
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
CONN_DELETE_TCB = "DELETE_TCB"
|
CONN_DELETE_TCB = "DELETE_TCB"
|
||||||
WAIT_TIMEOUT = 0x00000102 # 258 in decimal
|
WAIT_TIMEOUT = 0x00000102 # 258 in decimal
|
||||||
ACCESS_DENIED_SET = frozenset([errno.EPERM, errno.EACCES,
|
ACCESS_DENIED_ERRSET = frozenset([errno.EPERM, errno.EACCES,
|
||||||
cext.ERROR_ACCESS_DENIED])
|
cext.ERROR_ACCESS_DENIED])
|
||||||
|
NO_SUCH_SERVICE_ERRSET = frozenset([cext.ERROR_INVALID_NAME,
|
||||||
|
cext.ERROR_SERVICE_DOES_NOT_EXIST])
|
||||||
|
|
||||||
|
|
||||||
if enum is None:
|
if enum is None:
|
||||||
AF_LINK = -1
|
AF_LINK = -1
|
||||||
else:
|
else:
|
||||||
|
@ -77,43 +118,94 @@ if enum is not None:
|
||||||
|
|
||||||
globals().update(Priority.__members__)
|
globals().update(Priority.__members__)
|
||||||
|
|
||||||
scputimes = namedtuple('scputimes', ['user', 'system', 'idle'])
|
pinfo_map = dict(
|
||||||
|
num_handles=0,
|
||||||
|
ctx_switches=1,
|
||||||
|
user_time=2,
|
||||||
|
kernel_time=3,
|
||||||
|
create_time=4,
|
||||||
|
num_threads=5,
|
||||||
|
io_rcount=6,
|
||||||
|
io_wcount=7,
|
||||||
|
io_rbytes=8,
|
||||||
|
io_wbytes=9,
|
||||||
|
io_count_others=10,
|
||||||
|
io_bytes_others=11,
|
||||||
|
num_page_faults=12,
|
||||||
|
peak_wset=13,
|
||||||
|
wset=14,
|
||||||
|
peak_paged_pool=15,
|
||||||
|
paged_pool=16,
|
||||||
|
peak_non_paged_pool=17,
|
||||||
|
non_paged_pool=18,
|
||||||
|
pagefile=19,
|
||||||
|
peak_pagefile=20,
|
||||||
|
mem_private=21,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- named tuples
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
# psutil.cpu_times()
|
||||||
|
scputimes = namedtuple('scputimes',
|
||||||
|
['user', 'system', 'idle', 'interrupt', 'dpc'])
|
||||||
|
# psutil.virtual_memory()
|
||||||
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
|
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
|
||||||
pextmem = namedtuple(
|
# psutil.Process.memory_info()
|
||||||
'pextmem', ['num_page_faults', 'peak_wset', 'wset', 'peak_paged_pool',
|
pmem = namedtuple(
|
||||||
'paged_pool', 'peak_nonpaged_pool', 'nonpaged_pool',
|
'pmem', ['rss', 'vms',
|
||||||
'pagefile', 'peak_pagefile', 'private'])
|
'num_page_faults', 'peak_wset', 'wset', 'peak_paged_pool',
|
||||||
|
'paged_pool', 'peak_nonpaged_pool', 'nonpaged_pool',
|
||||||
|
'pagefile', 'peak_pagefile', 'private'])
|
||||||
|
# psutil.Process.memory_full_info()
|
||||||
|
pfullmem = namedtuple('pfullmem', pmem._fields + ('uss', ))
|
||||||
|
# psutil.Process.memory_maps(grouped=True)
|
||||||
pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss'])
|
pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss'])
|
||||||
|
# psutil.Process.memory_maps(grouped=False)
|
||||||
pmmap_ext = namedtuple(
|
pmmap_ext = namedtuple(
|
||||||
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
|
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
|
||||||
ntpinfo = namedtuple(
|
# psutil.Process.io_counters()
|
||||||
'ntpinfo', ['num_handles', 'ctx_switches', 'user_time', 'kernel_time',
|
pio = namedtuple('pio', ['read_count', 'write_count',
|
||||||
'create_time', 'num_threads', 'io_rcount', 'io_wcount',
|
'read_bytes', 'write_bytes',
|
||||||
'io_rbytes', 'io_wbytes'])
|
'other_count', 'other_bytes'])
|
||||||
|
|
||||||
# set later from __init__.py
|
|
||||||
NoSuchProcess = None
|
# =====================================================================
|
||||||
AccessDenied = None
|
# --- utils
|
||||||
TimeoutExpired = None
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=512)
|
@lru_cache(maxsize=512)
|
||||||
def _win32_QueryDosDevice(s):
|
def convert_dos_path(s):
|
||||||
return cext.win32_QueryDosDevice(s)
|
r"""Convert paths using native DOS format like:
|
||||||
|
"\Device\HarddiskVolume1\Windows\systemew\file.txt"
|
||||||
|
into:
|
||||||
def _convert_raw_path(s):
|
"C:\Windows\systemew\file.txt"
|
||||||
# convert paths using native DOS format like:
|
"""
|
||||||
# "\Device\HarddiskVolume1\Windows\systemew\file.txt"
|
|
||||||
# into: "C:\Windows\systemew\file.txt"
|
|
||||||
if PY3 and not isinstance(s, str):
|
|
||||||
s = s.decode('utf8')
|
|
||||||
rawdrive = '\\'.join(s.split('\\')[:3])
|
rawdrive = '\\'.join(s.split('\\')[:3])
|
||||||
driveletter = _win32_QueryDosDevice(rawdrive)
|
driveletter = cext.win32_QueryDosDevice(rawdrive)
|
||||||
return os.path.join(driveletter, s[len(rawdrive):])
|
return os.path.join(driveletter, s[len(rawdrive):])
|
||||||
|
|
||||||
|
|
||||||
# --- public functions
|
def py2_strencode(s):
|
||||||
|
"""Encode a unicode string to a byte string by using the default fs
|
||||||
|
encoding + "replace" error handler.
|
||||||
|
"""
|
||||||
|
if PY3:
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
if isinstance(s, str):
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
return s.encode(ENCODING, errors=ENCODING_ERRS)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- memory
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
def virtual_memory():
|
def virtual_memory():
|
||||||
|
@ -139,15 +231,21 @@ def swap_memory():
|
||||||
return _common.sswap(total, used, free, percent, 0, 0)
|
return _common.sswap(total, used, free, percent, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- disk
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
disk_io_counters = cext.disk_io_counters
|
||||||
|
|
||||||
|
|
||||||
def disk_usage(path):
|
def disk_usage(path):
|
||||||
"""Return disk usage associated with path."""
|
"""Return disk usage associated with path."""
|
||||||
try:
|
if PY3 and isinstance(path, bytes):
|
||||||
total, free = cext.disk_usage(path)
|
# XXX: do we want to use "strict"? Probably yes, in order
|
||||||
except WindowsError:
|
# to fail immediately. After all we are accepting input here...
|
||||||
if not os.path.exists(path):
|
path = path.decode(ENCODING, errors="strict")
|
||||||
msg = "No such file or directory: '%s'" % path
|
total, free = cext.disk_usage(path)
|
||||||
raise OSError(errno.ENOENT, msg)
|
|
||||||
raise
|
|
||||||
used = total - free
|
used = total - free
|
||||||
percent = usage_percent(used, total, _round=1)
|
percent = usage_percent(used, total, _round=1)
|
||||||
return _common.sdiskusage(total, used, free, percent)
|
return _common.sdiskusage(total, used, free, percent)
|
||||||
|
@ -159,18 +257,27 @@ def disk_partitions(all):
|
||||||
return [_common.sdiskpart(*x) for x in rawlist]
|
return [_common.sdiskpart(*x) for x in rawlist]
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- CPU
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
def cpu_times():
|
def cpu_times():
|
||||||
"""Return system CPU times as a named tuple."""
|
"""Return system CPU times as a named tuple."""
|
||||||
user, system, idle = cext.cpu_times()
|
user, system, idle = cext.cpu_times()
|
||||||
return scputimes(user, system, idle)
|
# Internally, GetSystemTimes() is used, and it doesn't return
|
||||||
|
# interrupt and dpc times. cext.per_cpu_times() does, so we
|
||||||
|
# rely on it to get those only.
|
||||||
|
percpu_summed = scputimes(*[sum(n) for n in zip(*cext.per_cpu_times())])
|
||||||
|
return scputimes(user, system, idle,
|
||||||
|
percpu_summed.interrupt, percpu_summed.dpc)
|
||||||
|
|
||||||
|
|
||||||
def per_cpu_times():
|
def per_cpu_times():
|
||||||
"""Return system per-CPU times as a list of named tuples."""
|
"""Return system per-CPU times as a list of named tuples."""
|
||||||
ret = []
|
ret = []
|
||||||
for cpu_t in cext.per_cpu_times():
|
for user, system, idle, interrupt, dpc in cext.per_cpu_times():
|
||||||
user, system, idle = cpu_t
|
item = scputimes(user, system, idle, interrupt, dpc)
|
||||||
item = scputimes(user, system, idle)
|
|
||||||
ret.append(item)
|
ret.append(item)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@ -185,9 +292,26 @@ def cpu_count_physical():
|
||||||
return cext.cpu_count_phys()
|
return cext.cpu_count_phys()
|
||||||
|
|
||||||
|
|
||||||
def boot_time():
|
def cpu_stats():
|
||||||
"""The system boot time expressed in seconds since the epoch."""
|
"""Return CPU statistics."""
|
||||||
return cext.boot_time()
|
ctx_switches, interrupts, dpcs, syscalls = cext.cpu_stats()
|
||||||
|
soft_interrupts = 0
|
||||||
|
return _common.scpustats(ctx_switches, interrupts, soft_interrupts,
|
||||||
|
syscalls)
|
||||||
|
|
||||||
|
|
||||||
|
def cpu_freq():
|
||||||
|
"""Return CPU frequency.
|
||||||
|
On Windows per-cpu frequency is not supported.
|
||||||
|
"""
|
||||||
|
curr, max_ = cext.cpu_freq()
|
||||||
|
min_ = 0.0
|
||||||
|
return [_common.scpufreq(float(curr), min_, float(max_))]
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- network
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
def net_connections(kind, _pid=-1):
|
def net_connections(kind, _pid=-1):
|
||||||
|
@ -202,6 +326,10 @@ def net_connections(kind, _pid=-1):
|
||||||
ret = set()
|
ret = set()
|
||||||
for item in rawlist:
|
for item in rawlist:
|
||||||
fd, fam, type, laddr, raddr, status, pid = item
|
fd, fam, type, laddr, raddr, status, pid = item
|
||||||
|
if laddr:
|
||||||
|
laddr = _common.addr(*laddr)
|
||||||
|
if raddr:
|
||||||
|
raddr = _common.addr(*raddr)
|
||||||
status = TCP_STATUSES[status]
|
status = TCP_STATUSES[status]
|
||||||
fam = sockfam_to_enum(fam)
|
fam = sockfam_to_enum(fam)
|
||||||
type = socktype_to_enum(type)
|
type = socktype_to_enum(type)
|
||||||
|
@ -214,8 +342,13 @@ def net_connections(kind, _pid=-1):
|
||||||
|
|
||||||
|
|
||||||
def net_if_stats():
|
def net_if_stats():
|
||||||
ret = cext.net_if_stats()
|
"""Get NIC stats (isup, duplex, speed, mtu)."""
|
||||||
for name, items in ret.items():
|
ret = {}
|
||||||
|
rawdict = cext.net_if_stats()
|
||||||
|
for name, items in rawdict.items():
|
||||||
|
if not PY3:
|
||||||
|
assert isinstance(name, unicode), type(name)
|
||||||
|
name = py2_strencode(name)
|
||||||
isup, duplex, speed, mtu = items
|
isup, duplex, speed, mtu = items
|
||||||
if hasattr(_common, 'NicDuplex'):
|
if hasattr(_common, 'NicDuplex'):
|
||||||
duplex = _common.NicDuplex(duplex)
|
duplex = _common.NicDuplex(duplex)
|
||||||
|
@ -223,23 +356,273 @@ def net_if_stats():
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def net_io_counters():
|
||||||
|
"""Return network I/O statistics for every network interface
|
||||||
|
installed on the system as a dict of raw tuples.
|
||||||
|
"""
|
||||||
|
ret = cext.net_io_counters()
|
||||||
|
return dict([(py2_strencode(k), v) for k, v in ret.items()])
|
||||||
|
|
||||||
|
|
||||||
|
def net_if_addrs():
|
||||||
|
"""Return the addresses associated to each NIC."""
|
||||||
|
ret = []
|
||||||
|
for items in cext.net_if_addrs():
|
||||||
|
items = list(items)
|
||||||
|
items[0] = py2_strencode(items[0])
|
||||||
|
ret.append(items)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- sensors
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def sensors_battery():
|
||||||
|
"""Return battery information."""
|
||||||
|
# For constants meaning see:
|
||||||
|
# https://msdn.microsoft.com/en-us/library/windows/desktop/
|
||||||
|
# aa373232(v=vs.85).aspx
|
||||||
|
acline_status, flags, percent, secsleft = cext.sensors_battery()
|
||||||
|
power_plugged = acline_status == 1
|
||||||
|
no_battery = bool(flags & 128)
|
||||||
|
charging = bool(flags & 8)
|
||||||
|
|
||||||
|
if no_battery:
|
||||||
|
return None
|
||||||
|
if power_plugged or charging:
|
||||||
|
secsleft = _common.POWER_TIME_UNLIMITED
|
||||||
|
elif secsleft == -1:
|
||||||
|
secsleft = _common.POWER_TIME_UNKNOWN
|
||||||
|
|
||||||
|
return _common.sbattery(percent, secsleft, power_plugged)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- other system functions
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
_last_btime = 0
|
||||||
|
|
||||||
|
|
||||||
|
def boot_time():
|
||||||
|
"""The system boot time expressed in seconds since the epoch."""
|
||||||
|
# This dirty hack is to adjust the precision of the returned
|
||||||
|
# value which may have a 1 second fluctuation, see:
|
||||||
|
# https://github.com/giampaolo/psutil/issues/1007
|
||||||
|
global _last_btime
|
||||||
|
ret = float(cext.boot_time())
|
||||||
|
if abs(ret - _last_btime) <= 1:
|
||||||
|
return _last_btime
|
||||||
|
else:
|
||||||
|
_last_btime = ret
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def users():
|
def users():
|
||||||
"""Return currently connected users as a list of namedtuples."""
|
"""Return currently connected users as a list of namedtuples."""
|
||||||
retlist = []
|
retlist = []
|
||||||
rawlist = cext.users()
|
rawlist = cext.users()
|
||||||
for item in rawlist:
|
for item in rawlist:
|
||||||
user, hostname, tstamp = item
|
user, hostname, tstamp = item
|
||||||
nt = _common.suser(user, None, hostname, tstamp)
|
user = py2_strencode(user)
|
||||||
|
nt = _common.suser(user, None, hostname, tstamp, None)
|
||||||
retlist.append(nt)
|
retlist.append(nt)
|
||||||
return retlist
|
return retlist
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- Windows services
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
def win_service_iter():
|
||||||
|
"""Yields a list of WindowsService instances."""
|
||||||
|
for name, display_name in cext.winservice_enumerate():
|
||||||
|
yield WindowsService(py2_strencode(name), py2_strencode(display_name))
|
||||||
|
|
||||||
|
|
||||||
|
def win_service_get(name):
|
||||||
|
"""Open a Windows service and return it as a WindowsService instance."""
|
||||||
|
service = WindowsService(name, None)
|
||||||
|
service._display_name = service._query_config()['display_name']
|
||||||
|
return service
|
||||||
|
|
||||||
|
|
||||||
|
class WindowsService(object):
|
||||||
|
"""Represents an installed Windows service."""
|
||||||
|
|
||||||
|
def __init__(self, name, display_name):
|
||||||
|
self._name = name
|
||||||
|
self._display_name = display_name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
details = "(name=%r, display_name=%r)" % (
|
||||||
|
self._name, self._display_name)
|
||||||
|
return "%s%s" % (self.__class__.__name__, details)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<%s at %s>" % (self.__str__(), id(self))
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
# Test for equality with another WindosService object based
|
||||||
|
# on name.
|
||||||
|
if not isinstance(other, WindowsService):
|
||||||
|
return NotImplemented
|
||||||
|
return self._name == other._name
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return not self == other
|
||||||
|
|
||||||
|
def _query_config(self):
|
||||||
|
with self._wrap_exceptions():
|
||||||
|
display_name, binpath, username, start_type = \
|
||||||
|
cext.winservice_query_config(self._name)
|
||||||
|
# XXX - update _self.display_name?
|
||||||
|
return dict(
|
||||||
|
display_name=py2_strencode(display_name),
|
||||||
|
binpath=py2_strencode(binpath),
|
||||||
|
username=py2_strencode(username),
|
||||||
|
start_type=py2_strencode(start_type))
|
||||||
|
|
||||||
|
def _query_status(self):
|
||||||
|
with self._wrap_exceptions():
|
||||||
|
status, pid = cext.winservice_query_status(self._name)
|
||||||
|
if pid == 0:
|
||||||
|
pid = None
|
||||||
|
return dict(status=status, pid=pid)
|
||||||
|
|
||||||
|
@contextlib.contextmanager
|
||||||
|
def _wrap_exceptions(self):
|
||||||
|
"""Ctx manager which translates bare OSError and WindowsError
|
||||||
|
exceptions into NoSuchProcess and AccessDenied.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except WindowsError as err:
|
||||||
|
if err.errno in ACCESS_DENIED_ERRSET:
|
||||||
|
raise AccessDenied(
|
||||||
|
pid=None, name=self._name,
|
||||||
|
msg="service %r is not querable (not enough privileges)" %
|
||||||
|
self._name)
|
||||||
|
elif err.errno in NO_SUCH_SERVICE_ERRSET or \
|
||||||
|
err.winerror in NO_SUCH_SERVICE_ERRSET:
|
||||||
|
raise NoSuchProcess(
|
||||||
|
pid=None, name=self._name,
|
||||||
|
msg="service %r does not exist)" % self._name)
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
# config query
|
||||||
|
|
||||||
|
def name(self):
|
||||||
|
"""The service name. This string is how a service is referenced
|
||||||
|
and can be passed to win_service_get() to get a new
|
||||||
|
WindowsService instance.
|
||||||
|
"""
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
def display_name(self):
|
||||||
|
"""The service display name. The value is cached when this class
|
||||||
|
is instantiated.
|
||||||
|
"""
|
||||||
|
return self._display_name
|
||||||
|
|
||||||
|
def binpath(self):
|
||||||
|
"""The fully qualified path to the service binary/exe file as
|
||||||
|
a string, including command line arguments.
|
||||||
|
"""
|
||||||
|
return self._query_config()['binpath']
|
||||||
|
|
||||||
|
def username(self):
|
||||||
|
"""The name of the user that owns this service."""
|
||||||
|
return self._query_config()['username']
|
||||||
|
|
||||||
|
def start_type(self):
|
||||||
|
"""A string which can either be "automatic", "manual" or
|
||||||
|
"disabled".
|
||||||
|
"""
|
||||||
|
return self._query_config()['start_type']
|
||||||
|
|
||||||
|
# status query
|
||||||
|
|
||||||
|
def pid(self):
|
||||||
|
"""The process PID, if any, else None. This can be passed
|
||||||
|
to Process class to control the service's process.
|
||||||
|
"""
|
||||||
|
return self._query_status()['pid']
|
||||||
|
|
||||||
|
def status(self):
|
||||||
|
"""Service status as a string."""
|
||||||
|
return self._query_status()['status']
|
||||||
|
|
||||||
|
def description(self):
|
||||||
|
"""Service long description."""
|
||||||
|
return py2_strencode(cext.winservice_query_descr(self.name()))
|
||||||
|
|
||||||
|
# utils
|
||||||
|
|
||||||
|
def as_dict(self):
|
||||||
|
"""Utility method retrieving all the information above as a
|
||||||
|
dictionary.
|
||||||
|
"""
|
||||||
|
d = self._query_config()
|
||||||
|
d.update(self._query_status())
|
||||||
|
d['name'] = self.name()
|
||||||
|
d['display_name'] = self.display_name()
|
||||||
|
d['description'] = self.description()
|
||||||
|
return d
|
||||||
|
|
||||||
|
# actions
|
||||||
|
# XXX: the necessary C bindings for start() and stop() are
|
||||||
|
# implemented but for now I prefer not to expose them.
|
||||||
|
# I may change my mind in the future. Reasons:
|
||||||
|
# - they require Administrator privileges
|
||||||
|
# - can't implement a timeout for stop() (unless by using a thread,
|
||||||
|
# which sucks)
|
||||||
|
# - would require adding ServiceAlreadyStarted and
|
||||||
|
# ServiceAlreadyStopped exceptions, adding two new APIs.
|
||||||
|
# - we might also want to have modify(), which would basically mean
|
||||||
|
# rewriting win32serviceutil.ChangeServiceConfig, which involves a
|
||||||
|
# lot of stuff (and API constants which would pollute the API), see:
|
||||||
|
# http://pyxr.sourceforge.net/PyXR/c/python24/lib/site-packages/
|
||||||
|
# win32/lib/win32serviceutil.py.html#0175
|
||||||
|
# - psutil is typically about "read only" monitoring stuff;
|
||||||
|
# win_service_* APIs should only be used to retrieve a service and
|
||||||
|
# check whether it's running
|
||||||
|
|
||||||
|
# def start(self, timeout=None):
|
||||||
|
# with self._wrap_exceptions():
|
||||||
|
# cext.winservice_start(self.name())
|
||||||
|
# if timeout:
|
||||||
|
# giveup_at = time.time() + timeout
|
||||||
|
# while True:
|
||||||
|
# if self.status() == "running":
|
||||||
|
# return
|
||||||
|
# else:
|
||||||
|
# if time.time() > giveup_at:
|
||||||
|
# raise TimeoutExpired(timeout)
|
||||||
|
# else:
|
||||||
|
# time.sleep(.1)
|
||||||
|
|
||||||
|
# def stop(self):
|
||||||
|
# # Note: timeout is not implemented because it's just not
|
||||||
|
# # possible, see:
|
||||||
|
# # http://stackoverflow.com/questions/11973228/
|
||||||
|
# with self._wrap_exceptions():
|
||||||
|
# return cext.winservice_stop(self.name())
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- processes
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
pids = cext.pids
|
pids = cext.pids
|
||||||
pid_exists = cext.pid_exists
|
pid_exists = cext.pid_exists
|
||||||
net_io_counters = cext.net_io_counters
|
ppid_map = cext.ppid_map # used internally by Process.children()
|
||||||
disk_io_counters = cext.disk_io_counters
|
|
||||||
ppid_map = cext.ppid_map # not meant to be public
|
|
||||||
net_if_addrs = cext.net_if_addrs
|
|
||||||
|
|
||||||
|
|
||||||
def wrap_exceptions(fun):
|
def wrap_exceptions(fun):
|
||||||
|
@ -251,10 +634,7 @@ def wrap_exceptions(fun):
|
||||||
try:
|
try:
|
||||||
return fun(self, *args, **kwargs)
|
return fun(self, *args, **kwargs)
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
# support for private module import
|
if err.errno in ACCESS_DENIED_ERRSET:
|
||||||
if NoSuchProcess is None or AccessDenied is None:
|
|
||||||
raise
|
|
||||||
if err.errno in ACCESS_DENIED_SET:
|
|
||||||
raise AccessDenied(self.pid, self._name)
|
raise AccessDenied(self.pid, self._name)
|
||||||
if err.errno == errno.ESRCH:
|
if err.errno == errno.ESRCH:
|
||||||
raise NoSuchProcess(self.pid, self._name)
|
raise NoSuchProcess(self.pid, self._name)
|
||||||
|
@ -272,6 +652,23 @@ class Process(object):
|
||||||
self._name = None
|
self._name = None
|
||||||
self._ppid = None
|
self._ppid = None
|
||||||
|
|
||||||
|
# --- oneshot() stuff
|
||||||
|
|
||||||
|
def oneshot_enter(self):
|
||||||
|
self.oneshot_info.cache_activate()
|
||||||
|
|
||||||
|
def oneshot_exit(self):
|
||||||
|
self.oneshot_info.cache_deactivate()
|
||||||
|
|
||||||
|
@memoize_when_activated
|
||||||
|
def oneshot_info(self):
|
||||||
|
"""Return multiple information about this process as a
|
||||||
|
raw tuple.
|
||||||
|
"""
|
||||||
|
ret = cext.proc_info(self.pid)
|
||||||
|
assert len(ret) == len(pinfo_map)
|
||||||
|
return ret
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def name(self):
|
def name(self):
|
||||||
"""Return process name, which on Windows is always the final
|
"""Return process name, which on Windows is always the final
|
||||||
|
@ -287,9 +684,9 @@ class Process(object):
|
||||||
try:
|
try:
|
||||||
# Note: this will fail with AD for most PIDs owned
|
# Note: this will fail with AD for most PIDs owned
|
||||||
# by another user but it's faster.
|
# by another user but it's faster.
|
||||||
return os.path.basename(self.exe())
|
return py2_strencode(os.path.basename(self.exe()))
|
||||||
except AccessDenied:
|
except AccessDenied:
|
||||||
return cext.proc_name(self.pid)
|
return py2_strencode(cext.proc_name(self.pid))
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def exe(self):
|
def exe(self):
|
||||||
|
@ -301,11 +698,22 @@ class Process(object):
|
||||||
# see https://github.com/giampaolo/psutil/issues/528
|
# see https://github.com/giampaolo/psutil/issues/528
|
||||||
if self.pid in (0, 4):
|
if self.pid in (0, 4):
|
||||||
raise AccessDenied(self.pid, self._name)
|
raise AccessDenied(self.pid, self._name)
|
||||||
return _convert_raw_path(cext.proc_exe(self.pid))
|
return py2_strencode(convert_dos_path(cext.proc_exe(self.pid)))
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def cmdline(self):
|
def cmdline(self):
|
||||||
return cext.proc_cmdline(self.pid)
|
ret = cext.proc_cmdline(self.pid)
|
||||||
|
if PY3:
|
||||||
|
return ret
|
||||||
|
else:
|
||||||
|
return [py2_strencode(s) for s in ret]
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def environ(self):
|
||||||
|
ustr = cext.proc_environ(self.pid)
|
||||||
|
if ustr and not PY3:
|
||||||
|
assert isinstance(ustr, unicode), type(ustr)
|
||||||
|
return parse_environ_block(py2_strencode(ustr))
|
||||||
|
|
||||||
def ppid(self):
|
def ppid(self):
|
||||||
try:
|
try:
|
||||||
|
@ -317,24 +725,39 @@ class Process(object):
|
||||||
try:
|
try:
|
||||||
return cext.proc_memory_info(self.pid)
|
return cext.proc_memory_info(self.pid)
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
if err.errno in ACCESS_DENIED_SET:
|
if err.errno in ACCESS_DENIED_ERRSET:
|
||||||
# TODO: the C ext can probably be refactored in order
|
# TODO: the C ext can probably be refactored in order
|
||||||
# to get this from cext.proc_info()
|
# to get this from cext.proc_info()
|
||||||
return cext.proc_memory_info_2(self.pid)
|
info = self.oneshot_info()
|
||||||
|
return (
|
||||||
|
info[pinfo_map['num_page_faults']],
|
||||||
|
info[pinfo_map['peak_wset']],
|
||||||
|
info[pinfo_map['wset']],
|
||||||
|
info[pinfo_map['peak_paged_pool']],
|
||||||
|
info[pinfo_map['paged_pool']],
|
||||||
|
info[pinfo_map['peak_non_paged_pool']],
|
||||||
|
info[pinfo_map['non_paged_pool']],
|
||||||
|
info[pinfo_map['pagefile']],
|
||||||
|
info[pinfo_map['peak_pagefile']],
|
||||||
|
info[pinfo_map['mem_private']],
|
||||||
|
)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def memory_info(self):
|
def memory_info(self):
|
||||||
# on Windows RSS == WorkingSetSize and VSM == PagefileUsage
|
# on Windows RSS == WorkingSetSize and VSM == PagefileUsage.
|
||||||
# fields of PROCESS_MEMORY_COUNTERS struct:
|
# Underlying C function returns fields of PROCESS_MEMORY_COUNTERS
|
||||||
# http://msdn.microsoft.com/en-us/library/windows/desktop/
|
# struct.
|
||||||
# ms684877(v=vs.85).aspx
|
|
||||||
t = self._get_raw_meminfo()
|
t = self._get_raw_meminfo()
|
||||||
return _common.pmem(t[2], t[7])
|
rss = t[2] # wset
|
||||||
|
vms = t[7] # pagefile
|
||||||
|
return pmem(*(rss, vms, ) + t)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def memory_info_ex(self):
|
def memory_full_info(self):
|
||||||
return pextmem(*self._get_raw_meminfo())
|
basic_mem = self.memory_info()
|
||||||
|
uss = cext.proc_memory_uss(self.pid)
|
||||||
|
return pfullmem(*basic_mem + (uss, ))
|
||||||
|
|
||||||
def memory_maps(self):
|
def memory_maps(self):
|
||||||
try:
|
try:
|
||||||
|
@ -342,14 +765,17 @@ class Process(object):
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
# XXX - can't use wrap_exceptions decorator as we're
|
# XXX - can't use wrap_exceptions decorator as we're
|
||||||
# returning a generator; probably needs refactoring.
|
# returning a generator; probably needs refactoring.
|
||||||
if err.errno in ACCESS_DENIED_SET:
|
if err.errno in ACCESS_DENIED_ERRSET:
|
||||||
raise AccessDenied(self.pid, self._name)
|
raise AccessDenied(self.pid, self._name)
|
||||||
if err.errno == errno.ESRCH:
|
if err.errno == errno.ESRCH:
|
||||||
raise NoSuchProcess(self.pid, self._name)
|
raise NoSuchProcess(self.pid, self._name)
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
for addr, perm, path, rss in raw:
|
for addr, perm, path, rss in raw:
|
||||||
path = _convert_raw_path(path)
|
path = convert_dos_path(path)
|
||||||
|
if not PY3:
|
||||||
|
assert isinstance(path, unicode), type(path)
|
||||||
|
path = py2_strencode(path)
|
||||||
addr = hex(addr)
|
addr = hex(addr)
|
||||||
yield (addr, perm, path, rss)
|
yield (addr, perm, path, rss)
|
||||||
|
|
||||||
|
@ -357,26 +783,34 @@ class Process(object):
|
||||||
def kill(self):
|
def kill(self):
|
||||||
return cext.proc_kill(self.pid)
|
return cext.proc_kill(self.pid)
|
||||||
|
|
||||||
|
@wrap_exceptions
|
||||||
|
def send_signal(self, sig):
|
||||||
|
os.kill(self.pid, sig)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def wait(self, timeout=None):
|
def wait(self, timeout=None):
|
||||||
if timeout is None:
|
if timeout is None:
|
||||||
timeout = cext.INFINITE
|
cext_timeout = cext.INFINITE
|
||||||
else:
|
else:
|
||||||
# WaitForSingleObject() expects time in milliseconds
|
# WaitForSingleObject() expects time in milliseconds
|
||||||
timeout = int(timeout * 1000)
|
cext_timeout = int(timeout * 1000)
|
||||||
ret = cext.proc_wait(self.pid, timeout)
|
while True:
|
||||||
if ret == WAIT_TIMEOUT:
|
ret = cext.proc_wait(self.pid, cext_timeout)
|
||||||
# support for private module import
|
if ret == WAIT_TIMEOUT:
|
||||||
if TimeoutExpired is None:
|
raise TimeoutExpired(timeout, self.pid, self._name)
|
||||||
raise RuntimeError("timeout expired")
|
if pid_exists(self.pid):
|
||||||
raise TimeoutExpired(timeout, self.pid, self._name)
|
if timeout is None:
|
||||||
return ret
|
continue
|
||||||
|
else:
|
||||||
|
raise TimeoutExpired(timeout, self.pid, self._name)
|
||||||
|
return ret
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def username(self):
|
def username(self):
|
||||||
if self.pid in (0, 4):
|
if self.pid in (0, 4):
|
||||||
return 'NT AUTHORITY\\SYSTEM'
|
return 'NT AUTHORITY\\SYSTEM'
|
||||||
return cext.proc_username(self.pid)
|
domain, user = cext.proc_username(self.pid)
|
||||||
|
return py2_strencode(domain) + '\\' + py2_strencode(user)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def create_time(self):
|
def create_time(self):
|
||||||
|
@ -386,13 +820,13 @@ class Process(object):
|
||||||
try:
|
try:
|
||||||
return cext.proc_create_time(self.pid)
|
return cext.proc_create_time(self.pid)
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
if err.errno in ACCESS_DENIED_SET:
|
if err.errno in ACCESS_DENIED_ERRSET:
|
||||||
return ntpinfo(*cext.proc_info(self.pid)).create_time
|
return self.oneshot_info()[pinfo_map['create_time']]
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def num_threads(self):
|
def num_threads(self):
|
||||||
return ntpinfo(*cext.proc_info(self.pid)).num_threads
|
return self.oneshot_info()[pinfo_map['num_threads']]
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def threads(self):
|
def threads(self):
|
||||||
|
@ -406,14 +840,16 @@ class Process(object):
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def cpu_times(self):
|
def cpu_times(self):
|
||||||
try:
|
try:
|
||||||
ret = cext.proc_cpu_times(self.pid)
|
user, system = cext.proc_cpu_times(self.pid)
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
if err.errno in ACCESS_DENIED_SET:
|
if err.errno in ACCESS_DENIED_ERRSET:
|
||||||
nt = ntpinfo(*cext.proc_info(self.pid))
|
info = self.oneshot_info()
|
||||||
ret = (nt.user_time, nt.kernel_time)
|
user = info[pinfo_map['user_time']]
|
||||||
|
system = info[pinfo_map['kernel_time']]
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
return _common.pcputimes(*ret)
|
# Children user/system times are not retrievable (set to 0).
|
||||||
|
return _common.pcputimes(user, system, 0.0, 0.0)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def suspend(self):
|
def suspend(self):
|
||||||
|
@ -430,24 +866,26 @@ class Process(object):
|
||||||
# return a normalized pathname since the native C function appends
|
# return a normalized pathname since the native C function appends
|
||||||
# "\\" at the and of the path
|
# "\\" at the and of the path
|
||||||
path = cext.proc_cwd(self.pid)
|
path = cext.proc_cwd(self.pid)
|
||||||
return os.path.normpath(path)
|
return py2_strencode(os.path.normpath(path))
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def open_files(self):
|
def open_files(self):
|
||||||
if self.pid in (0, 4):
|
if self.pid in (0, 4):
|
||||||
return []
|
return []
|
||||||
retlist = []
|
ret = set()
|
||||||
# Filenames come in in native format like:
|
# Filenames come in in native format like:
|
||||||
# "\Device\HarddiskVolume1\Windows\systemew\file.txt"
|
# "\Device\HarddiskVolume1\Windows\systemew\file.txt"
|
||||||
# Convert the first part in the corresponding drive letter
|
# Convert the first part in the corresponding drive letter
|
||||||
# (e.g. "C:\") by using Windows's QueryDosDevice()
|
# (e.g. "C:\") by using Windows's QueryDosDevice()
|
||||||
raw_file_names = cext.proc_open_files(self.pid)
|
raw_file_names = cext.proc_open_files(self.pid)
|
||||||
for _file in raw_file_names:
|
for _file in raw_file_names:
|
||||||
_file = _convert_raw_path(_file)
|
_file = convert_dos_path(_file)
|
||||||
if isfile_strict(_file) and _file not in retlist:
|
if isfile_strict(_file):
|
||||||
|
if not PY3:
|
||||||
|
_file = py2_strencode(_file)
|
||||||
ntuple = _common.popenfile(_file, -1)
|
ntuple = _common.popenfile(_file, -1)
|
||||||
retlist.append(ntuple)
|
ret.add(ntuple)
|
||||||
return retlist
|
return list(ret)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def connections(self, kind='inet'):
|
def connections(self, kind='inet'):
|
||||||
|
@ -485,12 +923,19 @@ class Process(object):
|
||||||
try:
|
try:
|
||||||
ret = cext.proc_io_counters(self.pid)
|
ret = cext.proc_io_counters(self.pid)
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
if err.errno in ACCESS_DENIED_SET:
|
if err.errno in ACCESS_DENIED_ERRSET:
|
||||||
nt = ntpinfo(*cext.proc_info(self.pid))
|
info = self.oneshot_info()
|
||||||
ret = (nt.io_rcount, nt.io_wcount, nt.io_rbytes, nt.io_wbytes)
|
ret = (
|
||||||
|
info[pinfo_map['io_rcount']],
|
||||||
|
info[pinfo_map['io_wcount']],
|
||||||
|
info[pinfo_map['io_rbytes']],
|
||||||
|
info[pinfo_map['io_wbytes']],
|
||||||
|
info[pinfo_map['io_count_others']],
|
||||||
|
info[pinfo_map['io_bytes_others']],
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
return _common.pio(*ret)
|
return pio(*ret)
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def status(self):
|
def status(self):
|
||||||
|
@ -537,12 +982,12 @@ class Process(object):
|
||||||
try:
|
try:
|
||||||
return cext.proc_num_handles(self.pid)
|
return cext.proc_num_handles(self.pid)
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
if err.errno in ACCESS_DENIED_SET:
|
if err.errno in ACCESS_DENIED_ERRSET:
|
||||||
return ntpinfo(*cext.proc_info(self.pid)).num_handles
|
return self.oneshot_info()[pinfo_map['num_handles']]
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@wrap_exceptions
|
@wrap_exceptions
|
||||||
def num_ctx_switches(self):
|
def num_ctx_switches(self):
|
||||||
ctx_switches = ntpinfo(*cext.proc_info(self.pid)).ctx_switches
|
ctx_switches = self.oneshot_info()[pinfo_map['ctx_switches']]
|
||||||
# only voluntary ctx switches are supported
|
# only voluntary ctx switches are supported
|
||||||
return _common.pctxsw(ctx_switches, 0)
|
return _common.pctxsw(ctx_switches, 0)
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Arnon Yaari
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
#include <sys/core.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
/* psutil_kread() - read from kernel memory */
|
||||||
|
int
|
||||||
|
psutil_kread(
|
||||||
|
int Kd, /* kernel memory file descriptor */
|
||||||
|
KA_T addr, /* kernel memory address */
|
||||||
|
char *buf, /* buffer to receive data */
|
||||||
|
size_t len) { /* length to read */
|
||||||
|
int br;
|
||||||
|
|
||||||
|
if (lseek64(Kd, (off64_t)addr, L_SET) == (off64_t)-1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
br = read(Kd, buf, len);
|
||||||
|
if (br == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (br != len) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError,
|
||||||
|
"size mismatch when reading kernel memory fd");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct procentry64 *
|
||||||
|
psutil_read_process_table(int * num) {
|
||||||
|
size_t msz;
|
||||||
|
pid32_t pid = 0;
|
||||||
|
struct procentry64 *processes = (struct procentry64 *)NULL;
|
||||||
|
struct procentry64 *p;
|
||||||
|
int Np = 0; /* number of processes allocated in 'processes' */
|
||||||
|
int np = 0; /* number of processes read into 'processes' */
|
||||||
|
int i; /* number of processes read in current iteration */
|
||||||
|
|
||||||
|
msz = (size_t)(PROCSIZE * PROCINFO_INCR);
|
||||||
|
processes = (struct procentry64 *)malloc(msz);
|
||||||
|
if (!processes) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Np = PROCINFO_INCR;
|
||||||
|
p = processes;
|
||||||
|
while ((i = getprocs64(p, PROCSIZE, (struct fdsinfo64 *)NULL, 0, &pid,
|
||||||
|
PROCINFO_INCR))
|
||||||
|
== PROCINFO_INCR) {
|
||||||
|
np += PROCINFO_INCR;
|
||||||
|
if (np >= Np) {
|
||||||
|
msz = (size_t)(PROCSIZE * (Np + PROCINFO_INCR));
|
||||||
|
processes = (struct procentry64 *)realloc((char *)processes, msz);
|
||||||
|
if (!processes) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
Np += PROCINFO_INCR;
|
||||||
|
}
|
||||||
|
p = (struct procentry64 *)((char *)processes + (np * PROCSIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add the number of processes read in the last iteration */
|
||||||
|
if (i > 0)
|
||||||
|
np += i;
|
||||||
|
|
||||||
|
*num = np;
|
||||||
|
return processes;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Arnon Yaari
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PSUTIL_AIX_COMMON_H__
|
||||||
|
#define __PSUTIL_AIX_COMMON_H__
|
||||||
|
|
||||||
|
#include <sys/core.h>
|
||||||
|
|
||||||
|
#define PROCINFO_INCR (256)
|
||||||
|
#define PROCSIZE (sizeof(struct procentry64))
|
||||||
|
#define FDSINFOSIZE (sizeof(struct fdsinfo64))
|
||||||
|
#define KMEM "/dev/kmem"
|
||||||
|
|
||||||
|
typedef u_longlong_t KA_T;
|
||||||
|
|
||||||
|
/* psutil_kread() - read from kernel memory */
|
||||||
|
int psutil_kread(int Kd, /* kernel memory file descriptor */
|
||||||
|
KA_T addr, /* kernel memory address */
|
||||||
|
char *buf, /* buffer to receive data */
|
||||||
|
size_t len); /* length to read */
|
||||||
|
|
||||||
|
struct procentry64 *
|
||||||
|
psutil_read_process_table(
|
||||||
|
int * num /* out - number of processes read */
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif /* __PSUTIL_AIX_COMMON_H__ */
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Arnon Yaari
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! Based on code from
|
||||||
|
https://lists.samba.org/archive/samba-technical/2009-February/063079.html
|
||||||
|
!*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
#include "ifaddrs.h"
|
||||||
|
|
||||||
|
#define MAX(x,y) ((x)>(y)?(x):(y))
|
||||||
|
#define SIZE(p) MAX((p).sa_len,sizeof(p))
|
||||||
|
|
||||||
|
|
||||||
|
static struct sockaddr *
|
||||||
|
sa_dup(struct sockaddr *sa1)
|
||||||
|
{
|
||||||
|
struct sockaddr *sa2;
|
||||||
|
size_t sz = sa1->sa_len;
|
||||||
|
sa2 = (struct sockaddr *) calloc(1, sz);
|
||||||
|
if (sa2 == NULL)
|
||||||
|
return NULL;
|
||||||
|
memcpy(sa2, sa1, sz);
|
||||||
|
return sa2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void freeifaddrs(struct ifaddrs *ifp)
|
||||||
|
{
|
||||||
|
if (NULL == ifp) return;
|
||||||
|
free(ifp->ifa_name);
|
||||||
|
free(ifp->ifa_addr);
|
||||||
|
free(ifp->ifa_netmask);
|
||||||
|
free(ifp->ifa_dstaddr);
|
||||||
|
freeifaddrs(ifp->ifa_next);
|
||||||
|
free(ifp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int getifaddrs(struct ifaddrs **ifap)
|
||||||
|
{
|
||||||
|
int sd, ifsize;
|
||||||
|
char *ccp, *ecp;
|
||||||
|
struct ifconf ifc;
|
||||||
|
struct ifreq *ifr;
|
||||||
|
struct ifaddrs *cifa = NULL; /* current */
|
||||||
|
struct ifaddrs *pifa = NULL; /* previous */
|
||||||
|
const size_t IFREQSZ = sizeof(struct ifreq);
|
||||||
|
int fam;
|
||||||
|
|
||||||
|
*ifap = NULL;
|
||||||
|
|
||||||
|
sd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (sd == -1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* find how much memory to allocate for the SIOCGIFCONF call */
|
||||||
|
if (ioctl(sd, SIOCGSIZIFCONF, (caddr_t)&ifsize) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ifc.ifc_req = (struct ifreq *) calloc(1, ifsize);
|
||||||
|
if (ifc.ifc_req == NULL)
|
||||||
|
goto error;
|
||||||
|
ifc.ifc_len = ifsize;
|
||||||
|
|
||||||
|
if (ioctl(sd, SIOCGIFCONF, &ifc) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ccp = (char *)ifc.ifc_req;
|
||||||
|
ecp = ccp + ifsize;
|
||||||
|
|
||||||
|
while (ccp < ecp) {
|
||||||
|
|
||||||
|
ifr = (struct ifreq *) ccp;
|
||||||
|
ifsize = sizeof(ifr->ifr_name) + SIZE(ifr->ifr_addr);
|
||||||
|
fam = ifr->ifr_addr.sa_family;
|
||||||
|
|
||||||
|
if (fam == AF_INET || fam == AF_INET6) {
|
||||||
|
cifa = (struct ifaddrs *) calloc(1, sizeof(struct ifaddrs));
|
||||||
|
if (cifa == NULL)
|
||||||
|
goto error;
|
||||||
|
cifa->ifa_next = NULL;
|
||||||
|
|
||||||
|
if (pifa == NULL) *ifap = cifa; /* first one */
|
||||||
|
else pifa->ifa_next = cifa;
|
||||||
|
|
||||||
|
cifa->ifa_name = strdup(ifr->ifr_name);
|
||||||
|
if (cifa->ifa_name == NULL)
|
||||||
|
goto error;
|
||||||
|
cifa->ifa_flags = 0;
|
||||||
|
cifa->ifa_dstaddr = NULL;
|
||||||
|
|
||||||
|
cifa->ifa_addr = sa_dup(&ifr->ifr_addr);
|
||||||
|
if (cifa->ifa_addr == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (fam == AF_INET) {
|
||||||
|
if (ioctl(sd, SIOCGIFNETMASK, ifr, IFREQSZ) < 0)
|
||||||
|
goto error;
|
||||||
|
cifa->ifa_netmask = sa_dup(&ifr->ifr_addr);
|
||||||
|
if (cifa->ifa_netmask == NULL)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == ioctl(sd, SIOCGIFFLAGS, ifr)) /* optional */
|
||||||
|
cifa->ifa_flags = ifr->ifr_flags;
|
||||||
|
|
||||||
|
if (fam == AF_INET) {
|
||||||
|
if (ioctl(sd, SIOCGIFDSTADDR, ifr, IFREQSZ) < 0) {
|
||||||
|
if (0 == ioctl(sd, SIOCGIFBRDADDR, ifr, IFREQSZ)) {
|
||||||
|
cifa->ifa_dstaddr = sa_dup(&ifr->ifr_addr);
|
||||||
|
if (cifa->ifa_dstaddr == NULL)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cifa->ifa_dstaddr = sa_dup(&ifr->ifr_addr);
|
||||||
|
if (cifa->ifa_dstaddr == NULL)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pifa = cifa;
|
||||||
|
}
|
||||||
|
|
||||||
|
ccp += ifsize;
|
||||||
|
}
|
||||||
|
free(ifc.ifc_req);
|
||||||
|
close(sd);
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
if (ifc.ifc_req != NULL)
|
||||||
|
free(ifc.ifc_req);
|
||||||
|
if (sd != -1)
|
||||||
|
close(sd);
|
||||||
|
freeifaddrs(*ifap);
|
||||||
|
return (-1);
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Arnon Yaari
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! Based on code from
|
||||||
|
https://lists.samba.org/archive/samba-technical/2009-February/063079.html
|
||||||
|
!*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef GENERIC_AIX_IFADDRS_H
|
||||||
|
#define GENERIC_AIX_IFADDRS_H
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
|
||||||
|
#undef ifa_dstaddr
|
||||||
|
#undef ifa_broadaddr
|
||||||
|
#define ifa_broadaddr ifa_dstaddr
|
||||||
|
|
||||||
|
struct ifaddrs {
|
||||||
|
struct ifaddrs *ifa_next;
|
||||||
|
char *ifa_name;
|
||||||
|
unsigned int ifa_flags;
|
||||||
|
struct sockaddr *ifa_addr;
|
||||||
|
struct sockaddr *ifa_netmask;
|
||||||
|
struct sockaddr *ifa_dstaddr;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int getifaddrs(struct ifaddrs **);
|
||||||
|
extern void freeifaddrs(struct ifaddrs *);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,287 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Arnon Yaari
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Baded on code from lsof:
|
||||||
|
* http://www.ibm.com/developerworks/aix/library/au-lsof.html
|
||||||
|
* - dialects/aix/dproc.c:gather_proc_info
|
||||||
|
* - lib/prfp.c:process_file
|
||||||
|
* - dialects/aix/dsock.c:process_socket
|
||||||
|
* - dialects/aix/dproc.c:get_kernel_access
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#define _KERNEL
|
||||||
|
#include <sys/file.h>
|
||||||
|
#undef _KERNEL
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/core.h>
|
||||||
|
#include <sys/domain.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <netinet/in_pcb.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "../../_psutil_common.h"
|
||||||
|
#include "net_kernel_structs.h"
|
||||||
|
#include "net_connections.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define NO_SOCKET (PyObject *)(-1)
|
||||||
|
|
||||||
|
static int
|
||||||
|
read_unp_addr(
|
||||||
|
int Kd,
|
||||||
|
KA_T unp_addr,
|
||||||
|
char *buf,
|
||||||
|
size_t buflen
|
||||||
|
) {
|
||||||
|
struct sockaddr_un *ua = (struct sockaddr_un *)NULL;
|
||||||
|
struct sockaddr_un un;
|
||||||
|
struct mbuf64 mb;
|
||||||
|
int uo;
|
||||||
|
|
||||||
|
if (psutil_kread(Kd, unp_addr, (char *)&mb, sizeof(mb))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uo = (int)(mb.m_hdr.mh_data - unp_addr);
|
||||||
|
if ((uo + sizeof(struct sockaddr)) <= sizeof(mb))
|
||||||
|
ua = (struct sockaddr_un *)((char *)&mb + uo);
|
||||||
|
else {
|
||||||
|
if (psutil_kread(Kd, (KA_T)mb.m_hdr.mh_data,
|
||||||
|
(char *)&un, sizeof(un))) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
ua = &un;
|
||||||
|
}
|
||||||
|
if (ua && ua->sun_path[0]) {
|
||||||
|
if (mb.m_len > sizeof(struct sockaddr_un))
|
||||||
|
mb.m_len = sizeof(struct sockaddr_un);
|
||||||
|
*((char *)ua + mb.m_len - 1) = '\0';
|
||||||
|
snprintf(buf, buflen, "%s", ua->sun_path);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
process_file(int Kd, pid32_t pid, int fd, KA_T fp) {
|
||||||
|
struct file64 f;
|
||||||
|
struct socket64 s;
|
||||||
|
struct protosw64 p;
|
||||||
|
struct domain d;
|
||||||
|
struct inpcb64 inp;
|
||||||
|
int fam;
|
||||||
|
struct tcpcb64 t;
|
||||||
|
int state = PSUTIL_CONN_NONE;
|
||||||
|
unsigned char *laddr = (unsigned char *)NULL;
|
||||||
|
unsigned char *raddr = (unsigned char *)NULL;
|
||||||
|
int rport, lport;
|
||||||
|
char laddr_str[INET6_ADDRSTRLEN];
|
||||||
|
char raddr_str[INET6_ADDRSTRLEN];
|
||||||
|
struct unpcb64 unp;
|
||||||
|
char unix_laddr_str[PATH_MAX] = { 0 };
|
||||||
|
char unix_raddr_str[PATH_MAX] = { 0 };
|
||||||
|
|
||||||
|
/* Read file structure */
|
||||||
|
if (psutil_kread(Kd, fp, (char *)&f, sizeof(f))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!f.f_count || f.f_type != DTYPE_SOCKET) {
|
||||||
|
return NO_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (psutil_kread(Kd, (KA_T) f.f_data, (char *) &s, sizeof(s))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!s.so_type) {
|
||||||
|
return NO_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!s.so_proto) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "invalid socket protocol handle");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (psutil_kread(Kd, (KA_T)s.so_proto, (char *)&p, sizeof(p))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p.pr_domain) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "invalid socket protocol domain");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (psutil_kread(Kd, (KA_T)p.pr_domain, (char *)&d, sizeof(d))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fam = d.dom_family;
|
||||||
|
if (fam == AF_INET || fam == AF_INET6) {
|
||||||
|
/* Read protocol control block */
|
||||||
|
if (!s.so_pcb) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "invalid socket PCB");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (psutil_kread(Kd, (KA_T) s.so_pcb, (char *) &inp, sizeof(inp))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.pr_protocol == IPPROTO_TCP) {
|
||||||
|
/* If this is a TCP socket, read its control block */
|
||||||
|
if (inp.inp_ppcb
|
||||||
|
&& !psutil_kread(Kd, (KA_T)inp.inp_ppcb,
|
||||||
|
(char *)&t, sizeof(t)))
|
||||||
|
state = t.t_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fam == AF_INET6) {
|
||||||
|
laddr = (unsigned char *)&inp.inp_laddr6;
|
||||||
|
if (!IN6_IS_ADDR_UNSPECIFIED(&inp.inp_faddr6)) {
|
||||||
|
raddr = (unsigned char *)&inp.inp_faddr6;
|
||||||
|
rport = (int)ntohs(inp.inp_fport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fam == AF_INET) {
|
||||||
|
laddr = (unsigned char *)&inp.inp_laddr;
|
||||||
|
if (inp.inp_faddr.s_addr != INADDR_ANY || inp.inp_fport != 0) {
|
||||||
|
raddr = (unsigned char *)&inp.inp_faddr;
|
||||||
|
rport = (int)ntohs(inp.inp_fport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lport = (int)ntohs(inp.inp_lport);
|
||||||
|
|
||||||
|
inet_ntop(fam, laddr, laddr_str, sizeof(laddr_str));
|
||||||
|
|
||||||
|
if (raddr != NULL) {
|
||||||
|
inet_ntop(fam, raddr, raddr_str, sizeof(raddr_str));
|
||||||
|
return Py_BuildValue("(iii(si)(si)ii)", fd, fam,
|
||||||
|
s.so_type, laddr_str, lport, raddr_str,
|
||||||
|
rport, state, pid);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Py_BuildValue("(iii(si)()ii)", fd, fam,
|
||||||
|
s.so_type, laddr_str, lport, state,
|
||||||
|
pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (fam == AF_UNIX) {
|
||||||
|
if (psutil_kread(Kd, (KA_T) s.so_pcb, (char *)&unp, sizeof(unp))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if ((KA_T) f.f_data != (KA_T) unp.unp_socket) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "unp_socket mismatch");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unp.unp_addr) {
|
||||||
|
if (read_unp_addr(Kd, unp.unp_addr, unix_laddr_str,
|
||||||
|
sizeof(unix_laddr_str))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unp.unp_conn) {
|
||||||
|
if (psutil_kread(Kd, (KA_T) unp.unp_conn, (char *)&unp,
|
||||||
|
sizeof(unp))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (read_unp_addr(Kd, unp.unp_addr, unix_raddr_str,
|
||||||
|
sizeof(unix_raddr_str))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Py_BuildValue("(iiissii)", fd, d.dom_family,
|
||||||
|
s.so_type, unix_laddr_str, unix_raddr_str, PSUTIL_CONN_NONE,
|
||||||
|
pid);
|
||||||
|
}
|
||||||
|
return NO_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_net_connections(PyObject *self, PyObject *args) {
|
||||||
|
PyObject *py_retlist = PyList_New(0);
|
||||||
|
PyObject *py_tuple = NULL;
|
||||||
|
KA_T fp;
|
||||||
|
int Kd = -1;
|
||||||
|
int i, np;
|
||||||
|
struct procentry64 *p;
|
||||||
|
struct fdsinfo64 *fds = (struct fdsinfo64 *)NULL;
|
||||||
|
pid32_t requested_pid;
|
||||||
|
pid32_t pid;
|
||||||
|
struct procentry64 *processes = (struct procentry64 *)NULL;
|
||||||
|
/* the process table */
|
||||||
|
|
||||||
|
if (py_retlist == NULL)
|
||||||
|
goto error;
|
||||||
|
if (! PyArg_ParseTuple(args, "i", &requested_pid))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
Kd = open(KMEM, O_RDONLY, 0);
|
||||||
|
if (Kd < 0) {
|
||||||
|
PyErr_SetFromErrnoWithFilename(PyExc_OSError, KMEM);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
processes = psutil_read_process_table(&np);
|
||||||
|
if (!processes)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Loop through processes */
|
||||||
|
for (p = processes; np > 0; np--, p++) {
|
||||||
|
pid = p->pi_pid;
|
||||||
|
if (requested_pid != -1 && requested_pid != pid)
|
||||||
|
continue;
|
||||||
|
if (p->pi_state == 0 || p->pi_state == SZOMB)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!fds) {
|
||||||
|
fds = (struct fdsinfo64 *)malloc((size_t)FDSINFOSIZE);
|
||||||
|
if (!fds) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getprocs64((struct procentry64 *)NULL, PROCSIZE, fds, FDSINFOSIZE,
|
||||||
|
&pid, 1)
|
||||||
|
!= 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* loop over file descriptors */
|
||||||
|
for (i = 0; i < p->pi_maxofile; i++) {
|
||||||
|
fp = (KA_T)fds->pi_ufd[i].fp;
|
||||||
|
if (fp) {
|
||||||
|
py_tuple = process_file(Kd, p->pi_pid, i, fp);
|
||||||
|
if (py_tuple == NULL)
|
||||||
|
goto error;
|
||||||
|
if (py_tuple != NO_SOCKET) {
|
||||||
|
if (PyList_Append(py_retlist, py_tuple))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_tuple);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(Kd);
|
||||||
|
free(processes);
|
||||||
|
if (fds != NULL)
|
||||||
|
free(fds);
|
||||||
|
return py_retlist;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_tuple);
|
||||||
|
Py_DECREF(py_retlist);
|
||||||
|
if (Kd > 0)
|
||||||
|
close(Kd);
|
||||||
|
if (processes != NULL)
|
||||||
|
free(processes);
|
||||||
|
if (fds != NULL)
|
||||||
|
free(fds);
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Arnon Yaari
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NET_CONNECTIONS_H__
|
||||||
|
#define __NET_CONNECTIONS_H__
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
PyObject* psutil_net_connections(PyObject *self, PyObject *args);
|
||||||
|
|
||||||
|
#endif /* __NET_CONNECTIONS_H__ */
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, Arnon Yaari
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The kernel is always 64 bit but Python is usually compiled as a 32 bit
|
||||||
|
* process. We're reading the kernel memory to get the network connections,
|
||||||
|
* so we need the structs we read to be defined with 64 bit "pointers".
|
||||||
|
* Here are the partial definitions of the structs we use, taken from the
|
||||||
|
* header files, with data type sizes converted to their 64 bit counterparts,
|
||||||
|
* and unused data truncated. */
|
||||||
|
|
||||||
|
#ifdef __64BIT__
|
||||||
|
/* In case we're in a 64 bit process after all */
|
||||||
|
#include <sys/socketvar.h>
|
||||||
|
#include <sys/protosw.h>
|
||||||
|
#include <sys/unpcb.h>
|
||||||
|
#include <sys/mbuf_base.h>
|
||||||
|
#include <netinet/ip_var.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <netinet/tcpip.h>
|
||||||
|
#include <netinet/tcp_timer.h>
|
||||||
|
#include <netinet/tcp_var.h>
|
||||||
|
#define file64 file
|
||||||
|
#define socket64 socket
|
||||||
|
#define protosw64 protosw
|
||||||
|
#define inpcb64 inpcb
|
||||||
|
#define tcpcb64 tcpcb
|
||||||
|
#define unpcb64 unpcb
|
||||||
|
#define mbuf64 mbuf
|
||||||
|
#else
|
||||||
|
struct file64 {
|
||||||
|
int f_flag;
|
||||||
|
int f_count;
|
||||||
|
int f_options;
|
||||||
|
int f_type;
|
||||||
|
u_longlong_t f_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct socket64 {
|
||||||
|
short so_type; /* generic type, see socket.h */
|
||||||
|
short so_options; /* from socket call, see socket.h */
|
||||||
|
ushort so_linger; /* time to linger while closing */
|
||||||
|
short so_state; /* internal state flags SS_*, below */
|
||||||
|
u_longlong_t so_pcb; /* protocol control block */
|
||||||
|
u_longlong_t so_proto; /* protocol handle */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct protosw64 {
|
||||||
|
short pr_type; /* socket type used for */
|
||||||
|
u_longlong_t pr_domain; /* domain protocol a member of */
|
||||||
|
short pr_protocol; /* protocol number */
|
||||||
|
short pr_flags; /* see below */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct inpcb64 {
|
||||||
|
u_longlong_t inp_next,inp_prev;
|
||||||
|
/* pointers to other pcb's */
|
||||||
|
u_longlong_t inp_head; /* pointer back to chain of inpcb's
|
||||||
|
for this protocol */
|
||||||
|
u_int32_t inp_iflowinfo; /* input flow label */
|
||||||
|
u_short inp_fport; /* foreign port */
|
||||||
|
u_int16_t inp_fatype; /* foreign address type */
|
||||||
|
union in_addr_6 inp_faddr_6; /* foreign host table entry */
|
||||||
|
u_int32_t inp_oflowinfo; /* output flow label */
|
||||||
|
u_short inp_lport; /* local port */
|
||||||
|
u_int16_t inp_latype; /* local address type */
|
||||||
|
union in_addr_6 inp_laddr_6; /* local host table entry */
|
||||||
|
u_longlong_t inp_socket; /* back pointer to socket */
|
||||||
|
u_longlong_t inp_ppcb; /* pointer to per-protocol pcb */
|
||||||
|
u_longlong_t space_rt;
|
||||||
|
struct sockaddr_in6 spare_dst;
|
||||||
|
u_longlong_t inp_ifa; /* interface address to use */
|
||||||
|
int inp_flags; /* generic IP/datagram flags */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tcpcb64 {
|
||||||
|
u_longlong_t seg__next;
|
||||||
|
u_longlong_t seg__prev;
|
||||||
|
short t_state; /* state of this connection */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct unpcb64 {
|
||||||
|
u_longlong_t unp_socket; /* pointer back to socket */
|
||||||
|
u_longlong_t unp_vnode; /* if associated with file */
|
||||||
|
ino_t unp_vno; /* fake vnode number */
|
||||||
|
u_longlong_t unp_conn; /* control block of connected socket */
|
||||||
|
u_longlong_t unp_refs; /* referencing socket linked list */
|
||||||
|
u_longlong_t unp_nextref; /* link in unp_refs list */
|
||||||
|
u_longlong_t unp_addr; /* bound address of socket */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct m_hdr64
|
||||||
|
{
|
||||||
|
u_longlong_t mh_next; /* next buffer in chain */
|
||||||
|
u_longlong_t mh_nextpkt; /* next chain in queue/record */
|
||||||
|
long mh_len; /* amount of data in this mbuf */
|
||||||
|
u_longlong_t mh_data; /* location of data */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mbuf64
|
||||||
|
{
|
||||||
|
struct m_hdr64 m_hdr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define m_len m_hdr.mh_len
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,265 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*
|
|
||||||
* Helper functions related to fetching process information.
|
|
||||||
* Used by _psutil_bsd module methods.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <Python.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/sysctl.h>
|
|
||||||
#include <sys/param.h>
|
|
||||||
#include <sys/user.h>
|
|
||||||
#include <sys/proc.h>
|
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
#include "process_info.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns a list of all BSD processes on the system. This routine
|
|
||||||
* allocates the list and puts it in *procList and a count of the
|
|
||||||
* number of entries in *procCount. You are responsible for freeing
|
|
||||||
* this list (use "free" from System framework).
|
|
||||||
* On success, the function returns 0.
|
|
||||||
* On error, the function returns a BSD errno value.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
struct kinfo_proc *result;
|
|
||||||
int done;
|
|
||||||
static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 };
|
|
||||||
// Declaring name as const requires us to cast it when passing it to
|
|
||||||
// sysctl because the prototype doesn't include the const modifier.
|
|
||||||
size_t length;
|
|
||||||
|
|
||||||
assert( procList != NULL);
|
|
||||||
assert(*procList == NULL);
|
|
||||||
assert(procCount != NULL);
|
|
||||||
|
|
||||||
*procCount = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We start by calling sysctl with result == NULL and length == 0.
|
|
||||||
* That will succeed, and set length to the appropriate length.
|
|
||||||
* We then allocate a buffer of that size and call sysctl again
|
|
||||||
* with that buffer. If that succeeds, we're done. If that fails
|
|
||||||
* with ENOMEM, we have to throw away our buffer and loop. Note
|
|
||||||
* that the loop causes use to call sysctl with NULL again; this
|
|
||||||
* is necessary because the ENOMEM failure case sets length to
|
|
||||||
* the amount of data returned, not the amount of data that
|
|
||||||
* could have been returned.
|
|
||||||
*/
|
|
||||||
result = NULL;
|
|
||||||
done = 0;
|
|
||||||
do {
|
|
||||||
assert(result == NULL);
|
|
||||||
// Call sysctl with a NULL buffer.
|
|
||||||
length = 0;
|
|
||||||
err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1,
|
|
||||||
NULL, &length, NULL, 0);
|
|
||||||
if (err == -1)
|
|
||||||
err = errno;
|
|
||||||
|
|
||||||
// Allocate an appropriately sized buffer based on the results
|
|
||||||
// from the previous call.
|
|
||||||
if (err == 0) {
|
|
||||||
result = malloc(length);
|
|
||||||
if (result == NULL)
|
|
||||||
err = ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call sysctl again with the new buffer. If we get an ENOMEM
|
|
||||||
// error, toss away our buffer and start again.
|
|
||||||
if (err == 0) {
|
|
||||||
err = sysctl((int *) name, (sizeof(name) / sizeof(*name)) - 1,
|
|
||||||
result, &length, NULL, 0);
|
|
||||||
if (err == -1)
|
|
||||||
err = errno;
|
|
||||||
if (err == 0) {
|
|
||||||
done = 1;
|
|
||||||
}
|
|
||||||
else if (err == ENOMEM) {
|
|
||||||
assert(result != NULL);
|
|
||||||
free(result);
|
|
||||||
result = NULL;
|
|
||||||
err = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (err == 0 && ! done);
|
|
||||||
|
|
||||||
// Clean up and establish post conditions.
|
|
||||||
if (err != 0 && result != NULL) {
|
|
||||||
free(result);
|
|
||||||
result = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*procList = result;
|
|
||||||
*procCount = length / sizeof(struct kinfo_proc);
|
|
||||||
|
|
||||||
assert((err == 0) == (*procList != NULL));
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char
|
|
||||||
*psutil_get_cmd_path(long pid, size_t *pathsize)
|
|
||||||
{
|
|
||||||
int mib[4];
|
|
||||||
char *path;
|
|
||||||
size_t size = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make a sysctl() call to get the raw argument space of the process.
|
|
||||||
*/
|
|
||||||
mib[0] = CTL_KERN;
|
|
||||||
mib[1] = KERN_PROC;
|
|
||||||
mib[2] = KERN_PROC_PATHNAME;
|
|
||||||
mib[3] = pid;
|
|
||||||
|
|
||||||
// call with a null buffer first to determine if we need a buffer
|
|
||||||
if (sysctl(mib, 4, NULL, &size, NULL, 0) == -1)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
path = malloc(size);
|
|
||||||
if (path == NULL) {
|
|
||||||
PyErr_NoMemory();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*pathsize = size;
|
|
||||||
if (sysctl(mib, 4, path, &size, NULL, 0) == -1) {
|
|
||||||
free(path);
|
|
||||||
return NULL; // Insufficient privileges
|
|
||||||
}
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX no longer used; it probably makese sense to remove it.
|
|
||||||
* Borrowed from psi Python System Information project
|
|
||||||
*
|
|
||||||
* Get command arguments and environment variables.
|
|
||||||
*
|
|
||||||
* Based on code from ps.
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* 0 for success;
|
|
||||||
* -1 for failure (Exception raised);
|
|
||||||
* 1 for insufficient privileges.
|
|
||||||
*/
|
|
||||||
char
|
|
||||||
*psutil_get_cmd_args(long pid, size_t *argsize)
|
|
||||||
{
|
|
||||||
int mib[4], argmax;
|
|
||||||
size_t size = sizeof(argmax);
|
|
||||||
char *procargs = NULL;
|
|
||||||
|
|
||||||
// Get the maximum process arguments size.
|
|
||||||
mib[0] = CTL_KERN;
|
|
||||||
mib[1] = KERN_ARGMAX;
|
|
||||||
|
|
||||||
size = sizeof(argmax);
|
|
||||||
if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// Allocate space for the arguments.
|
|
||||||
procargs = (char *)malloc(argmax);
|
|
||||||
if (procargs == NULL) {
|
|
||||||
PyErr_NoMemory();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make a sysctl() call to get the raw argument space of the process.
|
|
||||||
*/
|
|
||||||
mib[0] = CTL_KERN;
|
|
||||||
mib[1] = KERN_PROC;
|
|
||||||
mib[2] = KERN_PROC_ARGS;
|
|
||||||
mib[3] = pid;
|
|
||||||
|
|
||||||
size = argmax;
|
|
||||||
if (sysctl(mib, 4, procargs, &size, NULL, 0) == -1) {
|
|
||||||
free(procargs);
|
|
||||||
return NULL; // Insufficient privileges
|
|
||||||
}
|
|
||||||
|
|
||||||
// return string and set the length of arguments
|
|
||||||
*argsize = size;
|
|
||||||
return procargs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// returns the command line as a python list object
|
|
||||||
PyObject *
|
|
||||||
psutil_get_arg_list(long pid)
|
|
||||||
{
|
|
||||||
char *argstr = NULL;
|
|
||||||
int pos = 0;
|
|
||||||
size_t argsize = 0;
|
|
||||||
PyObject *retlist = Py_BuildValue("[]");
|
|
||||||
PyObject *item = NULL;
|
|
||||||
|
|
||||||
if (pid < 0)
|
|
||||||
return retlist;
|
|
||||||
argstr = psutil_get_cmd_args(pid, &argsize);
|
|
||||||
if (argstr == NULL)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
// args are returned as a flattened string with \0 separators between
|
|
||||||
// arguments add each string to the list then step forward to the next
|
|
||||||
// separator
|
|
||||||
if (argsize > 0) {
|
|
||||||
while (pos < argsize) {
|
|
||||||
item = Py_BuildValue("s", &argstr[pos]);
|
|
||||||
if (!item)
|
|
||||||
goto error;
|
|
||||||
if (PyList_Append(retlist, item))
|
|
||||||
goto error;
|
|
||||||
Py_DECREF(item);
|
|
||||||
pos = pos + strlen(&argstr[pos]) + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(argstr);
|
|
||||||
return retlist;
|
|
||||||
|
|
||||||
error:
|
|
||||||
Py_XDECREF(item);
|
|
||||||
Py_DECREF(retlist);
|
|
||||||
if (argstr != NULL)
|
|
||||||
free(argstr);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Return 1 if PID exists in the current process list, else 0.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
psutil_pid_exists(long pid)
|
|
||||||
{
|
|
||||||
int kill_ret;
|
|
||||||
|
|
||||||
if (pid < 0)
|
|
||||||
return 0;
|
|
||||||
// if kill returns success of permission denied we know it's a valid PID
|
|
||||||
kill_ret = kill(pid , 0);
|
|
||||||
if ((0 == kill_ret) || (EPERM == errno))
|
|
||||||
return 1;
|
|
||||||
// otherwise return 0 for PID not found
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
|
||||||
* Use of this source code is governed by a BSD-style license that can be
|
|
||||||
* found in the LICENSE file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <Python.h>
|
|
||||||
|
|
||||||
typedef struct kinfo_proc kinfo_proc;
|
|
||||||
|
|
||||||
char *psutil_get_cmd_args(long pid, size_t *argsize);
|
|
||||||
char *psutil_get_cmd_path(long pid, size_t *pathsize);
|
|
||||||
int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount);
|
|
||||||
int psutil_pid_exists(long pid);
|
|
||||||
PyObject* psutil_get_arg_list(long pid);
|
|
|
@ -0,0 +1,368 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola'.
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*
|
||||||
|
* Retrieves per-process open socket connections.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
#include <sys/user.h>
|
||||||
|
#include <sys/socketvar.h> // for struct xsocket
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <netinet/in.h> // for xinpcb struct
|
||||||
|
#include <netinet/in_pcb.h>
|
||||||
|
#include <netinet/tcp_var.h> // for struct xtcpcb
|
||||||
|
#include <arpa/inet.h> // for inet_ntop()
|
||||||
|
#include <libutil.h>
|
||||||
|
|
||||||
|
#include "../../_psutil_common.h"
|
||||||
|
#include "../../_psutil_posix.h"
|
||||||
|
|
||||||
|
|
||||||
|
// The tcplist fetching and walking is borrowed from netstat/inet.c.
|
||||||
|
static char *
|
||||||
|
psutil_fetch_tcplist(void) {
|
||||||
|
char *buf;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) < 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
buf = malloc(len);
|
||||||
|
if (buf == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (sysctlbyname("net.inet.tcp.pcblist", buf, &len, NULL, 0) < 0) {
|
||||||
|
free(buf);
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
psutil_sockaddr_port(int family, struct sockaddr_storage *ss) {
|
||||||
|
struct sockaddr_in6 *sin6;
|
||||||
|
struct sockaddr_in *sin;
|
||||||
|
|
||||||
|
if (family == AF_INET) {
|
||||||
|
sin = (struct sockaddr_in *)ss;
|
||||||
|
return (sin->sin_port);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sin6 = (struct sockaddr_in6 *)ss;
|
||||||
|
return (sin6->sin6_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void *
|
||||||
|
psutil_sockaddr_addr(int family, struct sockaddr_storage *ss) {
|
||||||
|
struct sockaddr_in6 *sin6;
|
||||||
|
struct sockaddr_in *sin;
|
||||||
|
|
||||||
|
if (family == AF_INET) {
|
||||||
|
sin = (struct sockaddr_in *)ss;
|
||||||
|
return (&sin->sin_addr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sin6 = (struct sockaddr_in6 *)ss;
|
||||||
|
return (&sin6->sin6_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static socklen_t
|
||||||
|
psutil_sockaddr_addrlen(int family) {
|
||||||
|
if (family == AF_INET)
|
||||||
|
return (sizeof(struct in_addr));
|
||||||
|
else
|
||||||
|
return (sizeof(struct in6_addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
psutil_sockaddr_matches(int family, int port, void *pcb_addr,
|
||||||
|
struct sockaddr_storage *ss) {
|
||||||
|
if (psutil_sockaddr_port(family, ss) != port)
|
||||||
|
return (0);
|
||||||
|
return (memcmp(psutil_sockaddr_addr(family, ss), pcb_addr,
|
||||||
|
psutil_sockaddr_addrlen(family)) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if __FreeBSD_version >= 1200026
|
||||||
|
static struct xtcpcb *
|
||||||
|
psutil_search_tcplist(char *buf, struct kinfo_file *kif) {
|
||||||
|
struct xtcpcb *tp;
|
||||||
|
struct xinpcb *inp;
|
||||||
|
#else
|
||||||
|
static struct tcpcb *
|
||||||
|
psutil_search_tcplist(char *buf, struct kinfo_file *kif) {
|
||||||
|
struct tcpcb *tp;
|
||||||
|
struct inpcb *inp;
|
||||||
|
#endif
|
||||||
|
struct xinpgen *xig, *oxig;
|
||||||
|
struct xsocket *so;
|
||||||
|
|
||||||
|
oxig = xig = (struct xinpgen *)buf;
|
||||||
|
for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
|
||||||
|
xig->xig_len > sizeof(struct xinpgen);
|
||||||
|
xig = (struct xinpgen *)((char *)xig + xig->xig_len)) {
|
||||||
|
|
||||||
|
#if __FreeBSD_version >= 1200026
|
||||||
|
tp = (struct xtcpcb *)xig;
|
||||||
|
inp = &tp->xt_inp;
|
||||||
|
so = &inp->xi_socket;
|
||||||
|
#else
|
||||||
|
tp = &((struct xtcpcb *)xig)->xt_tp;
|
||||||
|
inp = &((struct xtcpcb *)xig)->xt_inp;
|
||||||
|
so = &((struct xtcpcb *)xig)->xt_socket;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (so->so_type != kif->kf_sock_type ||
|
||||||
|
so->xso_family != kif->kf_sock_domain ||
|
||||||
|
so->xso_protocol != kif->kf_sock_protocol)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (kif->kf_sock_domain == AF_INET) {
|
||||||
|
if (!psutil_sockaddr_matches(
|
||||||
|
AF_INET, inp->inp_lport, &inp->inp_laddr,
|
||||||
|
#if __FreeBSD_version < 1200031
|
||||||
|
&kif->kf_sa_local))
|
||||||
|
#else
|
||||||
|
&kif->kf_un.kf_sock.kf_sa_local))
|
||||||
|
#endif
|
||||||
|
continue;
|
||||||
|
if (!psutil_sockaddr_matches(
|
||||||
|
AF_INET, inp->inp_fport, &inp->inp_faddr,
|
||||||
|
#if __FreeBSD_version < 1200031
|
||||||
|
&kif->kf_sa_peer))
|
||||||
|
#else
|
||||||
|
&kif->kf_un.kf_sock.kf_sa_peer))
|
||||||
|
#endif
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
if (!psutil_sockaddr_matches(
|
||||||
|
AF_INET6, inp->inp_lport, &inp->in6p_laddr,
|
||||||
|
#if __FreeBSD_version < 1200031
|
||||||
|
&kif->kf_sa_local))
|
||||||
|
#else
|
||||||
|
&kif->kf_un.kf_sock.kf_sa_local))
|
||||||
|
#endif
|
||||||
|
continue;
|
||||||
|
if (!psutil_sockaddr_matches(
|
||||||
|
AF_INET6, inp->inp_fport, &inp->in6p_faddr,
|
||||||
|
#if __FreeBSD_version < 1200031
|
||||||
|
&kif->kf_sa_peer))
|
||||||
|
#else
|
||||||
|
&kif->kf_un.kf_sock.kf_sa_peer))
|
||||||
|
#endif
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (tp);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_proc_connections(PyObject *self, PyObject *args) {
|
||||||
|
// Return connections opened by process.
|
||||||
|
long pid;
|
||||||
|
int i;
|
||||||
|
int cnt;
|
||||||
|
struct kinfo_file *freep = NULL;
|
||||||
|
struct kinfo_file *kif;
|
||||||
|
char *tcplist = NULL;
|
||||||
|
#if __FreeBSD_version >= 1200026
|
||||||
|
struct xtcpcb *tcp;
|
||||||
|
#else
|
||||||
|
struct tcpcb *tcp;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PyObject *py_retlist = PyList_New(0);
|
||||||
|
PyObject *py_tuple = NULL;
|
||||||
|
PyObject *py_laddr = NULL;
|
||||||
|
PyObject *py_raddr = NULL;
|
||||||
|
PyObject *py_af_filter = NULL;
|
||||||
|
PyObject *py_type_filter = NULL;
|
||||||
|
PyObject *py_family = NULL;
|
||||||
|
PyObject *py_type = NULL;
|
||||||
|
|
||||||
|
if (py_retlist == NULL)
|
||||||
|
return NULL;
|
||||||
|
if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter))
|
||||||
|
goto error;
|
||||||
|
if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
freep = kinfo_getfile(pid, &cnt);
|
||||||
|
if (freep == NULL) {
|
||||||
|
psutil_raise_for_pid(pid, "kinfo_getfile()");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcplist = psutil_fetch_tcplist();
|
||||||
|
if (tcplist == NULL) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < cnt; i++) {
|
||||||
|
int lport, rport, state;
|
||||||
|
char lip[200], rip[200];
|
||||||
|
char path[PATH_MAX];
|
||||||
|
int inseq;
|
||||||
|
py_tuple = NULL;
|
||||||
|
py_laddr = NULL;
|
||||||
|
py_raddr = NULL;
|
||||||
|
|
||||||
|
kif = &freep[i];
|
||||||
|
if (kif->kf_type == KF_TYPE_SOCKET) {
|
||||||
|
// apply filters
|
||||||
|
py_family = PyLong_FromLong((long)kif->kf_sock_domain);
|
||||||
|
inseq = PySequence_Contains(py_af_filter, py_family);
|
||||||
|
Py_DECREF(py_family);
|
||||||
|
if (inseq == 0)
|
||||||
|
continue;
|
||||||
|
py_type = PyLong_FromLong((long)kif->kf_sock_type);
|
||||||
|
inseq = PySequence_Contains(py_type_filter, py_type);
|
||||||
|
Py_DECREF(py_type);
|
||||||
|
if (inseq == 0)
|
||||||
|
continue;
|
||||||
|
// IPv4 / IPv6 socket
|
||||||
|
if ((kif->kf_sock_domain == AF_INET) ||
|
||||||
|
(kif->kf_sock_domain == AF_INET6)) {
|
||||||
|
// fill status
|
||||||
|
state = PSUTIL_CONN_NONE;
|
||||||
|
if (kif->kf_sock_type == SOCK_STREAM) {
|
||||||
|
tcp = psutil_search_tcplist(tcplist, kif);
|
||||||
|
if (tcp != NULL)
|
||||||
|
state = (int)tcp->t_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build addr and port
|
||||||
|
inet_ntop(
|
||||||
|
kif->kf_sock_domain,
|
||||||
|
psutil_sockaddr_addr(kif->kf_sock_domain,
|
||||||
|
#if __FreeBSD_version < 1200031
|
||||||
|
&kif->kf_sa_local),
|
||||||
|
#else
|
||||||
|
&kif->kf_un.kf_sock.kf_sa_local),
|
||||||
|
#endif
|
||||||
|
lip,
|
||||||
|
sizeof(lip));
|
||||||
|
inet_ntop(
|
||||||
|
kif->kf_sock_domain,
|
||||||
|
psutil_sockaddr_addr(kif->kf_sock_domain,
|
||||||
|
#if __FreeBSD_version < 1200031
|
||||||
|
&kif->kf_sa_peer),
|
||||||
|
#else
|
||||||
|
&kif->kf_un.kf_sock.kf_sa_peer),
|
||||||
|
#endif
|
||||||
|
rip,
|
||||||
|
sizeof(rip));
|
||||||
|
lport = htons(psutil_sockaddr_port(kif->kf_sock_domain,
|
||||||
|
#if __FreeBSD_version < 1200031
|
||||||
|
&kif->kf_sa_local));
|
||||||
|
#else
|
||||||
|
&kif->kf_un.kf_sock.kf_sa_local));
|
||||||
|
#endif
|
||||||
|
rport = htons(psutil_sockaddr_port(kif->kf_sock_domain,
|
||||||
|
#if __FreeBSD_version < 1200031
|
||||||
|
&kif->kf_sa_peer));
|
||||||
|
#else
|
||||||
|
&kif->kf_un.kf_sock.kf_sa_peer));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// construct python tuple/list
|
||||||
|
py_laddr = Py_BuildValue("(si)", lip, lport);
|
||||||
|
if (!py_laddr)
|
||||||
|
goto error;
|
||||||
|
if (rport != 0)
|
||||||
|
py_raddr = Py_BuildValue("(si)", rip, rport);
|
||||||
|
else
|
||||||
|
py_raddr = Py_BuildValue("()");
|
||||||
|
if (!py_raddr)
|
||||||
|
goto error;
|
||||||
|
py_tuple = Py_BuildValue(
|
||||||
|
"(iiiNNi)",
|
||||||
|
kif->kf_fd,
|
||||||
|
kif->kf_sock_domain,
|
||||||
|
kif->kf_sock_type,
|
||||||
|
py_laddr,
|
||||||
|
py_raddr,
|
||||||
|
state
|
||||||
|
);
|
||||||
|
if (!py_tuple)
|
||||||
|
goto error;
|
||||||
|
if (PyList_Append(py_retlist, py_tuple))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_tuple);
|
||||||
|
}
|
||||||
|
// UNIX socket.
|
||||||
|
// Note: remote path cannot be determined.
|
||||||
|
else if (kif->kf_sock_domain == AF_UNIX) {
|
||||||
|
struct sockaddr_un *sun;
|
||||||
|
|
||||||
|
#if __FreeBSD_version < 1200031
|
||||||
|
sun = (struct sockaddr_un *)&kif->kf_sa_local;
|
||||||
|
#else
|
||||||
|
sun = (struct sockaddr_un *)&kif->kf_un.kf_sock.kf_sa_local;
|
||||||
|
#endif
|
||||||
|
snprintf(
|
||||||
|
path, sizeof(path), "%.*s",
|
||||||
|
(int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))),
|
||||||
|
sun->sun_path);
|
||||||
|
|
||||||
|
py_laddr = PyUnicode_DecodeFSDefault(path);
|
||||||
|
if (! py_laddr)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
py_tuple = Py_BuildValue(
|
||||||
|
"(iiiOsi)",
|
||||||
|
kif->kf_fd,
|
||||||
|
kif->kf_sock_domain,
|
||||||
|
kif->kf_sock_type,
|
||||||
|
py_laddr,
|
||||||
|
"", // raddr can't be determined
|
||||||
|
PSUTIL_CONN_NONE
|
||||||
|
);
|
||||||
|
if (!py_tuple)
|
||||||
|
goto error;
|
||||||
|
if (PyList_Append(py_retlist, py_tuple))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_tuple);
|
||||||
|
Py_DECREF(py_laddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(freep);
|
||||||
|
free(tcplist);
|
||||||
|
return py_retlist;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_tuple);
|
||||||
|
Py_XDECREF(py_laddr);
|
||||||
|
Py_XDECREF(py_raddr);
|
||||||
|
Py_DECREF(py_retlist);
|
||||||
|
if (freep != NULL)
|
||||||
|
free(freep);
|
||||||
|
if (tcplist != NULL)
|
||||||
|
free(tcplist);
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
PyObject* psutil_proc_connections(PyObject* self, PyObject* args);
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Jay Loden, Giampaolo Rodola'. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
typedef struct kinfo_proc kinfo_proc;
|
||||||
|
|
||||||
|
int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount);
|
||||||
|
int psutil_kinfo_proc(const pid_t pid, struct kinfo_proc *proc);
|
||||||
|
|
||||||
|
//
|
||||||
|
PyObject* psutil_cpu_count_phys(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_get_cmdline(long pid);
|
||||||
|
PyObject* psutil_per_cpu_times(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_proc_cpu_affinity_get(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_proc_cpu_affinity_set(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_proc_cwd(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_proc_exe(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_proc_memory_maps(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_proc_num_fds(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_proc_threads(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_swap_mem(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_virtual_mem(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_cpu_stats(PyObject* self, PyObject* args);
|
||||||
|
#if defined(PSUTIL_FREEBSD)
|
||||||
|
PyObject* psutil_sensors_battery(PyObject* self, PyObject* args);
|
||||||
|
#endif
|
|
@ -0,0 +1,362 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola'.
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*
|
||||||
|
* Retrieves system-wide open socket connections. This is based off of
|
||||||
|
* sockstat utility source code:
|
||||||
|
* https://github.com/freebsd/freebsd/blob/master/usr.bin/sockstat/sockstat.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
#include <sys/user.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <sys/socketvar.h> // for struct xsocket
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/unpcb.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <netinet/in.h> // for xinpcb struct
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/in_pcb.h>
|
||||||
|
#include <netinet/tcp_var.h> // for struct xtcpcb
|
||||||
|
#include <arpa/inet.h> // for inet_ntop()
|
||||||
|
|
||||||
|
#include "../../_psutil_common.h"
|
||||||
|
#include "../../_psutil_posix.h"
|
||||||
|
|
||||||
|
static struct xfile *psutil_xfiles;
|
||||||
|
static int psutil_nxfiles;
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
psutil_populate_xfiles() {
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if ((psutil_xfiles = malloc(len = sizeof *psutil_xfiles)) == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
while (sysctlbyname("kern.file", psutil_xfiles, &len, 0, 0) == -1) {
|
||||||
|
if (errno != ENOMEM) {
|
||||||
|
PyErr_SetFromErrno(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
len *= 2;
|
||||||
|
if ((psutil_xfiles = realloc(psutil_xfiles, len)) == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (len > 0 && psutil_xfiles->xf_size != sizeof *psutil_xfiles) {
|
||||||
|
PyErr_Format(PyExc_RuntimeError, "struct xfile size mismatch");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
psutil_nxfiles = len / sizeof *psutil_xfiles;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct xfile *
|
||||||
|
psutil_get_file_from_sock(void *sock) {
|
||||||
|
struct xfile *xf;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for (xf = psutil_xfiles, n = 0; n < psutil_nxfiles; ++n, ++xf) {
|
||||||
|
if (xf->xf_data == sock)
|
||||||
|
return xf;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Reference:
|
||||||
|
// https://github.com/freebsd/freebsd/blob/master/usr.bin/sockstat/sockstat.c
|
||||||
|
int psutil_gather_inet(int proto, PyObject *py_retlist) {
|
||||||
|
struct xinpgen *xig, *exig;
|
||||||
|
struct xinpcb *xip;
|
||||||
|
struct xtcpcb *xtp;
|
||||||
|
#if __FreeBSD_version >= 1200026
|
||||||
|
struct xinpcb *inp;
|
||||||
|
#else
|
||||||
|
struct inpcb *inp;
|
||||||
|
#endif
|
||||||
|
struct xsocket *so;
|
||||||
|
const char *varname = NULL;
|
||||||
|
size_t len, bufsize;
|
||||||
|
void *buf;
|
||||||
|
int retry;
|
||||||
|
int type;
|
||||||
|
|
||||||
|
PyObject *py_tuple = NULL;
|
||||||
|
PyObject *py_laddr = NULL;
|
||||||
|
PyObject *py_raddr = NULL;
|
||||||
|
|
||||||
|
switch (proto) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
varname = "net.inet.tcp.pcblist";
|
||||||
|
type = SOCK_STREAM;
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
varname = "net.inet.udp.pcblist";
|
||||||
|
type = SOCK_DGRAM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = NULL;
|
||||||
|
bufsize = 8192;
|
||||||
|
retry = 5;
|
||||||
|
do {
|
||||||
|
for (;;) {
|
||||||
|
buf = realloc(buf, bufsize);
|
||||||
|
if (buf == NULL)
|
||||||
|
continue; // XXX
|
||||||
|
len = bufsize;
|
||||||
|
if (sysctlbyname(varname, buf, &len, NULL, 0) == 0)
|
||||||
|
break;
|
||||||
|
if (errno != ENOMEM) {
|
||||||
|
PyErr_SetFromErrno(0);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
bufsize *= 2;
|
||||||
|
}
|
||||||
|
xig = (struct xinpgen *)buf;
|
||||||
|
exig = (struct xinpgen *)(void *)((char *)buf + len - sizeof *exig);
|
||||||
|
if (xig->xig_len != sizeof *xig || exig->xig_len != sizeof *exig) {
|
||||||
|
PyErr_Format(PyExc_RuntimeError, "struct xinpgen size mismatch");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} while (xig->xig_gen != exig->xig_gen && retry--);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
struct xfile *xf;
|
||||||
|
int lport, rport, status, family;
|
||||||
|
|
||||||
|
xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len);
|
||||||
|
if (xig >= exig)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (proto) {
|
||||||
|
case IPPROTO_TCP:
|
||||||
|
xtp = (struct xtcpcb *)xig;
|
||||||
|
if (xtp->xt_len != sizeof *xtp) {
|
||||||
|
PyErr_Format(PyExc_RuntimeError,
|
||||||
|
"struct xtcpcb size mismatch");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
inp = &xtp->xt_inp;
|
||||||
|
#if __FreeBSD_version >= 1200026
|
||||||
|
so = &inp->xi_socket;
|
||||||
|
status = xtp->t_state;
|
||||||
|
#else
|
||||||
|
so = &xtp->xt_socket;
|
||||||
|
status = xtp->xt_tp.t_state;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case IPPROTO_UDP:
|
||||||
|
xip = (struct xinpcb *)xig;
|
||||||
|
if (xip->xi_len != sizeof *xip) {
|
||||||
|
PyErr_Format(PyExc_RuntimeError,
|
||||||
|
"struct xinpcb size mismatch");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
#if __FreeBSD_version >= 1200026
|
||||||
|
inp = xip;
|
||||||
|
#else
|
||||||
|
inp = &xip->xi_inp;
|
||||||
|
#endif
|
||||||
|
so = &xip->xi_socket;
|
||||||
|
status = PSUTIL_CONN_NONE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PyErr_Format(PyExc_RuntimeError, "invalid proto");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
char lip[200], rip[200];
|
||||||
|
|
||||||
|
xf = psutil_get_file_from_sock(so->xso_so);
|
||||||
|
if (xf == NULL)
|
||||||
|
continue;
|
||||||
|
lport = ntohs(inp->inp_lport);
|
||||||
|
rport = ntohs(inp->inp_fport);
|
||||||
|
|
||||||
|
if (inp->inp_vflag & INP_IPV4) {
|
||||||
|
family = AF_INET;
|
||||||
|
inet_ntop(AF_INET, &inp->inp_laddr.s_addr, lip, sizeof(lip));
|
||||||
|
inet_ntop(AF_INET, &inp->inp_faddr.s_addr, rip, sizeof(rip));
|
||||||
|
}
|
||||||
|
else if (inp->inp_vflag & INP_IPV6) {
|
||||||
|
family = AF_INET6;
|
||||||
|
inet_ntop(AF_INET6, &inp->in6p_laddr.s6_addr, lip, sizeof(lip));
|
||||||
|
inet_ntop(AF_INET6, &inp->in6p_faddr.s6_addr, rip, sizeof(rip));
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct python tuple/list
|
||||||
|
py_laddr = Py_BuildValue("(si)", lip, lport);
|
||||||
|
if (!py_laddr)
|
||||||
|
goto error;
|
||||||
|
if (rport != 0)
|
||||||
|
py_raddr = Py_BuildValue("(si)", rip, rport);
|
||||||
|
else
|
||||||
|
py_raddr = Py_BuildValue("()");
|
||||||
|
if (!py_raddr)
|
||||||
|
goto error;
|
||||||
|
py_tuple = Py_BuildValue(
|
||||||
|
"(iiiNNii)",
|
||||||
|
xf->xf_fd, // fd
|
||||||
|
family, // family
|
||||||
|
type, // type
|
||||||
|
py_laddr, // laddr
|
||||||
|
py_raddr, // raddr
|
||||||
|
status, // status
|
||||||
|
xf->xf_pid); // pid
|
||||||
|
if (!py_tuple)
|
||||||
|
goto error;
|
||||||
|
if (PyList_Append(py_retlist, py_tuple))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_tuple);
|
||||||
|
Py_XDECREF(py_laddr);
|
||||||
|
Py_XDECREF(py_raddr);
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int psutil_gather_unix(int proto, PyObject *py_retlist) {
|
||||||
|
struct xunpgen *xug, *exug;
|
||||||
|
struct xunpcb *xup;
|
||||||
|
const char *varname = NULL;
|
||||||
|
const char *protoname = NULL;
|
||||||
|
size_t len;
|
||||||
|
size_t bufsize;
|
||||||
|
void *buf;
|
||||||
|
int retry;
|
||||||
|
struct sockaddr_un *sun;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
|
||||||
|
PyObject *py_tuple = NULL;
|
||||||
|
PyObject *py_lpath = NULL;
|
||||||
|
|
||||||
|
switch (proto) {
|
||||||
|
case SOCK_STREAM:
|
||||||
|
varname = "net.local.stream.pcblist";
|
||||||
|
protoname = "stream";
|
||||||
|
break;
|
||||||
|
case SOCK_DGRAM:
|
||||||
|
varname = "net.local.dgram.pcblist";
|
||||||
|
protoname = "dgram";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = NULL;
|
||||||
|
bufsize = 8192;
|
||||||
|
retry = 5;
|
||||||
|
|
||||||
|
do {
|
||||||
|
for (;;) {
|
||||||
|
buf = realloc(buf, bufsize);
|
||||||
|
if (buf == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
len = bufsize;
|
||||||
|
if (sysctlbyname(varname, buf, &len, NULL, 0) == 0)
|
||||||
|
break;
|
||||||
|
if (errno != ENOMEM) {
|
||||||
|
PyErr_SetFromErrno(0);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
bufsize *= 2;
|
||||||
|
}
|
||||||
|
xug = (struct xunpgen *)buf;
|
||||||
|
exug = (struct xunpgen *)(void *)
|
||||||
|
((char *)buf + len - sizeof *exug);
|
||||||
|
if (xug->xug_len != sizeof *xug || exug->xug_len != sizeof *exug) {
|
||||||
|
PyErr_Format(PyExc_RuntimeError, "struct xinpgen size mismatch");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} while (xug->xug_gen != exug->xug_gen && retry--);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
struct xfile *xf;
|
||||||
|
|
||||||
|
xug = (struct xunpgen *)(void *)((char *)xug + xug->xug_len);
|
||||||
|
if (xug >= exug)
|
||||||
|
break;
|
||||||
|
xup = (struct xunpcb *)xug;
|
||||||
|
if (xup->xu_len != sizeof *xup)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
xf = psutil_get_file_from_sock(xup->xu_socket.xso_so);
|
||||||
|
if (xf == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sun = (struct sockaddr_un *)&xup->xu_addr;
|
||||||
|
snprintf(path, sizeof(path), "%.*s",
|
||||||
|
(int)(sun->sun_len - (sizeof(*sun) - sizeof(sun->sun_path))),
|
||||||
|
sun->sun_path);
|
||||||
|
py_lpath = PyUnicode_DecodeFSDefault(path);
|
||||||
|
if (! py_lpath)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
py_tuple = Py_BuildValue("(iiiOsii)",
|
||||||
|
xf->xf_fd, // fd
|
||||||
|
AF_UNIX, // family
|
||||||
|
proto, // type
|
||||||
|
py_lpath, // lpath
|
||||||
|
"", // rath
|
||||||
|
PSUTIL_CONN_NONE, // status
|
||||||
|
xf->xf_pid); // pid
|
||||||
|
if (!py_tuple)
|
||||||
|
goto error;
|
||||||
|
if (PyList_Append(py_retlist, py_tuple))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_lpath);
|
||||||
|
Py_DECREF(py_tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_tuple);
|
||||||
|
Py_XDECREF(py_lpath);
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject*
|
||||||
|
psutil_net_connections(PyObject* self, PyObject* args) {
|
||||||
|
// Return system-wide open connections.
|
||||||
|
PyObject *py_retlist = PyList_New(0);
|
||||||
|
|
||||||
|
if (py_retlist == NULL)
|
||||||
|
return NULL;
|
||||||
|
if (psutil_populate_xfiles() != 1)
|
||||||
|
goto error;
|
||||||
|
if (psutil_gather_inet(IPPROTO_TCP, py_retlist) == 0)
|
||||||
|
goto error;
|
||||||
|
if (psutil_gather_inet(IPPROTO_UDP, py_retlist) == 0)
|
||||||
|
goto error;
|
||||||
|
if (psutil_gather_unix(SOCK_STREAM, py_retlist) == 0)
|
||||||
|
goto error;
|
||||||
|
if (psutil_gather_unix(SOCK_DGRAM, py_retlist) == 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
free(psutil_xfiles);
|
||||||
|
return py_retlist;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_DECREF(py_retlist);
|
||||||
|
free(psutil_xfiles);
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola'.
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
PyObject* psutil_net_connections(PyObject* self, PyObject* args);
|
|
@ -0,0 +1,447 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola'.
|
||||||
|
* Copyright (c) 2015, Ryo ONODERA.
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
|
||||||
|
#include "../../_psutil_common.h"
|
||||||
|
#include "../../_psutil_posix.h"
|
||||||
|
|
||||||
|
|
||||||
|
// address family filter
|
||||||
|
enum af_filter {
|
||||||
|
INET,
|
||||||
|
INET4,
|
||||||
|
INET6,
|
||||||
|
TCP,
|
||||||
|
TCP4,
|
||||||
|
TCP6,
|
||||||
|
UDP,
|
||||||
|
UDP4,
|
||||||
|
UDP6,
|
||||||
|
UNIX,
|
||||||
|
ALL,
|
||||||
|
};
|
||||||
|
|
||||||
|
// kinfo_file results
|
||||||
|
struct kif {
|
||||||
|
SLIST_ENTRY(kif) kifs;
|
||||||
|
struct kinfo_file *kif;
|
||||||
|
};
|
||||||
|
|
||||||
|
// kinfo_file results list
|
||||||
|
SLIST_HEAD(kifhead, kif) kihead = SLIST_HEAD_INITIALIZER(kihead);
|
||||||
|
|
||||||
|
|
||||||
|
// kinfo_pcb results
|
||||||
|
struct kpcb {
|
||||||
|
SLIST_ENTRY(kpcb) kpcbs;
|
||||||
|
struct kinfo_pcb *kpcb;
|
||||||
|
};
|
||||||
|
|
||||||
|
// kinfo_pcb results list
|
||||||
|
SLIST_HEAD(kpcbhead, kpcb) kpcbhead = SLIST_HEAD_INITIALIZER(kpcbhead);
|
||||||
|
|
||||||
|
static void psutil_kiflist_init(void);
|
||||||
|
static void psutil_kiflist_clear(void);
|
||||||
|
static void psutil_kpcblist_init(void);
|
||||||
|
static void psutil_kpcblist_clear(void);
|
||||||
|
static int psutil_get_files(void);
|
||||||
|
static int psutil_get_sockets(const char *name);
|
||||||
|
static int psutil_get_info(int aff);
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize kinfo_file results list.
|
||||||
|
static void
|
||||||
|
psutil_kiflist_init(void) {
|
||||||
|
SLIST_INIT(&kihead);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Clear kinfo_file results list.
|
||||||
|
static void
|
||||||
|
psutil_kiflist_clear(void) {
|
||||||
|
while (!SLIST_EMPTY(&kihead)) {
|
||||||
|
SLIST_REMOVE_HEAD(&kihead, kifs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize kinof_pcb result list.
|
||||||
|
static void
|
||||||
|
psutil_kpcblist_init(void) {
|
||||||
|
SLIST_INIT(&kpcbhead);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Clear kinof_pcb result list.
|
||||||
|
static void
|
||||||
|
psutil_kpcblist_clear(void) {
|
||||||
|
while (!SLIST_EMPTY(&kpcbhead)) {
|
||||||
|
SLIST_REMOVE_HEAD(&kpcbhead, kpcbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get all open files including socket.
|
||||||
|
static int
|
||||||
|
psutil_get_files(void) {
|
||||||
|
size_t len;
|
||||||
|
size_t j;
|
||||||
|
int mib[6];
|
||||||
|
char *buf;
|
||||||
|
off_t offset;
|
||||||
|
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_FILE2;
|
||||||
|
mib[2] = KERN_FILE_BYFILE;
|
||||||
|
mib[3] = 0;
|
||||||
|
mib[4] = sizeof(struct kinfo_file);
|
||||||
|
mib[5] = 0;
|
||||||
|
|
||||||
|
if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = len % sizeof(off_t);
|
||||||
|
mib[5] = len / sizeof(struct kinfo_file);
|
||||||
|
|
||||||
|
if ((buf = malloc(len + offset)) == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sysctl(mib, 6, buf + offset, &len, NULL, 0) == -1) {
|
||||||
|
free(buf);
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len /= sizeof(struct kinfo_file);
|
||||||
|
struct kinfo_file *ki = (struct kinfo_file *)(buf + offset);
|
||||||
|
|
||||||
|
for (j = 0; j < len; j++) {
|
||||||
|
struct kif *kif = malloc(sizeof(struct kif));
|
||||||
|
kif->kif = &ki[j];
|
||||||
|
SLIST_INSERT_HEAD(&kihead, kif, kifs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// debug
|
||||||
|
struct kif *k;
|
||||||
|
SLIST_FOREACH(k, &kihead, kifs) {
|
||||||
|
printf("%d\n", k->kif->ki_pid);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get open sockets.
|
||||||
|
static int
|
||||||
|
psutil_get_sockets(const char *name) {
|
||||||
|
size_t namelen;
|
||||||
|
int mib[8];
|
||||||
|
struct kinfo_pcb *pcb;
|
||||||
|
size_t len;
|
||||||
|
size_t j;
|
||||||
|
|
||||||
|
memset(mib, 0, sizeof(mib));
|
||||||
|
|
||||||
|
if (sysctlnametomib(name, mib, &namelen) == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sysctl(mib, __arraycount(mib), NULL, &len, NULL, 0) == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((pcb = malloc(len)) == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(pcb, 0, len);
|
||||||
|
|
||||||
|
mib[6] = sizeof(*pcb);
|
||||||
|
mib[7] = len / sizeof(*pcb);
|
||||||
|
|
||||||
|
if (sysctl(mib, __arraycount(mib), pcb, &len, NULL, 0) == -1) {
|
||||||
|
free(pcb);
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len /= sizeof(struct kinfo_pcb);
|
||||||
|
struct kinfo_pcb *kp = (struct kinfo_pcb *)pcb;
|
||||||
|
|
||||||
|
for (j = 0; j < len; j++) {
|
||||||
|
struct kpcb *kpcb = malloc(sizeof(struct kpcb));
|
||||||
|
kpcb->kpcb = &kp[j];
|
||||||
|
SLIST_INSERT_HEAD(&kpcbhead, kpcb, kpcbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// debug
|
||||||
|
struct kif *k;
|
||||||
|
struct kpcb *k;
|
||||||
|
SLIST_FOREACH(k, &kpcbhead, kpcbs) {
|
||||||
|
printf("ki_type: %d\n", k->kpcb->ki_type);
|
||||||
|
printf("ki_family: %d\n", k->kpcb->ki_family);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Collect open file and connections.
|
||||||
|
static int
|
||||||
|
psutil_get_info(int aff) {
|
||||||
|
switch (aff) {
|
||||||
|
case INET:
|
||||||
|
if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case INET4:
|
||||||
|
if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case INET6:
|
||||||
|
if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case TCP:
|
||||||
|
if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case TCP4:
|
||||||
|
if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case TCP6:
|
||||||
|
if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case UDP:
|
||||||
|
if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case UDP4:
|
||||||
|
if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case UDP6:
|
||||||
|
if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case UNIX:
|
||||||
|
if (psutil_get_sockets("net.local.stream.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
if (psutil_get_sockets("net.local.seqpacket.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
if (psutil_get_sockets("net.local.dgram.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case ALL:
|
||||||
|
if (psutil_get_sockets("net.inet.tcp.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
if (psutil_get_sockets("net.inet.udp.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
if (psutil_get_sockets("net.inet6.tcp6.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
if (psutil_get_sockets("net.inet6.udp6.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
if (psutil_get_sockets("net.local.stream.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
if (psutil_get_sockets("net.local.seqpacket.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
if (psutil_get_sockets("net.local.dgram.pcblist") != 0)
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return system-wide connections (unless a pid != -1 is passed).
|
||||||
|
*/
|
||||||
|
PyObject *
|
||||||
|
psutil_net_connections(PyObject *self, PyObject *args) {
|
||||||
|
char laddr[PATH_MAX];
|
||||||
|
char raddr[PATH_MAX];
|
||||||
|
int32_t lport;
|
||||||
|
int32_t rport;
|
||||||
|
int32_t status;
|
||||||
|
pid_t pid;
|
||||||
|
PyObject *py_tuple = NULL;
|
||||||
|
PyObject *py_laddr = NULL;
|
||||||
|
PyObject *py_raddr = NULL;
|
||||||
|
PyObject *py_retlist = PyList_New(0);
|
||||||
|
|
||||||
|
if (py_retlist == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
psutil_kiflist_init();
|
||||||
|
psutil_kpcblist_init();
|
||||||
|
if (psutil_get_files() != 0)
|
||||||
|
goto error;
|
||||||
|
if (psutil_get_info(ALL) != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
struct kif *k;
|
||||||
|
SLIST_FOREACH(k, &kihead, kifs) {
|
||||||
|
struct kpcb *kp;
|
||||||
|
if ((pid != -1) && (k->kif->ki_pid != (unsigned int)pid))
|
||||||
|
continue;
|
||||||
|
SLIST_FOREACH(kp, &kpcbhead, kpcbs) {
|
||||||
|
if (k->kif->ki_fdata != kp->kpcb->ki_sockaddr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// IPv4 or IPv6
|
||||||
|
if ((kp->kpcb->ki_family == AF_INET) ||
|
||||||
|
(kp->kpcb->ki_family == AF_INET6)) {
|
||||||
|
|
||||||
|
if (kp->kpcb->ki_family == AF_INET) {
|
||||||
|
// IPv4
|
||||||
|
struct sockaddr_in *sin_src =
|
||||||
|
(struct sockaddr_in *)&kp->kpcb->ki_src;
|
||||||
|
struct sockaddr_in *sin_dst =
|
||||||
|
(struct sockaddr_in *)&kp->kpcb->ki_dst;
|
||||||
|
// source addr and port
|
||||||
|
inet_ntop(AF_INET, &sin_src->sin_addr, laddr,
|
||||||
|
sizeof(laddr));
|
||||||
|
lport = ntohs(sin_src->sin_port);
|
||||||
|
// remote addr and port
|
||||||
|
inet_ntop(AF_INET, &sin_dst->sin_addr, raddr,
|
||||||
|
sizeof(raddr));
|
||||||
|
rport = ntohs(sin_dst->sin_port);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// IPv6
|
||||||
|
struct sockaddr_in6 *sin6_src =
|
||||||
|
(struct sockaddr_in6 *)&kp->kpcb->ki_src;
|
||||||
|
struct sockaddr_in6 *sin6_dst =
|
||||||
|
(struct sockaddr_in6 *)&kp->kpcb->ki_dst;
|
||||||
|
// local addr and port
|
||||||
|
inet_ntop(AF_INET6, &sin6_src->sin6_addr, laddr,
|
||||||
|
sizeof(laddr));
|
||||||
|
lport = ntohs(sin6_src->sin6_port);
|
||||||
|
// remote addr and port
|
||||||
|
inet_ntop(AF_INET6, &sin6_dst->sin6_addr, raddr,
|
||||||
|
sizeof(raddr));
|
||||||
|
rport = ntohs(sin6_dst->sin6_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
// status
|
||||||
|
if (kp->kpcb->ki_type == SOCK_STREAM)
|
||||||
|
status = kp->kpcb->ki_tstate;
|
||||||
|
else
|
||||||
|
status = PSUTIL_CONN_NONE;
|
||||||
|
|
||||||
|
// build addr tuple
|
||||||
|
py_laddr = Py_BuildValue("(si)", laddr, lport);
|
||||||
|
if (! py_laddr)
|
||||||
|
goto error;
|
||||||
|
if (rport != 0)
|
||||||
|
py_raddr = Py_BuildValue("(si)", raddr, rport);
|
||||||
|
else
|
||||||
|
py_raddr = Py_BuildValue("()");
|
||||||
|
if (! py_raddr)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
else if (kp->kpcb->ki_family == AF_UNIX) {
|
||||||
|
// UNIX sockets
|
||||||
|
struct sockaddr_un *sun_src =
|
||||||
|
(struct sockaddr_un *)&kp->kpcb->ki_src;
|
||||||
|
struct sockaddr_un *sun_dst =
|
||||||
|
(struct sockaddr_un *)&kp->kpcb->ki_dst;
|
||||||
|
strcpy(laddr, sun_src->sun_path);
|
||||||
|
strcpy(raddr, sun_dst->sun_path);
|
||||||
|
status = PSUTIL_CONN_NONE;
|
||||||
|
py_laddr = PyUnicode_DecodeFSDefault(laddr);
|
||||||
|
if (! py_laddr)
|
||||||
|
goto error;
|
||||||
|
py_raddr = PyUnicode_DecodeFSDefault(raddr);
|
||||||
|
if (! py_raddr)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// append tuple to list
|
||||||
|
py_tuple = Py_BuildValue(
|
||||||
|
"(iiiOOii)",
|
||||||
|
k->kif->ki_fd,
|
||||||
|
kp->kpcb->ki_family,
|
||||||
|
kp->kpcb->ki_type,
|
||||||
|
py_laddr,
|
||||||
|
py_raddr,
|
||||||
|
status,
|
||||||
|
k->kif->ki_pid);
|
||||||
|
if (! py_tuple)
|
||||||
|
goto error;
|
||||||
|
if (PyList_Append(py_retlist, py_tuple))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_laddr);
|
||||||
|
Py_DECREF(py_raddr);
|
||||||
|
Py_DECREF(py_tuple);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
psutil_kiflist_clear();
|
||||||
|
psutil_kpcblist_clear();
|
||||||
|
return py_retlist;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_tuple);
|
||||||
|
Py_XDECREF(py_laddr);
|
||||||
|
Py_XDECREF(py_raddr);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola'.
|
||||||
|
* Copyright (c) 2015, Ryo ONODERA.
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PyObject *psutil_proc_connections(PyObject *, PyObject *);
|
||||||
|
PyObject *psutil_net_connections(PyObject *, PyObject *);
|
|
@ -0,0 +1,652 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola', Landry Breuil.
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*
|
||||||
|
* Platform-specific module methods for NetBSD.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(PSUTIL_NETBSD)
|
||||||
|
#define _KMEMUSER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/user.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/swap.h> // for swap_mem
|
||||||
|
#include <signal.h>
|
||||||
|
#include <kvm.h>
|
||||||
|
// connection stuff
|
||||||
|
#include <netdb.h> // for NI_MAXHOST
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/sched.h> // for CPUSTATES & CP_*
|
||||||
|
#define _KERNEL // for DTYPE_*
|
||||||
|
#include <sys/file.h>
|
||||||
|
#undef _KERNEL
|
||||||
|
#include <sys/disk.h> // struct diskstats
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "specific.h"
|
||||||
|
#include "../../_psutil_common.h"
|
||||||
|
#include "../../_psutil_posix.h"
|
||||||
|
|
||||||
|
#define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0)
|
||||||
|
#define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Utility functions
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
psutil_kinfo_proc(pid_t pid, kinfo_proc *proc) {
|
||||||
|
// Fills a kinfo_proc struct based on process pid.
|
||||||
|
int ret;
|
||||||
|
int mib[6];
|
||||||
|
size_t size = sizeof(kinfo_proc);
|
||||||
|
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_PROC2;
|
||||||
|
mib[2] = KERN_PROC_PID;
|
||||||
|
mib[3] = pid;
|
||||||
|
mib[4] = size;
|
||||||
|
mib[5] = 1;
|
||||||
|
|
||||||
|
ret = sysctl((int*)mib, 6, proc, &size, NULL, 0);
|
||||||
|
if (ret == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// sysctl stores 0 in the size if we can't find the process information.
|
||||||
|
if (size == 0) {
|
||||||
|
NoSuchProcess("");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct kinfo_file *
|
||||||
|
kinfo_getfile(pid_t pid, int* cnt) {
|
||||||
|
// Mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an
|
||||||
|
// int as arg and returns an array with cnt struct kinfo_file.
|
||||||
|
int mib[6];
|
||||||
|
size_t len;
|
||||||
|
struct kinfo_file* kf;
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_FILE2;
|
||||||
|
mib[2] = KERN_FILE_BYPID;
|
||||||
|
mib[3] = (int) pid;
|
||||||
|
mib[4] = sizeof(struct kinfo_file);
|
||||||
|
mib[5] = 0;
|
||||||
|
|
||||||
|
// get the size of what would be returned
|
||||||
|
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if ((kf = malloc(len)) == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
mib[5] = (int)(len / sizeof(struct kinfo_file));
|
||||||
|
if (sysctl(mib, 6, kf, &len, NULL, 0) < 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*cnt = (int)(len / sizeof(struct kinfo_file));
|
||||||
|
return kf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// XXX: This is no longer used as per
|
||||||
|
// https://github.com/giampaolo/psutil/pull/557#issuecomment-171912820
|
||||||
|
// Current implementation uses /proc instead.
|
||||||
|
// Left here just in case.
|
||||||
|
/*
|
||||||
|
PyObject *
|
||||||
|
psutil_proc_exe(PyObject *self, PyObject *args) {
|
||||||
|
#if __NetBSD_Version__ >= 799000000
|
||||||
|
pid_t pid;
|
||||||
|
char pathname[MAXPATHLEN];
|
||||||
|
int error;
|
||||||
|
int mib[4];
|
||||||
|
int ret;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||||
|
return NULL;
|
||||||
|
if (pid == 0) {
|
||||||
|
// else returns ENOENT
|
||||||
|
return Py_BuildValue("s", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_PROC_ARGS;
|
||||||
|
mib[2] = pid;
|
||||||
|
mib[3] = KERN_PROC_PATHNAME;
|
||||||
|
|
||||||
|
size = sizeof(pathname);
|
||||||
|
error = sysctl(mib, 4, NULL, &size, NULL, 0);
|
||||||
|
if (error == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = sysctl(mib, 4, pathname, &size, NULL, 0);
|
||||||
|
if (error == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (size == 0 || strlen(pathname) == 0) {
|
||||||
|
ret = psutil_pid_exists(pid);
|
||||||
|
if (ret == -1)
|
||||||
|
return NULL;
|
||||||
|
else if (ret == 0)
|
||||||
|
return NoSuchProcess("");
|
||||||
|
else
|
||||||
|
strcpy(pathname, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return PyUnicode_DecodeFSDefault(pathname);
|
||||||
|
#else
|
||||||
|
return Py_BuildValue("s", "");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_proc_num_threads(PyObject *self, PyObject *args) {
|
||||||
|
// Return number of threads used by process as a Python integer.
|
||||||
|
long pid;
|
||||||
|
kinfo_proc kp;
|
||||||
|
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||||
|
return NULL;
|
||||||
|
if (psutil_kinfo_proc(pid, &kp) == -1)
|
||||||
|
return NULL;
|
||||||
|
return Py_BuildValue("l", (long)kp.p_nlwps);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_proc_threads(PyObject *self, PyObject *args) {
|
||||||
|
pid_t pid;
|
||||||
|
int mib[5];
|
||||||
|
int i, nlwps;
|
||||||
|
ssize_t st;
|
||||||
|
size_t size;
|
||||||
|
struct kinfo_lwp *kl = NULL;
|
||||||
|
PyObject *py_retlist = PyList_New(0);
|
||||||
|
PyObject *py_tuple = NULL;
|
||||||
|
|
||||||
|
if (py_retlist == NULL)
|
||||||
|
return NULL;
|
||||||
|
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_LWP;
|
||||||
|
mib[2] = pid;
|
||||||
|
mib[3] = sizeof(struct kinfo_lwp);
|
||||||
|
mib[4] = 0;
|
||||||
|
|
||||||
|
st = sysctl(mib, 5, NULL, &size, NULL, 0);
|
||||||
|
if (st == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (size == 0) {
|
||||||
|
NoSuchProcess("");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
mib[4] = size / sizeof(size_t);
|
||||||
|
kl = malloc(size);
|
||||||
|
if (kl == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
st = sysctl(mib, 5, kl, &size, NULL, 0);
|
||||||
|
if (st == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (size == 0) {
|
||||||
|
NoSuchProcess("");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
nlwps = (int)(size / sizeof(struct kinfo_lwp));
|
||||||
|
for (i = 0; i < nlwps; i++) {
|
||||||
|
py_tuple = Py_BuildValue("idd",
|
||||||
|
(&kl[i])->l_lid,
|
||||||
|
PSUTIL_KPT2DOUBLE((&kl[i])->l_rtime),
|
||||||
|
PSUTIL_KPT2DOUBLE((&kl[i])->l_rtime));
|
||||||
|
if (py_tuple == NULL)
|
||||||
|
goto error;
|
||||||
|
if (PyList_Append(py_retlist, py_tuple))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_tuple);
|
||||||
|
}
|
||||||
|
free(kl);
|
||||||
|
return py_retlist;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_tuple);
|
||||||
|
Py_DECREF(py_retlist);
|
||||||
|
if (kl != NULL)
|
||||||
|
free(kl);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// APIS
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
int
|
||||||
|
psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) {
|
||||||
|
// Returns a list of all BSD processes on the system. This routine
|
||||||
|
// allocates the list and puts it in *procList and a count of the
|
||||||
|
// number of entries in *procCount. You are responsible for freeing
|
||||||
|
// this list (use "free" from System framework).
|
||||||
|
// On success, the function returns 0.
|
||||||
|
// On error, the function returns a BSD errno value.
|
||||||
|
kinfo_proc *result;
|
||||||
|
// Declaring name as const requires us to cast it when passing it to
|
||||||
|
// sysctl because the prototype doesn't include the const modifier.
|
||||||
|
char errbuf[_POSIX2_LINE_MAX];
|
||||||
|
int cnt;
|
||||||
|
kvm_t *kd;
|
||||||
|
|
||||||
|
assert( procList != NULL);
|
||||||
|
assert(*procList == NULL);
|
||||||
|
assert(procCount != NULL);
|
||||||
|
|
||||||
|
kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
|
||||||
|
|
||||||
|
if (kd == NULL) {
|
||||||
|
PyErr_Format(
|
||||||
|
PyExc_RuntimeError, "kvm_openfiles() syscall failed: %s", errbuf);
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = kvm_getproc2(kd, KERN_PROC_ALL, 0, sizeof(kinfo_proc), &cnt);
|
||||||
|
if (result == NULL) {
|
||||||
|
PyErr_Format(PyExc_RuntimeError, "kvm_getproc2() syscall failed");
|
||||||
|
kvm_close(kd);
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
*procCount = (size_t)cnt;
|
||||||
|
|
||||||
|
size_t mlen = cnt * sizeof(kinfo_proc);
|
||||||
|
|
||||||
|
if ((*procList = malloc(mlen)) == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
kvm_close(kd);
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(*procList, result, mlen);
|
||||||
|
assert(*procList != NULL);
|
||||||
|
kvm_close(kd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char *
|
||||||
|
psutil_get_cmd_args(pid_t pid, size_t *argsize) {
|
||||||
|
int mib[4];
|
||||||
|
ssize_t st;
|
||||||
|
size_t argmax;
|
||||||
|
size_t size;
|
||||||
|
char *procargs = NULL;
|
||||||
|
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_ARGMAX;
|
||||||
|
|
||||||
|
size = sizeof(argmax);
|
||||||
|
st = sysctl(mib, 2, &argmax, &size, NULL, 0);
|
||||||
|
if (st == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
procargs = (char *)malloc(argmax);
|
||||||
|
if (procargs == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_PROC_ARGS;
|
||||||
|
mib[2] = pid;
|
||||||
|
mib[3] = KERN_PROC_ARGV;
|
||||||
|
|
||||||
|
st = sysctl(mib, 4, procargs, &argmax, NULL, 0);
|
||||||
|
if (st == -1) {
|
||||||
|
free(procargs);
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*argsize = argmax;
|
||||||
|
return procargs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Return the command line as a python list object.
|
||||||
|
// XXX - most of the times sysctl() returns a truncated string.
|
||||||
|
// Also /proc/pid/cmdline behaves the same so it looks like this
|
||||||
|
// is a kernel bug.
|
||||||
|
PyObject *
|
||||||
|
psutil_get_cmdline(pid_t pid) {
|
||||||
|
char *argstr = NULL;
|
||||||
|
size_t pos = 0;
|
||||||
|
size_t argsize = 0;
|
||||||
|
PyObject *py_arg = NULL;
|
||||||
|
PyObject *py_retlist = PyList_New(0);
|
||||||
|
|
||||||
|
if (py_retlist == NULL)
|
||||||
|
return NULL;
|
||||||
|
if (pid == 0)
|
||||||
|
return py_retlist;
|
||||||
|
|
||||||
|
argstr = psutil_get_cmd_args(pid, &argsize);
|
||||||
|
if (argstr == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// args are returned as a flattened string with \0 separators between
|
||||||
|
// arguments add each string to the list then step forward to the next
|
||||||
|
// separator
|
||||||
|
if (argsize > 0) {
|
||||||
|
while (pos < argsize) {
|
||||||
|
py_arg = PyUnicode_DecodeFSDefault(&argstr[pos]);
|
||||||
|
if (!py_arg)
|
||||||
|
goto error;
|
||||||
|
if (PyList_Append(py_retlist, py_arg))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_arg);
|
||||||
|
pos = pos + strlen(&argstr[pos]) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(argstr);
|
||||||
|
return py_retlist;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_arg);
|
||||||
|
Py_DECREF(py_retlist);
|
||||||
|
if (argstr != NULL)
|
||||||
|
free(argstr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Virtual memory stats, taken from:
|
||||||
|
* https://github.com/satterly/zabbix-stats/blob/master/src/libs/zbxsysinfo/
|
||||||
|
* netbsd/memory.c
|
||||||
|
*/
|
||||||
|
PyObject *
|
||||||
|
psutil_virtual_mem(PyObject *self, PyObject *args) {
|
||||||
|
size_t size;
|
||||||
|
struct uvmexp_sysctl uv;
|
||||||
|
int mib[] = {CTL_VM, VM_UVMEXP2};
|
||||||
|
long pagesize = getpagesize();
|
||||||
|
|
||||||
|
size = sizeof(uv);
|
||||||
|
if (sysctl(mib, 2, &uv, &size, NULL, 0) < 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Py_BuildValue("KKKKKKKK",
|
||||||
|
(unsigned long long) uv.npages << uv.pageshift, // total
|
||||||
|
(unsigned long long) uv.free << uv.pageshift, // free
|
||||||
|
(unsigned long long) uv.active << uv.pageshift, // active
|
||||||
|
(unsigned long long) uv.inactive << uv.pageshift, // inactive
|
||||||
|
(unsigned long long) uv.wired << uv.pageshift, // wired
|
||||||
|
(unsigned long long) uv.filepages + uv.execpages * pagesize, // cached
|
||||||
|
// These are determined from /proc/meminfo in Python.
|
||||||
|
(unsigned long long) 0, // buffers
|
||||||
|
(unsigned long long) 0 // shared
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_swap_mem(PyObject *self, PyObject *args) {
|
||||||
|
uint64_t swap_total, swap_free;
|
||||||
|
struct swapent *swdev;
|
||||||
|
int nswap, i;
|
||||||
|
|
||||||
|
nswap = swapctl(SWAP_NSWAP, 0, 0);
|
||||||
|
if (nswap == 0) {
|
||||||
|
// This means there's no swap partition.
|
||||||
|
return Py_BuildValue("(iiiii)", 0, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
swdev = calloc(nswap, sizeof(*swdev));
|
||||||
|
if (swdev == NULL) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swapctl(SWAP_STATS, swdev, nswap) == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Total things up.
|
||||||
|
swap_total = swap_free = 0;
|
||||||
|
for (i = 0; i < nswap; i++) {
|
||||||
|
if (swdev[i].se_flags & SWF_ENABLE) {
|
||||||
|
swap_total += swdev[i].se_nblks * DEV_BSIZE;
|
||||||
|
swap_free += (swdev[i].se_nblks - swdev[i].se_inuse) * DEV_BSIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(swdev);
|
||||||
|
|
||||||
|
// Get swap in/out
|
||||||
|
unsigned int total;
|
||||||
|
size_t size = sizeof(total);
|
||||||
|
struct uvmexp_sysctl uv;
|
||||||
|
int mib[] = {CTL_VM, VM_UVMEXP2};
|
||||||
|
long pagesize = getpagesize();
|
||||||
|
size = sizeof(uv);
|
||||||
|
if (sysctl(mib, 2, &uv, &size, NULL, 0) < 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Py_BuildValue("(LLLll)",
|
||||||
|
swap_total,
|
||||||
|
(swap_total - swap_free),
|
||||||
|
swap_free,
|
||||||
|
(long) uv.pgswapin * pagesize, // swap in
|
||||||
|
(long) uv.pgswapout * pagesize); // swap out
|
||||||
|
|
||||||
|
error:
|
||||||
|
free(swdev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_proc_num_fds(PyObject *self, PyObject *args) {
|
||||||
|
long pid;
|
||||||
|
int cnt;
|
||||||
|
|
||||||
|
struct kinfo_file *freep;
|
||||||
|
|
||||||
|
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
freep = kinfo_getfile(pid, &cnt);
|
||||||
|
if (freep == NULL) {
|
||||||
|
psutil_raise_for_pid(pid, "kinfo_getfile()");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
free(freep);
|
||||||
|
|
||||||
|
return Py_BuildValue("i", cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_per_cpu_times(PyObject *self, PyObject *args) {
|
||||||
|
// XXX: why static?
|
||||||
|
int mib[3];
|
||||||
|
int ncpu;
|
||||||
|
size_t len;
|
||||||
|
size_t size;
|
||||||
|
int i;
|
||||||
|
PyObject *py_cputime = NULL;
|
||||||
|
PyObject *py_retlist = PyList_New(0);
|
||||||
|
|
||||||
|
if (py_retlist == NULL)
|
||||||
|
return NULL;
|
||||||
|
// retrieve the number of cpus
|
||||||
|
mib[0] = CTL_HW;
|
||||||
|
mib[1] = HW_NCPU;
|
||||||
|
len = sizeof(ncpu);
|
||||||
|
if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
uint64_t cpu_time[CPUSTATES];
|
||||||
|
|
||||||
|
for (i = 0; i < ncpu; i++) {
|
||||||
|
// per-cpu info
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_CP_TIME;
|
||||||
|
mib[2] = i;
|
||||||
|
size = sizeof(cpu_time);
|
||||||
|
if (sysctl(mib, 3, &cpu_time, &size, NULL, 0) == -1) {
|
||||||
|
warn("failed to get kern.cptime2");
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
py_cputime = Py_BuildValue(
|
||||||
|
"(ddddd)",
|
||||||
|
(double)cpu_time[CP_USER] / CLOCKS_PER_SEC,
|
||||||
|
(double)cpu_time[CP_NICE] / CLOCKS_PER_SEC,
|
||||||
|
(double)cpu_time[CP_SYS] / CLOCKS_PER_SEC,
|
||||||
|
(double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC,
|
||||||
|
(double)cpu_time[CP_INTR] / CLOCKS_PER_SEC);
|
||||||
|
if (!py_cputime)
|
||||||
|
goto error;
|
||||||
|
if (PyList_Append(py_retlist, py_cputime))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_cputime);
|
||||||
|
}
|
||||||
|
|
||||||
|
return py_retlist;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_cputime);
|
||||||
|
Py_DECREF(py_retlist);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_disk_io_counters(PyObject *self, PyObject *args) {
|
||||||
|
int i, dk_ndrive, mib[3];
|
||||||
|
size_t len;
|
||||||
|
struct io_sysctl *stats = NULL;
|
||||||
|
PyObject *py_disk_info = NULL;
|
||||||
|
PyObject *py_retdict = PyDict_New();
|
||||||
|
|
||||||
|
if (py_retdict == NULL)
|
||||||
|
return NULL;
|
||||||
|
mib[0] = CTL_HW;
|
||||||
|
mib[1] = HW_IOSTATS;
|
||||||
|
mib[2] = sizeof(struct io_sysctl);
|
||||||
|
len = 0;
|
||||||
|
if (sysctl(mib, 3, NULL, &len, NULL, 0) < 0) {
|
||||||
|
warn("can't get HW_IOSTATS");
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
dk_ndrive = (int)(len / sizeof(struct io_sysctl));
|
||||||
|
|
||||||
|
stats = malloc(len);
|
||||||
|
if (stats == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (sysctl(mib, 3, stats, &len, NULL, 0) < 0 ) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < dk_ndrive; i++) {
|
||||||
|
py_disk_info = Py_BuildValue(
|
||||||
|
"(KKKK)",
|
||||||
|
stats[i].rxfer,
|
||||||
|
stats[i].wxfer,
|
||||||
|
stats[i].rbytes,
|
||||||
|
stats[i].wbytes
|
||||||
|
);
|
||||||
|
if (!py_disk_info)
|
||||||
|
goto error;
|
||||||
|
if (PyDict_SetItemString(py_retdict, stats[i].name, py_disk_info))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_disk_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(stats);
|
||||||
|
return py_retdict;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_disk_info);
|
||||||
|
Py_DECREF(py_retdict);
|
||||||
|
if (stats != NULL)
|
||||||
|
free(stats);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_cpu_stats(PyObject *self, PyObject *args) {
|
||||||
|
size_t size;
|
||||||
|
struct uvmexp_sysctl uv;
|
||||||
|
int uvmexp_mib[] = {CTL_VM, VM_UVMEXP2};
|
||||||
|
|
||||||
|
size = sizeof(uv);
|
||||||
|
if (sysctl(uvmexp_mib, 2, &uv, &size, NULL, 0) < 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Py_BuildValue(
|
||||||
|
"IIIIIII",
|
||||||
|
uv.swtch, // ctx switches
|
||||||
|
uv.intrs, // interrupts - XXX always 0, will be determined via /proc
|
||||||
|
uv.softs, // soft interrupts
|
||||||
|
uv.syscalls, // syscalls - XXX always 0
|
||||||
|
uv.traps, // traps
|
||||||
|
uv.faults, // faults
|
||||||
|
uv.forks // forks
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola', Landry Breuil.
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
typedef struct kinfo_proc2 kinfo_proc;
|
||||||
|
|
||||||
|
int psutil_kinfo_proc(pid_t pid, kinfo_proc *proc);
|
||||||
|
struct kinfo_file * kinfo_getfile(pid_t pid, int* cnt);
|
||||||
|
int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount);
|
||||||
|
char *psutil_get_cmd_args(pid_t pid, size_t *argsize);
|
||||||
|
|
||||||
|
//
|
||||||
|
PyObject *psutil_get_cmdline(pid_t pid);
|
||||||
|
PyObject *psutil_proc_threads(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_virtual_mem(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_swap_mem(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_proc_connections(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_per_cpu_times(PyObject *self, PyObject *args);
|
||||||
|
PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_proc_exe(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_proc_num_threads(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_cpu_stats(PyObject* self, PyObject* args);
|
|
@ -0,0 +1,791 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola', Landry Breuil.
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*
|
||||||
|
* Platform-specific module methods for OpenBSD.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/user.h>
|
||||||
|
#include <sys/proc.h>
|
||||||
|
#include <sys/mount.h> // for VFS_*
|
||||||
|
#include <sys/swap.h> // for swap_mem
|
||||||
|
#include <sys/vmmeter.h> // for vmtotal struct
|
||||||
|
#include <signal.h>
|
||||||
|
#include <kvm.h>
|
||||||
|
// connection stuff
|
||||||
|
#include <netdb.h> // for NI_MAXHOST
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/sched.h> // for CPUSTATES & CP_*
|
||||||
|
#define _KERNEL // for DTYPE_*
|
||||||
|
#include <sys/file.h>
|
||||||
|
#undef _KERNEL
|
||||||
|
#include <sys/disk.h> // struct diskstats
|
||||||
|
#include <arpa/inet.h> // for inet_ntoa()
|
||||||
|
#include <err.h> // for warn() & err()
|
||||||
|
|
||||||
|
#include "../../_psutil_common.h"
|
||||||
|
#include "../../_psutil_posix.h"
|
||||||
|
|
||||||
|
#define PSUTIL_KPT2DOUBLE(t) (t ## _sec + t ## _usec / 1000000.0)
|
||||||
|
// #define PSUTIL_TV2DOUBLE(t) ((t).tv_sec + (t).tv_usec / 1000000.0)
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Utility functions
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
int
|
||||||
|
psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc) {
|
||||||
|
// Fills a kinfo_proc struct based on process pid.
|
||||||
|
int ret;
|
||||||
|
int mib[6];
|
||||||
|
size_t size = sizeof(struct kinfo_proc);
|
||||||
|
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_PROC;
|
||||||
|
mib[2] = KERN_PROC_PID;
|
||||||
|
mib[3] = pid;
|
||||||
|
mib[4] = size;
|
||||||
|
mib[5] = 1;
|
||||||
|
|
||||||
|
ret = sysctl((int*)mib, 6, proc, &size, NULL, 0);
|
||||||
|
if (ret == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// sysctl stores 0 in the size if we can't find the process information.
|
||||||
|
if (size == 0) {
|
||||||
|
NoSuchProcess("");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct kinfo_file *
|
||||||
|
kinfo_getfile(long pid, int* cnt) {
|
||||||
|
// Mimic's FreeBSD kinfo_file call, taking a pid and a ptr to an
|
||||||
|
// int as arg and returns an array with cnt struct kinfo_file.
|
||||||
|
int mib[6];
|
||||||
|
size_t len;
|
||||||
|
struct kinfo_file* kf;
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_FILE;
|
||||||
|
mib[2] = KERN_FILE_BYPID;
|
||||||
|
mib[3] = (int) pid;
|
||||||
|
mib[4] = sizeof(struct kinfo_file);
|
||||||
|
mib[5] = 0;
|
||||||
|
|
||||||
|
/* get the size of what would be returned */
|
||||||
|
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if ((kf = malloc(len)) == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
mib[5] = (int)(len / sizeof(struct kinfo_file));
|
||||||
|
if (sysctl(mib, 6, kf, &len, NULL, 0) < 0) {
|
||||||
|
free(kf);
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*cnt = (int)(len / sizeof(struct kinfo_file));
|
||||||
|
return kf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// APIS
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
int
|
||||||
|
psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount) {
|
||||||
|
// Returns a list of all BSD processes on the system. This routine
|
||||||
|
// allocates the list and puts it in *procList and a count of the
|
||||||
|
// number of entries in *procCount. You are responsible for freeing
|
||||||
|
// this list (use "free" from System framework).
|
||||||
|
// On success, the function returns 0.
|
||||||
|
// On error, the function returns a BSD errno value.
|
||||||
|
struct kinfo_proc *result;
|
||||||
|
// Declaring name as const requires us to cast it when passing it to
|
||||||
|
// sysctl because the prototype doesn't include the const modifier.
|
||||||
|
char errbuf[_POSIX2_LINE_MAX];
|
||||||
|
int cnt;
|
||||||
|
kvm_t *kd;
|
||||||
|
|
||||||
|
assert(procList != NULL);
|
||||||
|
assert(*procList == NULL);
|
||||||
|
assert(procCount != NULL);
|
||||||
|
|
||||||
|
kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
|
||||||
|
|
||||||
|
if (kd == NULL) {
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = kvm_getprocs(kd, KERN_PROC_ALL, 0, sizeof(struct kinfo_proc), &cnt);
|
||||||
|
if (result == NULL) {
|
||||||
|
kvm_close(kd);
|
||||||
|
err(1, NULL);
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
*procCount = (size_t)cnt;
|
||||||
|
|
||||||
|
size_t mlen = cnt * sizeof(struct kinfo_proc);
|
||||||
|
|
||||||
|
if ((*procList = malloc(mlen)) == NULL) {
|
||||||
|
kvm_close(kd);
|
||||||
|
err(1, NULL);
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(*procList, result, mlen);
|
||||||
|
assert(*procList != NULL);
|
||||||
|
kvm_close(kd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char **
|
||||||
|
_psutil_get_argv(long pid) {
|
||||||
|
static char **argv;
|
||||||
|
int argv_mib[] = {CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV};
|
||||||
|
size_t argv_size = 128;
|
||||||
|
// Loop and reallocate until we have enough space to fit argv.
|
||||||
|
for (;; argv_size *= 2) {
|
||||||
|
if (argv_size >= 8192) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError,
|
||||||
|
"can't allocate enough space for KERN_PROC_ARGV");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if ((argv = realloc(argv, argv_size)) == NULL)
|
||||||
|
continue;
|
||||||
|
if (sysctl(argv_mib, 4, argv, &argv_size, NULL, 0) == 0)
|
||||||
|
return argv;
|
||||||
|
if (errno == ENOMEM)
|
||||||
|
continue;
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// returns the command line as a python list object
|
||||||
|
PyObject *
|
||||||
|
psutil_get_cmdline(long pid) {
|
||||||
|
static char **argv;
|
||||||
|
char **p;
|
||||||
|
PyObject *py_arg = NULL;
|
||||||
|
PyObject *py_retlist = Py_BuildValue("[]");
|
||||||
|
|
||||||
|
if (!py_retlist)
|
||||||
|
return NULL;
|
||||||
|
if (pid < 0)
|
||||||
|
return py_retlist;
|
||||||
|
|
||||||
|
if ((argv = _psutil_get_argv(pid)) == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
for (p = argv; *p != NULL; p++) {
|
||||||
|
py_arg = PyUnicode_DecodeFSDefault(*p);
|
||||||
|
if (!py_arg)
|
||||||
|
goto error;
|
||||||
|
if (PyList_Append(py_retlist, py_arg))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_arg);
|
||||||
|
}
|
||||||
|
return py_retlist;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_arg);
|
||||||
|
Py_DECREF(py_retlist);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_proc_threads(PyObject *self, PyObject *args) {
|
||||||
|
// OpenBSD reference:
|
||||||
|
// https://github.com/janmojzis/pstree/blob/master/proc_kvm.c
|
||||||
|
// Note: this requires root access, else it will fail trying
|
||||||
|
// to access /dev/kmem.
|
||||||
|
long pid;
|
||||||
|
kvm_t *kd = NULL;
|
||||||
|
int nentries, i;
|
||||||
|
char errbuf[4096];
|
||||||
|
struct kinfo_proc *kp;
|
||||||
|
PyObject *py_retlist = PyList_New(0);
|
||||||
|
PyObject *py_tuple = NULL;
|
||||||
|
|
||||||
|
if (py_retlist == NULL)
|
||||||
|
return NULL;
|
||||||
|
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
kd = kvm_openfiles(0, 0, 0, O_RDONLY, errbuf);
|
||||||
|
if (! kd) {
|
||||||
|
if (strstr(errbuf, "Permission denied") != NULL)
|
||||||
|
AccessDenied("");
|
||||||
|
else
|
||||||
|
PyErr_Format(PyExc_RuntimeError, "kvm_openfiles() syscall failed");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
kp = kvm_getprocs(
|
||||||
|
kd, KERN_PROC_PID | KERN_PROC_SHOW_THREADS | KERN_PROC_KTHREAD, pid,
|
||||||
|
sizeof(*kp), &nentries);
|
||||||
|
if (! kp) {
|
||||||
|
if (strstr(errbuf, "Permission denied") != NULL)
|
||||||
|
AccessDenied("");
|
||||||
|
else
|
||||||
|
PyErr_Format(PyExc_RuntimeError, "kvm_getprocs() syscall failed");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nentries; i++) {
|
||||||
|
if (kp[i].p_tid < 0)
|
||||||
|
continue;
|
||||||
|
if (kp[i].p_pid == pid) {
|
||||||
|
py_tuple = Py_BuildValue(
|
||||||
|
"Idd",
|
||||||
|
kp[i].p_tid,
|
||||||
|
PSUTIL_KPT2DOUBLE(kp[i].p_uutime),
|
||||||
|
PSUTIL_KPT2DOUBLE(kp[i].p_ustime));
|
||||||
|
if (py_tuple == NULL)
|
||||||
|
goto error;
|
||||||
|
if (PyList_Append(py_retlist, py_tuple))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_tuple);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kvm_close(kd);
|
||||||
|
return py_retlist;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_tuple);
|
||||||
|
Py_DECREF(py_retlist);
|
||||||
|
if (kd != NULL)
|
||||||
|
kvm_close(kd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_virtual_mem(PyObject *self, PyObject *args) {
|
||||||
|
int64_t total_physmem;
|
||||||
|
int uvmexp_mib[] = {CTL_VM, VM_UVMEXP};
|
||||||
|
int bcstats_mib[] = {CTL_VFS, VFS_GENERIC, VFS_BCACHESTAT};
|
||||||
|
int physmem_mib[] = {CTL_HW, HW_PHYSMEM64};
|
||||||
|
int vmmeter_mib[] = {CTL_VM, VM_METER};
|
||||||
|
size_t size;
|
||||||
|
struct uvmexp uvmexp;
|
||||||
|
struct bcachestats bcstats;
|
||||||
|
struct vmtotal vmdata;
|
||||||
|
long pagesize = getpagesize();
|
||||||
|
|
||||||
|
size = sizeof(total_physmem);
|
||||||
|
if (sysctl(physmem_mib, 2, &total_physmem, &size, NULL, 0) < 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = sizeof(uvmexp);
|
||||||
|
if (sysctl(uvmexp_mib, 2, &uvmexp, &size, NULL, 0) < 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = sizeof(bcstats);
|
||||||
|
if (sysctl(bcstats_mib, 3, &bcstats, &size, NULL, 0) < 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = sizeof(vmdata);
|
||||||
|
if (sysctl(vmmeter_mib, 2, &vmdata, &size, NULL, 0) < 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Py_BuildValue("KKKKKKKK",
|
||||||
|
// Note: many programs calculate total memory as
|
||||||
|
// "uvmexp.npages * pagesize" but this is incorrect and does not
|
||||||
|
// match "sysctl | grep hw.physmem".
|
||||||
|
(unsigned long long) total_physmem,
|
||||||
|
(unsigned long long) uvmexp.free * pagesize,
|
||||||
|
(unsigned long long) uvmexp.active * pagesize,
|
||||||
|
(unsigned long long) uvmexp.inactive * pagesize,
|
||||||
|
(unsigned long long) uvmexp.wired * pagesize,
|
||||||
|
// this is how "top" determines it
|
||||||
|
(unsigned long long) bcstats.numbufpages * pagesize, // cached
|
||||||
|
(unsigned long long) 0, // buffers
|
||||||
|
(unsigned long long) vmdata.t_vmshr + vmdata.t_rmshr // shared
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_swap_mem(PyObject *self, PyObject *args) {
|
||||||
|
uint64_t swap_total, swap_free;
|
||||||
|
struct swapent *swdev;
|
||||||
|
int nswap, i;
|
||||||
|
|
||||||
|
if ((nswap = swapctl(SWAP_NSWAP, 0, 0)) == 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((swdev = calloc(nswap, sizeof(*swdev))) == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (swapctl(SWAP_STATS, swdev, nswap) == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Total things up.
|
||||||
|
swap_total = swap_free = 0;
|
||||||
|
for (i = 0; i < nswap; i++) {
|
||||||
|
if (swdev[i].se_flags & SWF_ENABLE) {
|
||||||
|
swap_free += (swdev[i].se_nblks - swdev[i].se_inuse);
|
||||||
|
swap_total += swdev[i].se_nblks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(swdev);
|
||||||
|
return Py_BuildValue("(LLLII)",
|
||||||
|
swap_total * DEV_BSIZE,
|
||||||
|
(swap_total - swap_free) * DEV_BSIZE,
|
||||||
|
swap_free * DEV_BSIZE,
|
||||||
|
// swap in / swap out is not supported as the
|
||||||
|
// swapent struct does not provide any info
|
||||||
|
// about it.
|
||||||
|
0, 0);
|
||||||
|
|
||||||
|
error:
|
||||||
|
free(swdev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_proc_num_fds(PyObject *self, PyObject *args) {
|
||||||
|
long pid;
|
||||||
|
int cnt;
|
||||||
|
|
||||||
|
struct kinfo_file *freep;
|
||||||
|
struct kinfo_proc kipp;
|
||||||
|
|
||||||
|
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||||
|
return NULL;
|
||||||
|
if (psutil_kinfo_proc(pid, &kipp) == -1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
freep = kinfo_getfile(pid, &cnt);
|
||||||
|
if (freep == NULL) {
|
||||||
|
psutil_raise_for_pid(pid, "kinfo_getfile()");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
free(freep);
|
||||||
|
|
||||||
|
return Py_BuildValue("i", cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_proc_cwd(PyObject *self, PyObject *args) {
|
||||||
|
// Reference:
|
||||||
|
// https://github.com/openbsd/src/blob/
|
||||||
|
// 588f7f8c69786211f2d16865c552afb91b1c7cba/bin/ps/print.c#L191
|
||||||
|
long pid;
|
||||||
|
struct kinfo_proc kp;
|
||||||
|
char path[MAXPATHLEN];
|
||||||
|
size_t pathlen = sizeof path;
|
||||||
|
|
||||||
|
if (! PyArg_ParseTuple(args, "l", &pid))
|
||||||
|
return NULL;
|
||||||
|
if (psutil_kinfo_proc(pid, &kp) == -1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
int name[] = { CTL_KERN, KERN_PROC_CWD, pid };
|
||||||
|
if (sysctl(name, 3, path, &pathlen, NULL, 0) != 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return PyUnicode_DecodeFSDefault(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// see sys/kern/kern_sysctl.c lines 1100 and
|
||||||
|
// usr.bin/fstat/fstat.c print_inet_details()
|
||||||
|
static char *
|
||||||
|
psutil_convert_ipv4(int family, uint32_t addr[4]) {
|
||||||
|
struct in_addr a;
|
||||||
|
memcpy(&a, addr, sizeof(a));
|
||||||
|
return inet_ntoa(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char *
|
||||||
|
psutil_inet6_addrstr(struct in6_addr *p)
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 sin6;
|
||||||
|
static char hbuf[NI_MAXHOST];
|
||||||
|
const int niflags = NI_NUMERICHOST;
|
||||||
|
|
||||||
|
memset(&sin6, 0, sizeof(sin6));
|
||||||
|
sin6.sin6_family = AF_INET6;
|
||||||
|
sin6.sin6_len = sizeof(struct sockaddr_in6);
|
||||||
|
sin6.sin6_addr = *p;
|
||||||
|
if (IN6_IS_ADDR_LINKLOCAL(p) &&
|
||||||
|
*(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) {
|
||||||
|
sin6.sin6_scope_id =
|
||||||
|
ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
|
||||||
|
sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
|
||||||
|
hbuf, sizeof(hbuf), NULL, 0, niflags))
|
||||||
|
return "invalid";
|
||||||
|
|
||||||
|
return hbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List process connections.
|
||||||
|
* Note: there is no net_connections() on OpenBSD. The Python
|
||||||
|
* implementation will iterate over all processes and use this
|
||||||
|
* function.
|
||||||
|
* Note: local and remote paths cannot be determined for UNIX sockets.
|
||||||
|
*/
|
||||||
|
PyObject *
|
||||||
|
psutil_proc_connections(PyObject *self, PyObject *args) {
|
||||||
|
long pid;
|
||||||
|
int i;
|
||||||
|
int cnt;
|
||||||
|
struct kinfo_file *freep = NULL;
|
||||||
|
struct kinfo_file *kif;
|
||||||
|
char *tcplist = NULL;
|
||||||
|
PyObject *py_retlist = PyList_New(0);
|
||||||
|
PyObject *py_tuple = NULL;
|
||||||
|
PyObject *py_laddr = NULL;
|
||||||
|
PyObject *py_raddr = NULL;
|
||||||
|
PyObject *py_af_filter = NULL;
|
||||||
|
PyObject *py_type_filter = NULL;
|
||||||
|
PyObject *py_family = NULL;
|
||||||
|
PyObject *_type = NULL;
|
||||||
|
|
||||||
|
if (py_retlist == NULL)
|
||||||
|
return NULL;
|
||||||
|
if (! PyArg_ParseTuple(args, "lOO", &pid, &py_af_filter, &py_type_filter))
|
||||||
|
goto error;
|
||||||
|
if (!PySequence_Check(py_af_filter) || !PySequence_Check(py_type_filter)) {
|
||||||
|
PyErr_SetString(PyExc_TypeError, "arg 2 or 3 is not a sequence");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
freep = kinfo_getfile(pid, &cnt);
|
||||||
|
if (freep == NULL) {
|
||||||
|
psutil_raise_for_pid(pid, "kinfo_getfile()");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < cnt; i++) {
|
||||||
|
int state;
|
||||||
|
int lport;
|
||||||
|
int rport;
|
||||||
|
char addrbuf[NI_MAXHOST + 2];
|
||||||
|
int inseq;
|
||||||
|
struct in6_addr laddr6;
|
||||||
|
py_tuple = NULL;
|
||||||
|
py_laddr = NULL;
|
||||||
|
py_raddr = NULL;
|
||||||
|
|
||||||
|
kif = &freep[i];
|
||||||
|
if (kif->f_type == DTYPE_SOCKET) {
|
||||||
|
// apply filters
|
||||||
|
py_family = PyLong_FromLong((long)kif->so_family);
|
||||||
|
inseq = PySequence_Contains(py_af_filter, py_family);
|
||||||
|
Py_DECREF(py_family);
|
||||||
|
if (inseq == 0)
|
||||||
|
continue;
|
||||||
|
_type = PyLong_FromLong((long)kif->so_type);
|
||||||
|
inseq = PySequence_Contains(py_type_filter, _type);
|
||||||
|
Py_DECREF(_type);
|
||||||
|
if (inseq == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// IPv4 / IPv6 socket
|
||||||
|
if ((kif->so_family == AF_INET) || (kif->so_family == AF_INET6)) {
|
||||||
|
// fill status
|
||||||
|
if (kif->so_type == SOCK_STREAM)
|
||||||
|
state = kif->t_state;
|
||||||
|
else
|
||||||
|
state = PSUTIL_CONN_NONE;
|
||||||
|
|
||||||
|
// ports
|
||||||
|
lport = ntohs(kif->inp_lport);
|
||||||
|
rport = ntohs(kif->inp_fport);
|
||||||
|
|
||||||
|
// local address, IPv4
|
||||||
|
if (kif->so_family == AF_INET) {
|
||||||
|
py_laddr = Py_BuildValue(
|
||||||
|
"(si)",
|
||||||
|
psutil_convert_ipv4(kif->so_family, kif->inp_laddru),
|
||||||
|
lport);
|
||||||
|
if (!py_laddr)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// local address, IPv6
|
||||||
|
memcpy(&laddr6, kif->inp_laddru, sizeof(laddr6));
|
||||||
|
snprintf(addrbuf, sizeof(addrbuf), "%s",
|
||||||
|
psutil_inet6_addrstr(&laddr6));
|
||||||
|
py_laddr = Py_BuildValue("(si)", addrbuf, lport);
|
||||||
|
if (!py_laddr)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rport != 0) {
|
||||||
|
// remote address, IPv4
|
||||||
|
if (kif->so_family == AF_INET) {
|
||||||
|
py_raddr = Py_BuildValue(
|
||||||
|
"(si)",
|
||||||
|
psutil_convert_ipv4(
|
||||||
|
kif->so_family, kif->inp_faddru),
|
||||||
|
rport);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// remote address, IPv6
|
||||||
|
memcpy(&laddr6, kif->inp_faddru, sizeof(laddr6));
|
||||||
|
snprintf(addrbuf, sizeof(addrbuf), "%s",
|
||||||
|
psutil_inet6_addrstr(&laddr6));
|
||||||
|
py_raddr = Py_BuildValue("(si)", addrbuf, rport);
|
||||||
|
if (!py_raddr)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
py_raddr = Py_BuildValue("()");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!py_raddr)
|
||||||
|
goto error;
|
||||||
|
py_tuple = Py_BuildValue(
|
||||||
|
"(iiiNNi)",
|
||||||
|
kif->fd_fd,
|
||||||
|
kif->so_family,
|
||||||
|
kif->so_type,
|
||||||
|
py_laddr,
|
||||||
|
py_raddr,
|
||||||
|
state);
|
||||||
|
if (!py_tuple)
|
||||||
|
goto error;
|
||||||
|
if (PyList_Append(py_retlist, py_tuple))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_tuple);
|
||||||
|
}
|
||||||
|
// UNIX socket.
|
||||||
|
// XXX: local addr is supposed to be in "unp_path" but it
|
||||||
|
// always empty; also "fstat" command is not able to show
|
||||||
|
// UNIX socket paths.
|
||||||
|
else if (kif->so_family == AF_UNIX) {
|
||||||
|
py_tuple = Py_BuildValue(
|
||||||
|
"(iiissi)",
|
||||||
|
kif->fd_fd,
|
||||||
|
kif->so_family,
|
||||||
|
kif->so_type,
|
||||||
|
"", // laddr (kif->unp_path is empty)
|
||||||
|
"", // raddr
|
||||||
|
PSUTIL_CONN_NONE);
|
||||||
|
if (!py_tuple)
|
||||||
|
goto error;
|
||||||
|
if (PyList_Append(py_retlist, py_tuple))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_tuple);
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(freep);
|
||||||
|
free(tcplist);
|
||||||
|
return py_retlist;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_tuple);
|
||||||
|
Py_XDECREF(py_laddr);
|
||||||
|
Py_XDECREF(py_raddr);
|
||||||
|
Py_DECREF(py_retlist);
|
||||||
|
if (freep != NULL)
|
||||||
|
free(freep);
|
||||||
|
if (tcplist != NULL)
|
||||||
|
free(tcplist);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_per_cpu_times(PyObject *self, PyObject *args) {
|
||||||
|
int mib[3];
|
||||||
|
int ncpu;
|
||||||
|
size_t len;
|
||||||
|
size_t size;
|
||||||
|
int i;
|
||||||
|
PyObject *py_retlist = PyList_New(0);
|
||||||
|
PyObject *py_cputime = NULL;
|
||||||
|
|
||||||
|
if (py_retlist == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
|
||||||
|
// retrieve the number of cpus
|
||||||
|
mib[0] = CTL_HW;
|
||||||
|
mib[1] = HW_NCPU;
|
||||||
|
len = sizeof(ncpu);
|
||||||
|
if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
uint64_t cpu_time[CPUSTATES];
|
||||||
|
|
||||||
|
for (i = 0; i < ncpu; i++) {
|
||||||
|
// per-cpu info
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_CPTIME2;
|
||||||
|
mib[2] = i;
|
||||||
|
size = sizeof(cpu_time);
|
||||||
|
if (sysctl(mib, 3, &cpu_time, &size, NULL, 0) == -1) {
|
||||||
|
warn("failed to get kern.cptime2");
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
py_cputime = Py_BuildValue(
|
||||||
|
"(ddddd)",
|
||||||
|
(double)cpu_time[CP_USER] / CLOCKS_PER_SEC,
|
||||||
|
(double)cpu_time[CP_NICE] / CLOCKS_PER_SEC,
|
||||||
|
(double)cpu_time[CP_SYS] / CLOCKS_PER_SEC,
|
||||||
|
(double)cpu_time[CP_IDLE] / CLOCKS_PER_SEC,
|
||||||
|
(double)cpu_time[CP_INTR] / CLOCKS_PER_SEC);
|
||||||
|
if (!py_cputime)
|
||||||
|
goto error;
|
||||||
|
if (PyList_Append(py_retlist, py_cputime))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_cputime);
|
||||||
|
}
|
||||||
|
|
||||||
|
return py_retlist;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_cputime);
|
||||||
|
Py_DECREF(py_retlist);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_disk_io_counters(PyObject *self, PyObject *args) {
|
||||||
|
int i, dk_ndrive, mib[3];
|
||||||
|
size_t len;
|
||||||
|
struct diskstats *stats = NULL;
|
||||||
|
|
||||||
|
PyObject *py_retdict = PyDict_New();
|
||||||
|
PyObject *py_disk_info = NULL;
|
||||||
|
if (py_retdict == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
mib[0] = CTL_HW;
|
||||||
|
mib[1] = HW_DISKSTATS;
|
||||||
|
len = 0;
|
||||||
|
if (sysctl(mib, 2, NULL, &len, NULL, 0) < 0) {
|
||||||
|
warn("can't get hw.diskstats size");
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
dk_ndrive = (int)(len / sizeof(struct diskstats));
|
||||||
|
|
||||||
|
stats = malloc(len);
|
||||||
|
if (stats == NULL) {
|
||||||
|
warn("can't malloc");
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (sysctl(mib, 2, stats, &len, NULL, 0) < 0 ) {
|
||||||
|
warn("could not read hw.diskstats");
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < dk_ndrive; i++) {
|
||||||
|
py_disk_info = Py_BuildValue(
|
||||||
|
"(KKKK)",
|
||||||
|
stats[i].ds_rxfer, // num reads
|
||||||
|
stats[i].ds_wxfer, // num writes
|
||||||
|
stats[i].ds_rbytes, // read bytes
|
||||||
|
stats[i].ds_wbytes // write bytes
|
||||||
|
);
|
||||||
|
if (!py_disk_info)
|
||||||
|
goto error;
|
||||||
|
if (PyDict_SetItemString(py_retdict, stats[i].ds_name, py_disk_info))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_disk_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(stats);
|
||||||
|
return py_retdict;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_disk_info);
|
||||||
|
Py_DECREF(py_retdict);
|
||||||
|
if (stats != NULL)
|
||||||
|
free(stats);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyObject *
|
||||||
|
psutil_cpu_stats(PyObject *self, PyObject *args) {
|
||||||
|
size_t size;
|
||||||
|
struct uvmexp uv;
|
||||||
|
int uvmexp_mib[] = {CTL_VM, VM_UVMEXP};
|
||||||
|
|
||||||
|
size = sizeof(uv);
|
||||||
|
if (sysctl(uvmexp_mib, 2, &uv, &size, NULL, 0) < 0) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Py_BuildValue(
|
||||||
|
"IIIIIII",
|
||||||
|
uv.swtch, // ctx switches
|
||||||
|
uv.intrs, // interrupts - XXX always 0, will be determined via /proc
|
||||||
|
uv.softs, // soft interrupts
|
||||||
|
uv.syscalls, // syscalls - XXX always 0
|
||||||
|
uv.traps, // traps
|
||||||
|
uv.faults, // faults
|
||||||
|
uv.forks // forks
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola', Landry Breuil.
|
||||||
|
* All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
typedef struct kinfo_proc kinfo_proc;
|
||||||
|
|
||||||
|
int psutil_kinfo_proc(pid_t pid, struct kinfo_proc *proc);
|
||||||
|
struct kinfo_file * kinfo_getfile(long pid, int* cnt);
|
||||||
|
int psutil_get_proc_list(struct kinfo_proc **procList, size_t *procCount);
|
||||||
|
char **_psutil_get_argv(long pid);
|
||||||
|
PyObject * psutil_get_cmdline(long pid);
|
||||||
|
|
||||||
|
//
|
||||||
|
PyObject *psutil_proc_threads(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_virtual_mem(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_swap_mem(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_proc_num_fds(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_proc_cwd(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_proc_connections(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_per_cpu_times(PyObject *self, PyObject *args);
|
||||||
|
PyObject* psutil_disk_io_counters(PyObject* self, PyObject* args);
|
||||||
|
PyObject* psutil_cpu_stats(PyObject* self, PyObject* args);
|
|
@ -21,28 +21,7 @@
|
||||||
|
|
||||||
#include "process_info.h"
|
#include "process_info.h"
|
||||||
#include "../../_psutil_common.h"
|
#include "../../_psutil_common.h"
|
||||||
|
#include "../../_psutil_posix.h"
|
||||||
|
|
||||||
/*
|
|
||||||
* Return 1 if PID exists in the current process list, else 0.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
psutil_pid_exists(long pid)
|
|
||||||
{
|
|
||||||
int kill_ret;
|
|
||||||
|
|
||||||
// save some time if it's an invalid PID
|
|
||||||
if (pid < 0)
|
|
||||||
return 0;
|
|
||||||
// if kill returns success of permission denied we know it's a valid PID
|
|
||||||
kill_ret = kill(pid , 0);
|
|
||||||
if ( (0 == kill_ret) || (EPERM == errno))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
// otherwise return 0 for PID not found
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns a list of all BSD processes on the system. This routine
|
* Returns a list of all BSD processes on the system. This routine
|
||||||
|
@ -53,14 +32,12 @@ psutil_pid_exists(long pid)
|
||||||
* On error, the function returns a BSD errno value.
|
* On error, the function returns a BSD errno value.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
psutil_get_proc_list(kinfo_proc **procList, size_t *procCount)
|
psutil_get_proc_list(kinfo_proc **procList, size_t *procCount) {
|
||||||
{
|
int mib3[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
|
||||||
// Declaring mib as const requires use of a cast since the
|
size_t size, size2;
|
||||||
// sysctl prototype doesn't include the const modifier.
|
void *ptr;
|
||||||
static const int mib3[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
|
int err;
|
||||||
size_t size, size2;
|
int lim = 8; // some limit
|
||||||
void *ptr;
|
|
||||||
int err, lim = 8; // some limit
|
|
||||||
|
|
||||||
assert( procList != NULL);
|
assert( procList != NULL);
|
||||||
assert(*procList == NULL);
|
assert(*procList == NULL);
|
||||||
|
@ -116,8 +93,7 @@ psutil_get_proc_list(kinfo_proc **procList, size_t *procCount)
|
||||||
|
|
||||||
// Read the maximum argument size for processes
|
// Read the maximum argument size for processes
|
||||||
int
|
int
|
||||||
psutil_get_argmax()
|
psutil_get_argmax() {
|
||||||
{
|
|
||||||
int argmax;
|
int argmax;
|
||||||
int mib[] = { CTL_KERN, KERN_ARGMAX };
|
int mib[] = { CTL_KERN, KERN_ARGMAX };
|
||||||
size_t size = sizeof(argmax);
|
size_t size = sizeof(argmax);
|
||||||
|
@ -130,18 +106,18 @@ psutil_get_argmax()
|
||||||
|
|
||||||
// return process args as a python list
|
// return process args as a python list
|
||||||
PyObject *
|
PyObject *
|
||||||
psutil_get_arg_list(long pid)
|
psutil_get_cmdline(long pid) {
|
||||||
{
|
|
||||||
int mib[3];
|
int mib[3];
|
||||||
int nargs;
|
int nargs;
|
||||||
int len;
|
size_t len;
|
||||||
char *procargs = NULL;
|
char *procargs = NULL;
|
||||||
char *arg_ptr;
|
char *arg_ptr;
|
||||||
char *arg_end;
|
char *arg_end;
|
||||||
char *curr_arg;
|
char *curr_arg;
|
||||||
size_t argmax;
|
size_t argmax;
|
||||||
PyObject *arg = NULL;
|
|
||||||
PyObject *arglist = NULL;
|
PyObject *py_arg = NULL;
|
||||||
|
PyObject *py_retlist = NULL;
|
||||||
|
|
||||||
// special case for PID 0 (kernel_task) where cmdline cannot be fetched
|
// special case for PID 0 (kernel_task) where cmdline cannot be fetched
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
|
@ -163,15 +139,14 @@ psutil_get_arg_list(long pid)
|
||||||
// read argument space
|
// read argument space
|
||||||
mib[0] = CTL_KERN;
|
mib[0] = CTL_KERN;
|
||||||
mib[1] = KERN_PROCARGS2;
|
mib[1] = KERN_PROCARGS2;
|
||||||
mib[2] = pid;
|
mib[2] = (pid_t)pid;
|
||||||
if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) {
|
if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) {
|
||||||
if (EINVAL == errno) {
|
// In case of zombie process we'll get EINVAL. We translate it
|
||||||
// EINVAL == access denied OR nonexistent PID
|
// to NSP and _psosx.py will translate it to ZP.
|
||||||
if (psutil_pid_exists(pid))
|
if ((errno == EINVAL) && (psutil_pid_exists(pid)))
|
||||||
AccessDenied();
|
NoSuchProcess("");
|
||||||
else
|
else
|
||||||
NoSuchProcess();
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
}
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,17 +171,17 @@ psutil_get_arg_list(long pid)
|
||||||
|
|
||||||
// iterate through arguments
|
// iterate through arguments
|
||||||
curr_arg = arg_ptr;
|
curr_arg = arg_ptr;
|
||||||
arglist = Py_BuildValue("[]");
|
py_retlist = Py_BuildValue("[]");
|
||||||
if (!arglist)
|
if (!py_retlist)
|
||||||
goto error;
|
goto error;
|
||||||
while (arg_ptr < arg_end && nargs > 0) {
|
while (arg_ptr < arg_end && nargs > 0) {
|
||||||
if (*arg_ptr++ == '\0') {
|
if (*arg_ptr++ == '\0') {
|
||||||
arg = Py_BuildValue("s", curr_arg);
|
py_arg = PyUnicode_DecodeFSDefault(curr_arg);
|
||||||
if (!arg)
|
if (! py_arg)
|
||||||
goto error;
|
goto error;
|
||||||
if (PyList_Append(arglist, arg))
|
if (PyList_Append(py_retlist, py_arg))
|
||||||
goto error;
|
goto error;
|
||||||
Py_DECREF(arg);
|
Py_DECREF(py_arg);
|
||||||
// iterate to next arg and decrement # of args
|
// iterate to next arg and decrement # of args
|
||||||
curr_arg = arg_ptr;
|
curr_arg = arg_ptr;
|
||||||
nargs--;
|
nargs--;
|
||||||
|
@ -214,26 +189,142 @@ psutil_get_arg_list(long pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
free(procargs);
|
free(procargs);
|
||||||
return arglist;
|
return py_retlist;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
Py_XDECREF(arg);
|
Py_XDECREF(py_arg);
|
||||||
Py_XDECREF(arglist);
|
Py_XDECREF(py_retlist);
|
||||||
if (procargs != NULL)
|
if (procargs != NULL)
|
||||||
free(procargs);
|
free(procargs);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return process environment as a python string
|
||||||
|
PyObject *
|
||||||
|
psutil_get_environ(long pid) {
|
||||||
|
int mib[3];
|
||||||
|
int nargs;
|
||||||
|
char *procargs = NULL;
|
||||||
|
char *procenv = NULL;
|
||||||
|
char *arg_ptr;
|
||||||
|
char *arg_end;
|
||||||
|
char *env_start;
|
||||||
|
size_t argmax;
|
||||||
|
PyObject *py_ret = NULL;
|
||||||
|
|
||||||
|
// special case for PID 0 (kernel_task) where cmdline cannot be fetched
|
||||||
|
if (pid == 0)
|
||||||
|
goto empty;
|
||||||
|
|
||||||
|
// read argmax and allocate memory for argument space.
|
||||||
|
argmax = psutil_get_argmax();
|
||||||
|
if (! argmax) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
procargs = (char *)malloc(argmax);
|
||||||
|
if (NULL == procargs) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read argument space
|
||||||
|
mib[0] = CTL_KERN;
|
||||||
|
mib[1] = KERN_PROCARGS2;
|
||||||
|
mib[2] = (pid_t)pid;
|
||||||
|
if (sysctl(mib, 3, procargs, &argmax, NULL, 0) < 0) {
|
||||||
|
// In case of zombie process we'll get EINVAL. We translate it
|
||||||
|
// to NSP and _psosx.py will translate it to ZP.
|
||||||
|
if ((errno == EINVAL) && (psutil_pid_exists(pid)))
|
||||||
|
NoSuchProcess("");
|
||||||
|
else
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_end = &procargs[argmax];
|
||||||
|
// copy the number of arguments to nargs
|
||||||
|
memcpy(&nargs, procargs, sizeof(nargs));
|
||||||
|
|
||||||
|
// skip executable path
|
||||||
|
arg_ptr = procargs + sizeof(nargs);
|
||||||
|
arg_ptr = memchr(arg_ptr, '\0', arg_end - arg_ptr);
|
||||||
|
|
||||||
|
if (arg_ptr == NULL || arg_ptr == arg_end)
|
||||||
|
goto empty;
|
||||||
|
|
||||||
|
// skip ahead to the first argument
|
||||||
|
for (; arg_ptr < arg_end; arg_ptr++) {
|
||||||
|
if (*arg_ptr != '\0')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate through arguments
|
||||||
|
while (arg_ptr < arg_end && nargs > 0) {
|
||||||
|
if (*arg_ptr++ == '\0')
|
||||||
|
nargs--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build an environment variable block
|
||||||
|
env_start = arg_ptr;
|
||||||
|
|
||||||
|
procenv = calloc(1, arg_end - arg_ptr);
|
||||||
|
if (procenv == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*arg_ptr != '\0' && arg_ptr < arg_end) {
|
||||||
|
char *s = memchr(arg_ptr + 1, '\0', arg_end - arg_ptr);
|
||||||
|
|
||||||
|
if (s == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
memcpy(procenv + (arg_ptr - env_start), arg_ptr, s - arg_ptr);
|
||||||
|
|
||||||
|
arg_ptr = s + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
py_ret = PyUnicode_DecodeFSDefaultAndSize(
|
||||||
|
procenv, arg_ptr - env_start + 1);
|
||||||
|
if (!py_ret) {
|
||||||
|
// XXX: don't want to free() this as per:
|
||||||
|
// https://github.com/giampaolo/psutil/issues/926
|
||||||
|
// It sucks but not sure what else to do.
|
||||||
|
procargs = NULL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(procargs);
|
||||||
|
free(procenv);
|
||||||
|
|
||||||
|
return py_ret;
|
||||||
|
|
||||||
|
empty:
|
||||||
|
if (procargs != NULL)
|
||||||
|
free(procargs);
|
||||||
|
return Py_BuildValue("s", "");
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_ret);
|
||||||
|
if (procargs != NULL)
|
||||||
|
free(procargs);
|
||||||
|
if (procenv != NULL)
|
||||||
|
free(procargs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp)
|
psutil_get_kinfo_proc(long pid, struct kinfo_proc *kp) {
|
||||||
{
|
|
||||||
int mib[4];
|
int mib[4];
|
||||||
size_t len;
|
size_t len;
|
||||||
mib[0] = CTL_KERN;
|
mib[0] = CTL_KERN;
|
||||||
mib[1] = KERN_PROC;
|
mib[1] = KERN_PROC;
|
||||||
mib[2] = KERN_PROC_PID;
|
mib[2] = KERN_PROC_PID;
|
||||||
mib[3] = pid;
|
mib[3] = (pid_t)pid;
|
||||||
|
|
||||||
// fetch the info with sysctl()
|
// fetch the info with sysctl()
|
||||||
len = sizeof(struct kinfo_proc);
|
len = sizeof(struct kinfo_proc);
|
||||||
|
@ -247,7 +338,7 @@ psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp)
|
||||||
|
|
||||||
// sysctl succeeds but len is zero, happens when process has gone away
|
// sysctl succeeds but len is zero, happens when process has gone away
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
NoSuchProcess();
|
NoSuchProcess("");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -255,27 +346,16 @@ psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A thin wrapper around proc_pidinfo()
|
* A wrapper around proc_pidinfo().
|
||||||
|
* Returns 0 on failure (and Python exception gets already set).
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
psutil_proc_pidinfo(long pid, int flavor, void *pti, int size)
|
psutil_proc_pidinfo(long pid, int flavor, uint64_t arg, void *pti, int size) {
|
||||||
{
|
errno = 0;
|
||||||
int ret = proc_pidinfo((int)pid, flavor, 0, pti, size);
|
int ret = proc_pidinfo((int)pid, flavor, arg, pti, size);
|
||||||
if (ret == 0) {
|
if ((ret <= 0) || ((unsigned long)ret < sizeof(pti))) {
|
||||||
if (! psutil_pid_exists(pid)) {
|
psutil_raise_for_pid(pid, "proc_pidinfo()");
|
||||||
NoSuchProcess();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
AccessDenied();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ret != size) {
|
|
||||||
AccessDenied();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else {
|
return ret;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,9 @@
|
||||||
typedef struct kinfo_proc kinfo_proc;
|
typedef struct kinfo_proc kinfo_proc;
|
||||||
|
|
||||||
int psutil_get_argmax(void);
|
int psutil_get_argmax(void);
|
||||||
int psutil_get_kinfo_proc(pid_t pid, struct kinfo_proc *kp);
|
int psutil_get_kinfo_proc(long pid, struct kinfo_proc *kp);
|
||||||
int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount);
|
int psutil_get_proc_list(kinfo_proc **procList, size_t *procCount);
|
||||||
int psutil_pid_exists(long pid);
|
int psutil_proc_pidinfo(
|
||||||
int psutil_proc_pidinfo(long pid, int flavor, void *pti, int size);
|
long pid, int flavor, uint64_t arg, void *pti, int size);
|
||||||
PyObject* psutil_get_arg_list(long pid);
|
PyObject* psutil_get_cmdline(long pid);
|
||||||
|
PyObject* psutil_get_environ(long pid);
|
||||||
|
|
|
@ -0,0 +1,405 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola', Oleksii Shevchuk.
|
||||||
|
* All rights reserved. Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
*
|
||||||
|
* Functions specific for Process.environ().
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define NEW_MIB_COMPLIANT 1
|
||||||
|
#define _STRUCTURED_PROC 1
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
#if !defined(_LP64) && _FILE_OFFSET_BITS == 64
|
||||||
|
# undef _FILE_OFFSET_BITS
|
||||||
|
# undef _LARGEFILE64_SOURCE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/procfs.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include "environ.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define STRING_SEARCH_BUF_SIZE 512
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open address space of specified process and return file descriptor.
|
||||||
|
* @param pid a pid of process.
|
||||||
|
* @param procfs_path a path to mounted procfs filesystem.
|
||||||
|
* @return file descriptor or -1 in case of error.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
open_address_space(pid_t pid, const char *procfs_path) {
|
||||||
|
int fd;
|
||||||
|
char proc_path[PATH_MAX];
|
||||||
|
|
||||||
|
snprintf(proc_path, PATH_MAX, "%s/%i/as", procfs_path, pid);
|
||||||
|
fd = open(proc_path, O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read chunk of data by offset to specified buffer of the same size.
|
||||||
|
* @param fd a file descriptor.
|
||||||
|
* @param offset an required offset in file.
|
||||||
|
* @param buf a buffer where to store result.
|
||||||
|
* @param buf_size a size of buffer where data will be stored.
|
||||||
|
* @return amount of bytes stored to the buffer or -1 in case of
|
||||||
|
* error.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
read_offt(int fd, off_t offset, char *buf, size_t buf_size) {
|
||||||
|
size_t to_read = buf_size;
|
||||||
|
size_t stored = 0;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
while (to_read) {
|
||||||
|
r = pread(fd, buf + stored, to_read, offset + stored);
|
||||||
|
if (r < 0)
|
||||||
|
goto error;
|
||||||
|
else if (r == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
to_read -= r;
|
||||||
|
stored += r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stored;
|
||||||
|
|
||||||
|
error:
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read null-terminated string from file descriptor starting from
|
||||||
|
* specified offset.
|
||||||
|
* @param fd a file descriptor of opened address space.
|
||||||
|
* @param offset an offset in specified file descriptor.
|
||||||
|
* @return allocated null-terminated string or NULL in case of error.
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
read_cstring_offt(int fd, off_t offset) {
|
||||||
|
int r;
|
||||||
|
int i = 0;
|
||||||
|
off_t end = offset;
|
||||||
|
size_t len;
|
||||||
|
char buf[STRING_SEARCH_BUF_SIZE];
|
||||||
|
char *result = NULL;
|
||||||
|
|
||||||
|
if (lseek(fd, offset, SEEK_SET) == (off_t)-1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search end of string
|
||||||
|
for (;;) {
|
||||||
|
r = read(fd, buf, sizeof(buf));
|
||||||
|
if (r == -1) {
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
else if (r == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (i=0; i<r; i++)
|
||||||
|
if (! buf[i])
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
|
||||||
|
end += r;
|
||||||
|
}
|
||||||
|
|
||||||
|
found:
|
||||||
|
len = end + i - offset;
|
||||||
|
|
||||||
|
result = malloc(len+1);
|
||||||
|
if (! result) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len) {
|
||||||
|
if (read_offt(fd, offset, result, len) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result[len] = '\0';
|
||||||
|
return result;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (result)
|
||||||
|
free(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read block of addresses by offset, dereference them one by one
|
||||||
|
* and create an array of null terminated C strings from them.
|
||||||
|
* @param fd a file descriptor of address space of interesting process.
|
||||||
|
* @param offset an offset of address block in address space.
|
||||||
|
* @param ptr_size a size of pointer. Only 4 or 8 are valid values.
|
||||||
|
* @param count amount of pointers in block.
|
||||||
|
* @return allocated array of strings dereferenced and read by offset.
|
||||||
|
* Number of elements in array are count. In case of error function
|
||||||
|
* returns NULL.
|
||||||
|
*/
|
||||||
|
static char **
|
||||||
|
read_cstrings_block(int fd, off_t offset, size_t ptr_size, size_t count) {
|
||||||
|
char **result = NULL;
|
||||||
|
char *pblock = NULL;
|
||||||
|
size_t pblock_size;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
assert(ptr_size == 4 || ptr_size == 8);
|
||||||
|
|
||||||
|
if (!count)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
pblock_size = ptr_size * count;
|
||||||
|
|
||||||
|
pblock = malloc(pblock_size);
|
||||||
|
if (! pblock) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read_offt(fd, offset, pblock, pblock_size) != pblock_size)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
result = (char **) calloc(count, sizeof(char *));
|
||||||
|
if (! result) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i<count; i++) {
|
||||||
|
result[i] = read_cstring_offt(
|
||||||
|
fd, (ptr_size == 4?
|
||||||
|
((uint32_t *) pblock)[i]:
|
||||||
|
((uint64_t *) pblock)[i]));
|
||||||
|
|
||||||
|
if (!result[i])
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(pblock);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (result)
|
||||||
|
psutil_free_cstrings_array(result, i);
|
||||||
|
if (pblock)
|
||||||
|
free(pblock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that caller process can extract proper values from psinfo_t
|
||||||
|
* structure.
|
||||||
|
* @param info a pointer to process info (psinfo_t) structure of the
|
||||||
|
* interesting process.
|
||||||
|
* @return 1 in case if caller process can extract proper values from
|
||||||
|
* psinfo_t structure, or 0 otherwise.
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
is_ptr_dereference_possible(psinfo_t info) {
|
||||||
|
#if !defined(_LP64)
|
||||||
|
return info.pr_dmodel == PR_MODEL_ILP32;
|
||||||
|
#else
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return pointer size according to psinfo_t structure
|
||||||
|
* @param info a ponter to process info (psinfo_t) structure of the
|
||||||
|
* interesting process.
|
||||||
|
* @return pointer size (4 or 8).
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
ptr_size_by_psinfo(psinfo_t info) {
|
||||||
|
return info.pr_dmodel == PR_MODEL_ILP32? 4 : 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Count amount of pointers in a block which ends with NULL.
|
||||||
|
* @param fd a discriptor of /proc/PID/as special file.
|
||||||
|
* @param offt an offset of block of pointers at the file.
|
||||||
|
* @param ptr_size a pointer size (allowed values: {4, 8}).
|
||||||
|
* @return amount of non-NULL pointers or -1 in case of error.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
search_pointers_vector_size_offt(int fd, off_t offt, size_t ptr_size) {
|
||||||
|
int count = 0;
|
||||||
|
int r;
|
||||||
|
char buf[8];
|
||||||
|
static const char zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
assert(ptr_size == 4 || ptr_size == 8);
|
||||||
|
|
||||||
|
if (lseek(fd, offt, SEEK_SET) == (off_t)-1)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
for (;; count ++) {
|
||||||
|
r = read(fd, buf, ptr_size);
|
||||||
|
|
||||||
|
if (r < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (r != ptr_size) {
|
||||||
|
PyErr_SetString(
|
||||||
|
PyExc_RuntimeError, "pointer block is truncated");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! memcmp(buf, zeros, ptr_size))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
|
||||||
|
error:
|
||||||
|
PyErr_SetFromErrno(PyExc_OSError);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Derefence and read array of strings by psinfo_t.pr_argv pointer from
|
||||||
|
* remote process.
|
||||||
|
* @param info a ponter to process info (psinfo_t) structure of the
|
||||||
|
* interesting process
|
||||||
|
* @param procfs_path a cstring with path to mounted procfs filesystem.
|
||||||
|
* @param count a pointer to variable where to store amount of elements in
|
||||||
|
* returned array. In case of error value of variable will not be
|
||||||
|
changed.
|
||||||
|
* @return allocated array of cstrings or NULL in case of error.
|
||||||
|
*/
|
||||||
|
char **
|
||||||
|
psutil_read_raw_args(psinfo_t info, const char *procfs_path, size_t *count) {
|
||||||
|
int as;
|
||||||
|
char **result;
|
||||||
|
|
||||||
|
if (! is_ptr_dereference_possible(info)) {
|
||||||
|
PyErr_SetString(
|
||||||
|
PyExc_NotImplementedError,
|
||||||
|
"can't get env of a 64 bit process from a 32 bit process");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! (info.pr_argv && info.pr_argc)) {
|
||||||
|
PyErr_SetString(
|
||||||
|
PyExc_RuntimeError, "process doesn't have arguments block");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
as = open_address_space(info.pr_pid, procfs_path);
|
||||||
|
if (as < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
result = read_cstrings_block(
|
||||||
|
as, info.pr_argv, ptr_size_by_psinfo(info), info.pr_argc
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result && count)
|
||||||
|
*count = info.pr_argc;
|
||||||
|
|
||||||
|
close(as);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dereference and read array of strings by psinfo_t.pr_envp pointer
|
||||||
|
* from remote process.
|
||||||
|
* @param info a ponter to process info (psinfo_t) structure of the
|
||||||
|
* interesting process.
|
||||||
|
* @param procfs_path a cstring with path to mounted procfs filesystem.
|
||||||
|
* @param count a pointer to variable where to store amount of elements in
|
||||||
|
* returned array. In case of error value of variable will not be
|
||||||
|
* changed. To detect special case (described later) variable should be
|
||||||
|
* initialized by -1 or other negative value.
|
||||||
|
* @return allocated array of cstrings or NULL in case of error.
|
||||||
|
* Special case: count set to 0, return NULL.
|
||||||
|
* Special case means there is no error acquired, but no data
|
||||||
|
* retrieved.
|
||||||
|
* Special case exists because the nature of the process. From the
|
||||||
|
* beginning it's not clean how many pointers in envp array. Also
|
||||||
|
* situation when environment is empty is common for kernel processes.
|
||||||
|
*/
|
||||||
|
char **
|
||||||
|
psutil_read_raw_env(psinfo_t info, const char *procfs_path, ssize_t *count) {
|
||||||
|
int as;
|
||||||
|
int env_count;
|
||||||
|
int ptr_size;
|
||||||
|
char **result = NULL;
|
||||||
|
|
||||||
|
if (! is_ptr_dereference_possible(info)) {
|
||||||
|
PyErr_SetString(
|
||||||
|
PyExc_NotImplementedError,
|
||||||
|
"can't get env of a 64 bit process from a 32 bit process");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
as = open_address_space(info.pr_pid, procfs_path);
|
||||||
|
if (as < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ptr_size = ptr_size_by_psinfo(info);
|
||||||
|
|
||||||
|
env_count = search_pointers_vector_size_offt(
|
||||||
|
as, info.pr_envp, ptr_size);
|
||||||
|
|
||||||
|
if (env_count >= 0 && count)
|
||||||
|
*count = env_count;
|
||||||
|
|
||||||
|
if (env_count > 0)
|
||||||
|
result = read_cstrings_block(
|
||||||
|
as, info.pr_envp, ptr_size, env_count);
|
||||||
|
|
||||||
|
close(as);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free array of cstrings.
|
||||||
|
* @param array an array of cstrings returned by psutil_read_raw_env,
|
||||||
|
* psutil_read_raw_args or any other function.
|
||||||
|
* @param count a count of strings in the passed array
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
psutil_free_cstrings_array(char **array, size_t count) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!array)
|
||||||
|
return;
|
||||||
|
for (i=0; i<count; i++) {
|
||||||
|
if (array[i]) {
|
||||||
|
free(array[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(array);
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola', Oleksii Shevchuk.
|
||||||
|
* All rights reserved. Use of this source code is governed by a BSD-style
|
||||||
|
* license that can be found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PROCESS_AS_UTILS_H
|
||||||
|
#define PROCESS_AS_UTILS_H
|
||||||
|
|
||||||
|
char **
|
||||||
|
psutil_read_raw_args(psinfo_t info, const char *procfs_path, size_t *count);
|
||||||
|
|
||||||
|
char **
|
||||||
|
psutil_read_raw_env(psinfo_t info, const char *procfs_path, ssize_t *count);
|
||||||
|
|
||||||
|
void
|
||||||
|
psutil_free_cstrings_array(char **array, size_t count);
|
||||||
|
|
||||||
|
#endif // PROCESS_AS_UTILS_H
|
|
@ -0,0 +1,124 @@
|
||||||
|
/* Refrences:
|
||||||
|
* https://lists.samba.org/archive/samba-technical/2009-February/063079.html
|
||||||
|
* http://stackoverflow.com/questions/4139405/#4139811
|
||||||
|
* https://github.com/steve-o/openpgm/blob/master/openpgm/pgm/getifaddrs.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/sockio.h>
|
||||||
|
|
||||||
|
#include "ifaddrs.h"
|
||||||
|
|
||||||
|
#define MAX(x,y) ((x)>(y)?(x):(y))
|
||||||
|
#define SIZE(p) MAX((p).ss_len,sizeof(p))
|
||||||
|
|
||||||
|
|
||||||
|
static struct sockaddr *
|
||||||
|
sa_dup (struct sockaddr_storage *sa1)
|
||||||
|
{
|
||||||
|
struct sockaddr *sa2;
|
||||||
|
size_t sz = sizeof(struct sockaddr_storage);
|
||||||
|
sa2 = (struct sockaddr *) calloc(1,sz);
|
||||||
|
memcpy(sa2,sa1,sz);
|
||||||
|
return(sa2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void freeifaddrs (struct ifaddrs *ifp)
|
||||||
|
{
|
||||||
|
if (NULL == ifp) return;
|
||||||
|
free(ifp->ifa_name);
|
||||||
|
free(ifp->ifa_addr);
|
||||||
|
free(ifp->ifa_netmask);
|
||||||
|
free(ifp->ifa_dstaddr);
|
||||||
|
freeifaddrs(ifp->ifa_next);
|
||||||
|
free(ifp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int getifaddrs (struct ifaddrs **ifap)
|
||||||
|
{
|
||||||
|
int sd = -1;
|
||||||
|
char *ccp, *ecp;
|
||||||
|
struct lifconf ifc;
|
||||||
|
struct lifreq *ifr;
|
||||||
|
struct lifnum lifn;
|
||||||
|
struct ifaddrs *cifa = NULL; /* current */
|
||||||
|
struct ifaddrs *pifa = NULL; /* previous */
|
||||||
|
const size_t IFREQSZ = sizeof(struct lifreq);
|
||||||
|
|
||||||
|
sd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sd < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ifc.lifc_buf = NULL;
|
||||||
|
*ifap = NULL;
|
||||||
|
/* find how much memory to allocate for the SIOCGLIFCONF call */
|
||||||
|
lifn.lifn_family = AF_UNSPEC;
|
||||||
|
lifn.lifn_flags = 0;
|
||||||
|
if (ioctl(sd, SIOCGLIFNUM, &lifn) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Sun and Apple code likes to pad the interface count here in case interfaces
|
||||||
|
* are coming up between calls */
|
||||||
|
lifn.lifn_count += 4;
|
||||||
|
|
||||||
|
ifc.lifc_family = AF_UNSPEC;
|
||||||
|
ifc.lifc_len = lifn.lifn_count * sizeof(struct lifreq);
|
||||||
|
ifc.lifc_buf = calloc(1, ifc.lifc_len);
|
||||||
|
if (ioctl(sd, SIOCGLIFCONF, &ifc) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ccp = (char *)ifc.lifc_req;
|
||||||
|
ecp = ccp + ifc.lifc_len;
|
||||||
|
|
||||||
|
while (ccp < ecp) {
|
||||||
|
|
||||||
|
ifr = (struct lifreq *) ccp;
|
||||||
|
cifa = (struct ifaddrs *) calloc(1, sizeof(struct ifaddrs));
|
||||||
|
cifa->ifa_next = NULL;
|
||||||
|
cifa->ifa_name = strdup(ifr->lifr_name);
|
||||||
|
|
||||||
|
if (pifa == NULL) *ifap = cifa; /* first one */
|
||||||
|
else pifa->ifa_next = cifa;
|
||||||
|
|
||||||
|
if (ioctl(sd, SIOCGLIFADDR, ifr, IFREQSZ) < 0)
|
||||||
|
goto error;
|
||||||
|
cifa->ifa_addr = sa_dup(&ifr->lifr_addr);
|
||||||
|
|
||||||
|
if (ioctl(sd, SIOCGLIFNETMASK, ifr, IFREQSZ) < 0)
|
||||||
|
goto error;
|
||||||
|
cifa->ifa_netmask = sa_dup(&ifr->lifr_addr);
|
||||||
|
|
||||||
|
cifa->ifa_flags = 0;
|
||||||
|
cifa->ifa_dstaddr = NULL;
|
||||||
|
|
||||||
|
if (0 == ioctl(sd, SIOCGLIFFLAGS, ifr)) /* optional */
|
||||||
|
cifa->ifa_flags = ifr->lifr_flags;
|
||||||
|
|
||||||
|
if (ioctl(sd, SIOCGLIFDSTADDR, ifr, IFREQSZ) < 0) {
|
||||||
|
if (0 == ioctl(sd, SIOCGLIFBRDADDR, ifr, IFREQSZ))
|
||||||
|
cifa->ifa_dstaddr = sa_dup(&ifr->lifr_addr);
|
||||||
|
}
|
||||||
|
else cifa->ifa_dstaddr = sa_dup(&ifr->lifr_addr);
|
||||||
|
|
||||||
|
pifa = cifa;
|
||||||
|
ccp += IFREQSZ;
|
||||||
|
}
|
||||||
|
free(ifc.lifc_buf);
|
||||||
|
close(sd);
|
||||||
|
return 0;
|
||||||
|
error:
|
||||||
|
if (ifc.lifc_buf != NULL)
|
||||||
|
free(ifc.lifc_buf);
|
||||||
|
if (sd != -1)
|
||||||
|
close(sd);
|
||||||
|
return (-1);
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
/* Reference: https://lists.samba.org/archive/samba-technical/2009-February/063079.html */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __IFADDRS_H__
|
||||||
|
#define __IFADDRS_H__
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
|
||||||
|
#undef ifa_dstaddr
|
||||||
|
#undef ifa_broadaddr
|
||||||
|
#define ifa_broadaddr ifa_dstaddr
|
||||||
|
|
||||||
|
struct ifaddrs {
|
||||||
|
struct ifaddrs *ifa_next;
|
||||||
|
char *ifa_name;
|
||||||
|
unsigned int ifa_flags;
|
||||||
|
struct sockaddr *ifa_addr;
|
||||||
|
struct sockaddr *ifa_netmask;
|
||||||
|
struct sockaddr *ifa_dstaddr;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int getifaddrs(struct ifaddrs **);
|
||||||
|
extern void freeifaddrs(struct ifaddrs *);
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,41 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola', Jeff Tang. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
#include "inet_ntop.h"
|
#include "inet_ntop.h"
|
||||||
|
|
||||||
// From: https://memset.wordpress.com/2010/10/09/inet_ntop-for-win32/
|
// From: https://memset.wordpress.com/2010/10/09/inet_ntop-for-win32/
|
||||||
PCSTR
|
PCSTR WSAAPI
|
||||||
WSAAPI
|
inet_ntop(__in INT family,
|
||||||
inet_ntop(
|
__in PVOID pAddr,
|
||||||
__in INT Family,
|
__out_ecount(StringBufSize) PSTR pStringBuf,
|
||||||
__in PVOID pAddr,
|
__in size_t StringBufSize) {
|
||||||
__out_ecount(StringBufSize) PSTR pStringBuf,
|
|
||||||
__in size_t StringBufSize
|
|
||||||
)
|
|
||||||
{
|
|
||||||
DWORD dwAddressLength = 0;
|
DWORD dwAddressLength = 0;
|
||||||
struct sockaddr_storage srcaddr;
|
struct sockaddr_storage srcaddr;
|
||||||
struct sockaddr_in *srcaddr4 = (struct sockaddr_in*) &srcaddr;
|
struct sockaddr_in *srcaddr4 = (struct sockaddr_in*) &srcaddr;
|
||||||
struct sockaddr_in6 *srcaddr6 = (struct sockaddr_in6*) &srcaddr;
|
struct sockaddr_in6 *srcaddr6 = (struct sockaddr_in6*) &srcaddr;
|
||||||
|
|
||||||
memset(&srcaddr, 0, sizeof(struct sockaddr_storage));
|
memset(&srcaddr, 0, sizeof(struct sockaddr_storage));
|
||||||
srcaddr.ss_family = Family;
|
srcaddr.ss_family = family;
|
||||||
|
|
||||||
if (Family == AF_INET)
|
if (family == AF_INET) {
|
||||||
{
|
|
||||||
dwAddressLength = sizeof(struct sockaddr_in);
|
dwAddressLength = sizeof(struct sockaddr_in);
|
||||||
memcpy(&(srcaddr4->sin_addr), pAddr, sizeof(struct in_addr));
|
memcpy(&(srcaddr4->sin_addr), pAddr, sizeof(struct in_addr));
|
||||||
} else if (Family == AF_INET6)
|
}
|
||||||
{
|
else if (family == AF_INET6) {
|
||||||
dwAddressLength = sizeof(struct sockaddr_in6);
|
dwAddressLength = sizeof(struct sockaddr_in6);
|
||||||
memcpy(&(srcaddr6->sin6_addr), pAddr, sizeof(struct in6_addr));
|
memcpy(&(srcaddr6->sin6_addr), pAddr, sizeof(struct in6_addr));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "invalid family");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WSAAddressToString((LPSOCKADDR) &srcaddr,
|
if (WSAAddressToString((LPSOCKADDR) &srcaddr,
|
||||||
dwAddressLength,
|
dwAddressLength,
|
||||||
0,
|
0,
|
||||||
pStringBuf,
|
pStringBuf,
|
||||||
(LPDWORD) &StringBufSize) != 0) {
|
(LPDWORD) &StringBufSize) != 0) {
|
||||||
|
PyErr_SetExcFromWindowsErr(PyExc_OSError, WSAGetLastError());
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return pStringBuf;
|
return pStringBuf;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola', Jeff Tang. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
PCSTR
|
PCSTR WSAAPI
|
||||||
WSAAPI
|
|
||||||
inet_ntop(
|
inet_ntop(
|
||||||
__in INT Family,
|
__in INT Family,
|
||||||
__in PVOID pAddr,
|
__in PVOID pAddr,
|
||||||
__out_ecount(StringBufSize) PSTR pStringBuf,
|
__out_ecount(StringBufSize) PSTR pStringBuf,
|
||||||
__in size_t StringBufSize
|
__in size_t StringBufSize
|
||||||
);
|
);
|
||||||
|
|
|
@ -7,6 +7,106 @@
|
||||||
#define __NTEXTAPI_H__
|
#define __NTEXTAPI_H__
|
||||||
#include <winternl.h>
|
#include <winternl.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
LARGE_INTEGER IdleTime;
|
||||||
|
LARGE_INTEGER KernelTime;
|
||||||
|
LARGE_INTEGER UserTime;
|
||||||
|
LARGE_INTEGER DpcTime;
|
||||||
|
LARGE_INTEGER InterruptTime;
|
||||||
|
ULONG InterruptCount;
|
||||||
|
} _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
LARGE_INTEGER IdleProcessTime;
|
||||||
|
LARGE_INTEGER IoReadTransferCount;
|
||||||
|
LARGE_INTEGER IoWriteTransferCount;
|
||||||
|
LARGE_INTEGER IoOtherTransferCount;
|
||||||
|
ULONG IoReadOperationCount;
|
||||||
|
ULONG IoWriteOperationCount;
|
||||||
|
ULONG IoOtherOperationCount;
|
||||||
|
ULONG AvailablePages;
|
||||||
|
ULONG CommittedPages;
|
||||||
|
ULONG CommitLimit;
|
||||||
|
ULONG PeakCommitment;
|
||||||
|
ULONG PageFaultCount;
|
||||||
|
ULONG CopyOnWriteCount;
|
||||||
|
ULONG TransitionCount;
|
||||||
|
ULONG CacheTransitionCount;
|
||||||
|
ULONG DemandZeroCount;
|
||||||
|
ULONG PageReadCount;
|
||||||
|
ULONG PageReadIoCount;
|
||||||
|
ULONG CacheReadCount;
|
||||||
|
ULONG CacheIoCount;
|
||||||
|
ULONG DirtyPagesWriteCount;
|
||||||
|
ULONG DirtyWriteIoCount;
|
||||||
|
ULONG MappedPagesWriteCount;
|
||||||
|
ULONG MappedWriteIoCount;
|
||||||
|
ULONG PagedPoolPages;
|
||||||
|
ULONG NonPagedPoolPages;
|
||||||
|
ULONG PagedPoolAllocs;
|
||||||
|
ULONG PagedPoolFrees;
|
||||||
|
ULONG NonPagedPoolAllocs;
|
||||||
|
ULONG NonPagedPoolFrees;
|
||||||
|
ULONG FreeSystemPtes;
|
||||||
|
ULONG ResidentSystemCodePage;
|
||||||
|
ULONG TotalSystemDriverPages;
|
||||||
|
ULONG TotalSystemCodePages;
|
||||||
|
ULONG NonPagedPoolLookasideHits;
|
||||||
|
ULONG PagedPoolLookasideHits;
|
||||||
|
ULONG AvailablePagedPoolPages;
|
||||||
|
ULONG ResidentSystemCachePage;
|
||||||
|
ULONG ResidentPagedPoolPage;
|
||||||
|
ULONG ResidentSystemDriverPage;
|
||||||
|
ULONG CcFastReadNoWait;
|
||||||
|
ULONG CcFastReadWait;
|
||||||
|
ULONG CcFastReadResourceMiss;
|
||||||
|
ULONG CcFastReadNotPossible;
|
||||||
|
ULONG CcFastMdlReadNoWait;
|
||||||
|
ULONG CcFastMdlReadWait;
|
||||||
|
ULONG CcFastMdlReadResourceMiss;
|
||||||
|
ULONG CcFastMdlReadNotPossible;
|
||||||
|
ULONG CcMapDataNoWait;
|
||||||
|
ULONG CcMapDataWait;
|
||||||
|
ULONG CcMapDataNoWaitMiss;
|
||||||
|
ULONG CcMapDataWaitMiss;
|
||||||
|
ULONG CcPinMappedDataCount;
|
||||||
|
ULONG CcPinReadNoWait;
|
||||||
|
ULONG CcPinReadWait;
|
||||||
|
ULONG CcPinReadNoWaitMiss;
|
||||||
|
ULONG CcPinReadWaitMiss;
|
||||||
|
ULONG CcCopyReadNoWait;
|
||||||
|
ULONG CcCopyReadWait;
|
||||||
|
ULONG CcCopyReadNoWaitMiss;
|
||||||
|
ULONG CcCopyReadWaitMiss;
|
||||||
|
ULONG CcMdlReadNoWait;
|
||||||
|
ULONG CcMdlReadWait;
|
||||||
|
ULONG CcMdlReadNoWaitMiss;
|
||||||
|
ULONG CcMdlReadWaitMiss;
|
||||||
|
ULONG CcReadAheadIos;
|
||||||
|
ULONG CcLazyWriteIos;
|
||||||
|
ULONG CcLazyWritePages;
|
||||||
|
ULONG CcDataFlushes;
|
||||||
|
ULONG CcDataPages;
|
||||||
|
ULONG ContextSwitches;
|
||||||
|
ULONG FirstLevelTbFills;
|
||||||
|
ULONG SecondLevelTbFills;
|
||||||
|
ULONG SystemCalls;
|
||||||
|
|
||||||
|
} _SYSTEM_PERFORMANCE_INFORMATION;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ULONG ContextSwitches;
|
||||||
|
ULONG DpcCount;
|
||||||
|
ULONG DpcRate;
|
||||||
|
ULONG TimeIncrement;
|
||||||
|
ULONG DpcBypassCount;
|
||||||
|
ULONG ApcBypassCount;
|
||||||
|
} _SYSTEM_INTERRUPT_INFORMATION;
|
||||||
|
|
||||||
|
|
||||||
typedef enum _KTHREAD_STATE {
|
typedef enum _KTHREAD_STATE {
|
||||||
Initialized,
|
Initialized,
|
||||||
Ready,
|
Ready,
|
||||||
|
@ -20,6 +120,7 @@ typedef enum _KTHREAD_STATE {
|
||||||
MaximumThreadState
|
MaximumThreadState
|
||||||
} KTHREAD_STATE, *PKTHREAD_STATE;
|
} KTHREAD_STATE, *PKTHREAD_STATE;
|
||||||
|
|
||||||
|
|
||||||
typedef enum _KWAIT_REASON {
|
typedef enum _KWAIT_REASON {
|
||||||
Executive = 0,
|
Executive = 0,
|
||||||
FreePage = 1,
|
FreePage = 1,
|
||||||
|
@ -61,12 +162,16 @@ typedef enum _KWAIT_REASON {
|
||||||
MaximumWaitReason = 37
|
MaximumWaitReason = 37
|
||||||
} KWAIT_REASON, *PKWAIT_REASON;
|
} KWAIT_REASON, *PKWAIT_REASON;
|
||||||
|
|
||||||
typedef struct _CLIENT_ID {
|
|
||||||
|
typedef struct _CLIENT_ID2 {
|
||||||
HANDLE UniqueProcess;
|
HANDLE UniqueProcess;
|
||||||
HANDLE UniqueThread;
|
HANDLE UniqueThread;
|
||||||
} CLIENT_ID, *PCLIENT_ID;
|
} CLIENT_ID2, *PCLIENT_ID2;
|
||||||
|
|
||||||
typedef struct _SYSTEM_THREAD_INFORMATION {
|
#define CLIENT_ID CLIENT_ID2
|
||||||
|
#define PCLIENT_ID PCLIENT_ID2
|
||||||
|
|
||||||
|
typedef struct _SYSTEM_THREAD_INFORMATION2 {
|
||||||
LARGE_INTEGER KernelTime;
|
LARGE_INTEGER KernelTime;
|
||||||
LARGE_INTEGER UserTime;
|
LARGE_INTEGER UserTime;
|
||||||
LARGE_INTEGER CreateTime;
|
LARGE_INTEGER CreateTime;
|
||||||
|
@ -78,10 +183,14 @@ typedef struct _SYSTEM_THREAD_INFORMATION {
|
||||||
ULONG ContextSwitches;
|
ULONG ContextSwitches;
|
||||||
ULONG ThreadState;
|
ULONG ThreadState;
|
||||||
KWAIT_REASON WaitReason;
|
KWAIT_REASON WaitReason;
|
||||||
} SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION;
|
} SYSTEM_THREAD_INFORMATION2, *PSYSTEM_THREAD_INFORMATION2;
|
||||||
|
|
||||||
|
#define SYSTEM_THREAD_INFORMATION SYSTEM_THREAD_INFORMATION2
|
||||||
|
#define PSYSTEM_THREAD_INFORMATION PSYSTEM_THREAD_INFORMATION2
|
||||||
|
|
||||||
typedef struct _TEB *PTEB;
|
typedef struct _TEB *PTEB;
|
||||||
|
|
||||||
|
|
||||||
// private
|
// private
|
||||||
typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION {
|
typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION {
|
||||||
SYSTEM_THREAD_INFORMATION ThreadInfo;
|
SYSTEM_THREAD_INFORMATION ThreadInfo;
|
||||||
|
@ -94,6 +203,7 @@ typedef struct _SYSTEM_EXTENDED_THREAD_INFORMATION {
|
||||||
ULONG_PTR Reserved4;
|
ULONG_PTR Reserved4;
|
||||||
} SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION;
|
} SYSTEM_EXTENDED_THREAD_INFORMATION, *PSYSTEM_EXTENDED_THREAD_INFORMATION;
|
||||||
|
|
||||||
|
|
||||||
typedef struct _SYSTEM_PROCESS_INFORMATION2 {
|
typedef struct _SYSTEM_PROCESS_INFORMATION2 {
|
||||||
ULONG NextEntryOffset;
|
ULONG NextEntryOffset;
|
||||||
ULONG NumberOfThreads;
|
ULONG NumberOfThreads;
|
||||||
|
@ -151,6 +261,7 @@ typedef struct _WINSTATION_INFO {
|
||||||
FILETIME CurrentTime;
|
FILETIME CurrentTime;
|
||||||
} WINSTATION_INFO, *PWINSTATION_INFO;
|
} WINSTATION_INFO, *PWINSTATION_INFO;
|
||||||
|
|
||||||
|
|
||||||
typedef BOOLEAN (WINAPI * PWINSTATIONQUERYINFORMATIONW)
|
typedef BOOLEAN (WINAPI * PWINSTATIONQUERYINFORMATIONW)
|
||||||
(HANDLE,ULONG,WINSTATIONINFOCLASS,PVOID,ULONG,PULONG);
|
(HANDLE,ULONG,WINSTATIONINFOCLASS,PVOID,ULONG,PULONG);
|
||||||
|
|
||||||
|
@ -162,6 +273,7 @@ typedef BOOLEAN (WINAPI * PWINSTATIONQUERYINFORMATIONW)
|
||||||
*/
|
*/
|
||||||
typedef LONG NTSTATUS;
|
typedef LONG NTSTATUS;
|
||||||
|
|
||||||
|
|
||||||
typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
|
typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
|
||||||
HANDLE ProcessHandle,
|
HANDLE ProcessHandle,
|
||||||
DWORD ProcessInformationClass,
|
DWORD ProcessInformationClass,
|
||||||
|
@ -170,6 +282,7 @@ typedef NTSTATUS (NTAPI *_NtQueryInformationProcess)(
|
||||||
PDWORD ReturnLength
|
PDWORD ReturnLength
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
typedef NTSTATUS (NTAPI *_NtSetInformationProcess)(
|
typedef NTSTATUS (NTAPI *_NtSetInformationProcess)(
|
||||||
HANDLE ProcessHandle,
|
HANDLE ProcessHandle,
|
||||||
DWORD ProcessInformationClass,
|
DWORD ProcessInformationClass,
|
||||||
|
@ -186,7 +299,7 @@ typedef enum _PROCESSINFOCLASS2 {
|
||||||
ProcessTimes,
|
ProcessTimes,
|
||||||
ProcessBasePriority,
|
ProcessBasePriority,
|
||||||
ProcessRaisePriority,
|
ProcessRaisePriority,
|
||||||
ProcessDebugPort,
|
_ProcessDebugPort,
|
||||||
ProcessExceptionPort,
|
ProcessExceptionPort,
|
||||||
ProcessAccessToken,
|
ProcessAccessToken,
|
||||||
ProcessLdtInformation,
|
ProcessLdtInformation,
|
||||||
|
@ -207,9 +320,9 @@ typedef enum _PROCESSINFOCLASS2 {
|
||||||
ProcessForegroundInformation,
|
ProcessForegroundInformation,
|
||||||
_ProcessWow64Information,
|
_ProcessWow64Information,
|
||||||
/* added after XP+ */
|
/* added after XP+ */
|
||||||
ProcessImageFileName,
|
_ProcessImageFileName,
|
||||||
ProcessLUIDDeviceMapsEnabled,
|
ProcessLUIDDeviceMapsEnabled,
|
||||||
ProcessBreakOnTermination,
|
_ProcessBreakOnTermination,
|
||||||
ProcessDebugObjectHandle,
|
ProcessDebugObjectHandle,
|
||||||
ProcessDebugFlags,
|
ProcessDebugFlags,
|
||||||
ProcessHandleTracing,
|
ProcessHandleTracing,
|
||||||
|
@ -221,8 +334,12 @@ typedef enum _PROCESSINFOCLASS2 {
|
||||||
MaxProcessInfoClass
|
MaxProcessInfoClass
|
||||||
} PROCESSINFOCLASS2;
|
} PROCESSINFOCLASS2;
|
||||||
|
|
||||||
|
|
||||||
#define PROCESSINFOCLASS PROCESSINFOCLASS2
|
#define PROCESSINFOCLASS PROCESSINFOCLASS2
|
||||||
#define ProcessBasicInformation _ProcessBasicInformation
|
#define ProcessBasicInformation _ProcessBasicInformation
|
||||||
#define ProcessWow64Information _ProcessWow64Information
|
#define ProcessWow64Information _ProcessWow64Information
|
||||||
|
#define ProcessDebugPort _ProcessDebugPort
|
||||||
|
#define ProcessImageFileName _ProcessImageFileName
|
||||||
|
#define ProcessBreakOnTermination _ProcessBreakOnTermination
|
||||||
|
|
||||||
#endif // __NTEXTAPI_H__
|
#endif // __NTEXTAPI_H__
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "process_handles.h"
|
#include "process_handles.h"
|
||||||
|
#include "../../_psutil_common.h"
|
||||||
|
|
||||||
static _NtQuerySystemInformation __NtQuerySystemInformation = NULL;
|
static _NtQuerySystemInformation __NtQuerySystemInformation = NULL;
|
||||||
static _NtQueryObject __NtQueryObject = NULL;
|
static _NtQueryObject __NtQueryObject = NULL;
|
||||||
|
@ -19,18 +20,16 @@ HANDLE g_hThread = NULL;
|
||||||
PUNICODE_STRING g_pNameBuffer = NULL;
|
PUNICODE_STRING g_pNameBuffer = NULL;
|
||||||
ULONG g_dwSize = 0;
|
ULONG g_dwSize = 0;
|
||||||
ULONG g_dwLength = 0;
|
ULONG g_dwLength = 0;
|
||||||
PVOID g_fiber = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
PVOID
|
PVOID
|
||||||
GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName)
|
GetLibraryProcAddress(PSTR LibraryName, PSTR ProcName) {
|
||||||
{
|
|
||||||
return GetProcAddress(GetModuleHandleA(LibraryName), ProcName);
|
return GetProcAddress(GetModuleHandleA(LibraryName), ProcName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
psutil_get_open_files(long dwPid, HANDLE hProcess)
|
psutil_get_open_files(long dwPid, HANDLE hProcess) {
|
||||||
{
|
|
||||||
OSVERSIONINFO osvi;
|
OSVERSIONINFO osvi;
|
||||||
|
|
||||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
||||||
|
@ -44,9 +43,9 @@ psutil_get_open_files(long dwPid, HANDLE hProcess)
|
||||||
return psutil_get_open_files_getmappedfilename(dwPid, hProcess);
|
return psutil_get_open_files_getmappedfilename(dwPid, hProcess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
psutil_get_open_files_init(BOOL threaded)
|
psutil_get_open_files_init(BOOL threaded) {
|
||||||
{
|
|
||||||
if (g_initialized == TRUE)
|
if (g_initialized == TRUE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -65,9 +64,9 @@ psutil_get_open_files_init(BOOL threaded)
|
||||||
g_initialized = TRUE;
|
g_initialized = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess)
|
psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess) {
|
||||||
{
|
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
|
PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
|
||||||
DWORD dwInfoSize = 0x10000;
|
DWORD dwInfoSize = 0x10000;
|
||||||
|
@ -75,9 +74,9 @@ psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess)
|
||||||
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL;
|
PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX hHandle = NULL;
|
||||||
DWORD i = 0;
|
DWORD i = 0;
|
||||||
BOOLEAN error = FALSE;
|
BOOLEAN error = FALSE;
|
||||||
PyObject* pyListFiles = NULL;
|
|
||||||
PyObject* pyFilePath = NULL;
|
|
||||||
DWORD dwWait = 0;
|
DWORD dwWait = 0;
|
||||||
|
PyObject* py_retlist = NULL;
|
||||||
|
PyObject* py_path = NULL;
|
||||||
|
|
||||||
if (g_initialized == FALSE)
|
if (g_initialized == FALSE)
|
||||||
psutil_get_open_files_init(TRUE);
|
psutil_get_open_files_init(TRUE);
|
||||||
|
@ -98,8 +97,8 @@ psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Py_BuildValue raises an exception if NULL is returned
|
// Py_BuildValue raises an exception if NULL is returned
|
||||||
pyListFiles = PyList_New(0);
|
py_retlist = PyList_New(0);
|
||||||
if (pyListFiles == NULL) {
|
if (py_retlist == NULL) {
|
||||||
error = TRUE;
|
error = TRUE;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
@ -139,8 +138,7 @@ psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess)
|
||||||
hHandle = &pHandleInfo->Handles[i];
|
hHandle = &pHandleInfo->Handles[i];
|
||||||
|
|
||||||
// Check if this hHandle belongs to the PID the user specified.
|
// Check if this hHandle belongs to the PID the user specified.
|
||||||
if (hHandle->UniqueProcessId != (HANDLE)dwPid ||
|
if (hHandle->UniqueProcessId != (HANDLE)dwPid)
|
||||||
hHandle->ObjectTypeIndex != HANDLE_TYPE_FILE)
|
|
||||||
goto loop_cleanup;
|
goto loop_cleanup;
|
||||||
|
|
||||||
if (!DuplicateHandle(hProcess,
|
if (!DuplicateHandle(hProcess,
|
||||||
|
@ -208,9 +206,9 @@ psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess)
|
||||||
g_pNameBuffer->Buffer);
|
g_pNameBuffer->Buffer);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pyFilePath = PyUnicode_FromWideChar(g_pNameBuffer->Buffer,
|
py_path = PyUnicode_FromWideChar(g_pNameBuffer->Buffer,
|
||||||
g_pNameBuffer->Length/2);
|
g_pNameBuffer->Length/2);
|
||||||
if (pyFilePath == NULL) {
|
if (py_path == NULL) {
|
||||||
/*
|
/*
|
||||||
printf("[%d] PyUnicode_FromWideChar (%#x): %#x \n",
|
printf("[%d] PyUnicode_FromWideChar (%#x): %#x \n",
|
||||||
dwPid,
|
dwPid,
|
||||||
|
@ -221,7 +219,7 @@ psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess)
|
||||||
goto loop_cleanup;
|
goto loop_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyList_Append(pyListFiles, pyFilePath)) {
|
if (PyList_Append(py_retlist, py_path)) {
|
||||||
/*
|
/*
|
||||||
printf("[%d] PyList_Append (%#x): %#x \n",
|
printf("[%d] PyList_Append (%#x): %#x \n",
|
||||||
dwPid,
|
dwPid,
|
||||||
|
@ -234,8 +232,8 @@ psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess)
|
||||||
}
|
}
|
||||||
|
|
||||||
loop_cleanup:
|
loop_cleanup:
|
||||||
Py_XDECREF(pyFilePath);
|
Py_XDECREF(py_path);
|
||||||
pyFilePath = NULL;
|
py_path = NULL;
|
||||||
|
|
||||||
if (g_pNameBuffer != NULL)
|
if (g_pNameBuffer != NULL)
|
||||||
HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
|
HeapFree(GetProcessHeap(), 0, g_pNameBuffer);
|
||||||
|
@ -264,27 +262,28 @@ cleanup:
|
||||||
pHandleInfo = NULL;
|
pHandleInfo = NULL;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
Py_XDECREF(pyListFiles);
|
Py_XDECREF(py_retlist);
|
||||||
pyListFiles = NULL;
|
py_retlist = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
LeaveCriticalSection(&g_cs);
|
LeaveCriticalSection(&g_cs);
|
||||||
|
|
||||||
return pyListFiles;
|
return py_retlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DWORD
|
DWORD
|
||||||
psutil_NtQueryObject()
|
psutil_NtQueryObject() {
|
||||||
{
|
|
||||||
DWORD dwWait = 0;
|
DWORD dwWait = 0;
|
||||||
|
|
||||||
if (g_hThread == NULL)
|
if (g_hThread == NULL)
|
||||||
g_hThread = CreateThread(NULL,
|
g_hThread = CreateThread(
|
||||||
0,
|
NULL,
|
||||||
(LPTHREAD_START_ROUTINE)psutil_NtQueryObjectThread,
|
0,
|
||||||
NULL,
|
psutil_NtQueryObjectThread,
|
||||||
0,
|
NULL,
|
||||||
NULL);
|
0,
|
||||||
|
NULL);
|
||||||
if (g_hThread == NULL)
|
if (g_hThread == NULL)
|
||||||
return GetLastError();
|
return GetLastError();
|
||||||
|
|
||||||
|
@ -301,24 +300,15 @@ psutil_NtQueryObject()
|
||||||
WaitForSingleObject(g_hThread, INFINITE);
|
WaitForSingleObject(g_hThread, INFINITE);
|
||||||
CloseHandle(g_hThread);
|
CloseHandle(g_hThread);
|
||||||
|
|
||||||
// Cleanup Fiber
|
|
||||||
if (g_fiber != NULL)
|
|
||||||
DeleteFiber(g_fiber);
|
|
||||||
g_fiber = NULL;
|
|
||||||
|
|
||||||
g_hThread = NULL;
|
g_hThread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dwWait;
|
return dwWait;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
psutil_NtQueryObjectThread()
|
|
||||||
{
|
|
||||||
// Prevent the thread stack from leaking when this
|
|
||||||
// thread gets terminated due to NTQueryObject hanging
|
|
||||||
g_fiber = ConvertThreadToFiber(NULL);
|
|
||||||
|
|
||||||
|
DWORD WINAPI
|
||||||
|
psutil_NtQueryObjectThread(LPVOID lpvParam) {
|
||||||
// Loop infinitely waiting for work
|
// Loop infinitely waiting for work
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
WaitForSingleObject(g_hEvtStart, INFINITE);
|
WaitForSingleObject(g_hEvtStart, INFINITE);
|
||||||
|
@ -332,9 +322,9 @@ psutil_NtQueryObjectThread()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess)
|
psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess) {
|
||||||
{
|
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
|
PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
|
||||||
DWORD dwInfoSize = 0x10000;
|
DWORD dwInfoSize = 0x10000;
|
||||||
|
@ -344,8 +334,8 @@ psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess)
|
||||||
HANDLE hMap = NULL;
|
HANDLE hMap = NULL;
|
||||||
DWORD i = 0;
|
DWORD i = 0;
|
||||||
BOOLEAN error = FALSE;
|
BOOLEAN error = FALSE;
|
||||||
PyObject* pyListFiles = NULL;
|
PyObject* py_retlist = NULL;
|
||||||
PyObject* pyFilePath = NULL;
|
PyObject* py_path = NULL;
|
||||||
ULONG dwSize = 0;
|
ULONG dwSize = 0;
|
||||||
LPVOID pMem = NULL;
|
LPVOID pMem = NULL;
|
||||||
TCHAR pszFilename[MAX_PATH+1];
|
TCHAR pszFilename[MAX_PATH+1];
|
||||||
|
@ -360,8 +350,8 @@ psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Py_BuildValue raises an exception if NULL is returned
|
// Py_BuildValue raises an exception if NULL is returned
|
||||||
pyListFiles = PyList_New(0);
|
py_retlist = PyList_New(0);
|
||||||
if (pyListFiles == NULL) {
|
if (py_retlist == NULL) {
|
||||||
error = TRUE;
|
error = TRUE;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
@ -401,8 +391,7 @@ psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess)
|
||||||
hHandle = &pHandleInfo->Handles[i];
|
hHandle = &pHandleInfo->Handles[i];
|
||||||
|
|
||||||
// Check if this hHandle belongs to the PID the user specified.
|
// Check if this hHandle belongs to the PID the user specified.
|
||||||
if (hHandle->UniqueProcessId != (HANDLE)dwPid ||
|
if (hHandle->UniqueProcessId != (HANDLE)dwPid)
|
||||||
hHandle->ObjectTypeIndex != HANDLE_TYPE_FILE)
|
|
||||||
goto loop_cleanup;
|
goto loop_cleanup;
|
||||||
|
|
||||||
if (!DuplicateHandle(hProcess,
|
if (!DuplicateHandle(hProcess,
|
||||||
|
@ -445,7 +434,8 @@ psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess)
|
||||||
goto loop_cleanup;
|
goto loop_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
dwSize = GetMappedFileName(GetCurrentProcess(), pMem, pszFilename, MAX_PATH);
|
dwSize = GetMappedFileName(
|
||||||
|
GetCurrentProcess(), pMem, pszFilename, MAX_PATH);
|
||||||
if (dwSize == 0) {
|
if (dwSize == 0) {
|
||||||
/*
|
/*
|
||||||
printf("[%d] GetMappedFileName (%#x): %#x \n",
|
printf("[%d] GetMappedFileName (%#x): %#x \n",
|
||||||
|
@ -465,8 +455,8 @@ psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess)
|
||||||
pszFilename);
|
pszFilename);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pyFilePath = PyUnicode_FromWideChar(pszFilename, dwSize);
|
py_path = PyUnicode_FromWideChar(pszFilename, dwSize);
|
||||||
if (pyFilePath == NULL) {
|
if (py_path == NULL) {
|
||||||
/*
|
/*
|
||||||
printf("[%d] PyUnicode_FromStringAndSize (%#x): %#x \n",
|
printf("[%d] PyUnicode_FromStringAndSize (%#x): %#x \n",
|
||||||
dwPid,
|
dwPid,
|
||||||
|
@ -477,7 +467,7 @@ psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess)
|
||||||
goto loop_cleanup;
|
goto loop_cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PyList_Append(pyListFiles, pyFilePath)) {
|
if (PyList_Append(py_retlist, py_path)) {
|
||||||
/*
|
/*
|
||||||
printf("[%d] PyList_Append (%#x): %#x \n",
|
printf("[%d] PyList_Append (%#x): %#x \n",
|
||||||
dwPid,
|
dwPid,
|
||||||
|
@ -489,8 +479,8 @@ psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess)
|
||||||
}
|
}
|
||||||
|
|
||||||
loop_cleanup:
|
loop_cleanup:
|
||||||
Py_XDECREF(pyFilePath);
|
Py_XDECREF(py_path);
|
||||||
pyFilePath = NULL;
|
py_path = NULL;
|
||||||
|
|
||||||
if (pMem != NULL)
|
if (pMem != NULL)
|
||||||
UnmapViewOfFile(pMem);
|
UnmapViewOfFile(pMem);
|
||||||
|
@ -525,9 +515,9 @@ cleanup:
|
||||||
pHandleInfo = NULL;
|
pHandleInfo = NULL;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
Py_XDECREF(pyListFiles);
|
Py_XDECREF(py_retlist);
|
||||||
pyListFiles = NULL;
|
py_retlist = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pyListFiles;
|
return py_retlist;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,8 +48,7 @@ typedef NTSTATUS (NTAPI *_NtQueryObject)(
|
||||||
// Undocumented FILE_INFORMATION_CLASS: FileNameInformation
|
// Undocumented FILE_INFORMATION_CLASS: FileNameInformation
|
||||||
static const SYSTEM_INFORMATION_CLASS SystemExtendedHandleInformation = (SYSTEM_INFORMATION_CLASS)64;
|
static const SYSTEM_INFORMATION_CLASS SystemExtendedHandleInformation = (SYSTEM_INFORMATION_CLASS)64;
|
||||||
|
|
||||||
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX
|
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX {
|
||||||
{
|
|
||||||
PVOID Object;
|
PVOID Object;
|
||||||
HANDLE UniqueProcessId;
|
HANDLE UniqueProcessId;
|
||||||
HANDLE HandleValue;
|
HANDLE HandleValue;
|
||||||
|
@ -60,8 +59,7 @@ typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX
|
||||||
ULONG Reserved;
|
ULONG Reserved;
|
||||||
} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX;
|
} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX;
|
||||||
|
|
||||||
typedef struct _SYSTEM_HANDLE_INFORMATION_EX
|
typedef struct _SYSTEM_HANDLE_INFORMATION_EX {
|
||||||
{
|
|
||||||
ULONG_PTR NumberOfHandles;
|
ULONG_PTR NumberOfHandles;
|
||||||
ULONG_PTR Reserved;
|
ULONG_PTR Reserved;
|
||||||
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
|
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
|
||||||
|
@ -108,6 +106,6 @@ PyObject* psutil_get_open_files(long pid, HANDLE processHandle);
|
||||||
PyObject* psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess);
|
PyObject* psutil_get_open_files_ntqueryobject(long dwPid, HANDLE hProcess);
|
||||||
PyObject* psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess);
|
PyObject* psutil_get_open_files_getmappedfilename(long dwPid, HANDLE hProcess);
|
||||||
DWORD psutil_NtQueryObject(void);
|
DWORD psutil_NtQueryObject(void);
|
||||||
void psutil_NtQueryObjectThread(void);
|
DWORD WINAPI psutil_NtQueryObjectThread(LPVOID lpvParam);
|
||||||
|
|
||||||
#endif // __PROCESS_HANDLES_H__
|
#endif // __PROCESS_HANDLES_H__
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -12,15 +12,23 @@
|
||||||
#include "security.h"
|
#include "security.h"
|
||||||
#include "ntextapi.h"
|
#include "ntextapi.h"
|
||||||
|
|
||||||
|
#define HANDLE_TO_PYNUM(handle) PyLong_FromUnsignedLong((unsigned long) handle)
|
||||||
|
#define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLong(obj))
|
||||||
|
|
||||||
|
|
||||||
DWORD* psutil_get_pids(DWORD *numberOfReturnedPIDs);
|
DWORD* psutil_get_pids(DWORD *numberOfReturnedPIDs);
|
||||||
HANDLE psutil_handle_from_pid(DWORD pid);
|
HANDLE psutil_handle_from_pid(DWORD pid);
|
||||||
HANDLE psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess);
|
HANDLE psutil_handle_from_pid_waccess(DWORD pid, DWORD dwDesiredAccess);
|
||||||
int psutil_handlep_is_running(HANDLE hProcess);
|
|
||||||
int psutil_pid_in_proclist(DWORD pid);
|
|
||||||
int psutil_pid_is_running(DWORD pid);
|
int psutil_pid_is_running(DWORD pid);
|
||||||
PVOID psutil_get_peb_address(HANDLE ProcessHandle);
|
|
||||||
PyObject* psutil_get_arg_list(long pid);
|
|
||||||
int psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess,
|
int psutil_get_proc_info(DWORD pid, PSYSTEM_PROCESS_INFORMATION *retProcess,
|
||||||
PVOID *retBuffer);
|
PVOID *retBuffer);
|
||||||
|
|
||||||
|
int psutil_assert_pid_exists(DWORD pid, char *err);
|
||||||
|
int psutil_assert_pid_not_exists(DWORD pid, char *err);
|
||||||
|
|
||||||
|
|
||||||
|
PyObject* psutil_get_cmdline(long pid);
|
||||||
|
PyObject* psutil_get_cwd(long pid);
|
||||||
|
PyObject* psutil_get_environ(long pid);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -108,8 +108,7 @@ psutil_has_system_privilege(HANDLE hProcess) {
|
||||||
|
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege)
|
psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege) {
|
||||||
{
|
|
||||||
TOKEN_PRIVILEGES tp;
|
TOKEN_PRIVILEGES tp;
|
||||||
LUID luid;
|
LUID luid;
|
||||||
TOKEN_PRIVILEGES tpPrevious;
|
TOKEN_PRIVILEGES tpPrevious;
|
||||||
|
@ -159,8 +158,7 @@ psutil_set_privilege(HANDLE hToken, LPCTSTR Privilege, BOOL bEnablePrivilege)
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
psutil_set_se_debug()
|
psutil_set_se_debug() {
|
||||||
{
|
|
||||||
HANDLE hToken;
|
HANDLE hToken;
|
||||||
if (! OpenThreadToken(GetCurrentThread(),
|
if (! OpenThreadToken(GetCurrentThread(),
|
||||||
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
||||||
|
@ -198,8 +196,7 @@ psutil_set_se_debug()
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
psutil_unset_se_debug()
|
psutil_unset_se_debug() {
|
||||||
{
|
|
||||||
HANDLE hToken;
|
HANDLE hToken;
|
||||||
if (! OpenThreadToken(GetCurrentThread(),
|
if (! OpenThreadToken(GetCurrentThread(),
|
||||||
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
||||||
|
|
|
@ -0,0 +1,485 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <Winsvc.h>
|
||||||
|
|
||||||
|
#include "services.h"
|
||||||
|
#include "../../_psutil_common.h"
|
||||||
|
|
||||||
|
// ==================================================================
|
||||||
|
// utils
|
||||||
|
// ==================================================================
|
||||||
|
|
||||||
|
SC_HANDLE
|
||||||
|
psutil_get_service_handler(char *service_name, DWORD scm_access, DWORD access)
|
||||||
|
{
|
||||||
|
ENUM_SERVICE_STATUS_PROCESSW *lpService = NULL;
|
||||||
|
SC_HANDLE sc = NULL;
|
||||||
|
SC_HANDLE hService = NULL;
|
||||||
|
|
||||||
|
sc = OpenSCManager(NULL, NULL, scm_access);
|
||||||
|
if (sc == NULL) {
|
||||||
|
PyErr_SetFromWindowsErr(0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
hService = OpenService(sc, service_name, access);
|
||||||
|
if (hService == NULL) {
|
||||||
|
CloseServiceHandle(sc);
|
||||||
|
PyErr_SetFromWindowsErr(0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
CloseServiceHandle(sc);
|
||||||
|
return hService;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// XXX - expose these as constants?
|
||||||
|
static const char *
|
||||||
|
get_startup_string(DWORD startup) {
|
||||||
|
switch (startup) {
|
||||||
|
case SERVICE_AUTO_START:
|
||||||
|
return "automatic";
|
||||||
|
case SERVICE_DEMAND_START:
|
||||||
|
return "manual";
|
||||||
|
case SERVICE_DISABLED:
|
||||||
|
return "disabled";
|
||||||
|
/*
|
||||||
|
// drivers only (since we use EnumServicesStatusEx() with
|
||||||
|
// SERVICE_WIN32)
|
||||||
|
case SERVICE_BOOT_START:
|
||||||
|
return "boot-start";
|
||||||
|
case SERVICE_SYSTEM_START:
|
||||||
|
return "system-start";
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// XXX - expose these as constants?
|
||||||
|
static const char *
|
||||||
|
get_state_string(DWORD state) {
|
||||||
|
switch (state) {
|
||||||
|
case SERVICE_RUNNING:
|
||||||
|
return "running";
|
||||||
|
case SERVICE_PAUSED:
|
||||||
|
return "paused";
|
||||||
|
case SERVICE_START_PENDING:
|
||||||
|
return "start_pending";
|
||||||
|
case SERVICE_PAUSE_PENDING:
|
||||||
|
return "pause_pending";
|
||||||
|
case SERVICE_CONTINUE_PENDING:
|
||||||
|
return "continue_pending";
|
||||||
|
case SERVICE_STOP_PENDING:
|
||||||
|
return "stop_pending";
|
||||||
|
case SERVICE_STOPPED:
|
||||||
|
return "stopped";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ==================================================================
|
||||||
|
// APIs
|
||||||
|
// ==================================================================
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enumerate all services.
|
||||||
|
*/
|
||||||
|
PyObject *
|
||||||
|
psutil_winservice_enumerate(PyObject *self, PyObject *args) {
|
||||||
|
ENUM_SERVICE_STATUS_PROCESSW *lpService = NULL;
|
||||||
|
BOOL ok;
|
||||||
|
SC_HANDLE sc = NULL;
|
||||||
|
DWORD bytesNeeded = 0;
|
||||||
|
DWORD srvCount;
|
||||||
|
DWORD resumeHandle = 0;
|
||||||
|
DWORD dwBytes = 0;
|
||||||
|
DWORD i;
|
||||||
|
PyObject *py_retlist = PyList_New(0);
|
||||||
|
PyObject *py_tuple = NULL;
|
||||||
|
PyObject *py_name = NULL;
|
||||||
|
PyObject *py_display_name = NULL;
|
||||||
|
|
||||||
|
if (py_retlist == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
sc = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
|
||||||
|
if (sc == NULL) {
|
||||||
|
PyErr_SetFromWindowsErr(0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
ok = EnumServicesStatusExW(
|
||||||
|
sc,
|
||||||
|
SC_ENUM_PROCESS_INFO,
|
||||||
|
SERVICE_WIN32, // XXX - extend this to include drivers etc.?
|
||||||
|
SERVICE_STATE_ALL,
|
||||||
|
(LPBYTE)lpService,
|
||||||
|
dwBytes,
|
||||||
|
&bytesNeeded,
|
||||||
|
&srvCount,
|
||||||
|
&resumeHandle,
|
||||||
|
NULL);
|
||||||
|
if (ok || (GetLastError() != ERROR_MORE_DATA))
|
||||||
|
break;
|
||||||
|
if (lpService)
|
||||||
|
free(lpService);
|
||||||
|
dwBytes = bytesNeeded;
|
||||||
|
lpService = (ENUM_SERVICE_STATUS_PROCESSW*)malloc(dwBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < srvCount; i++) {
|
||||||
|
// Get unicode name / display name.
|
||||||
|
py_name = NULL;
|
||||||
|
py_name = PyUnicode_FromWideChar(
|
||||||
|
lpService[i].lpServiceName, wcslen(lpService[i].lpServiceName));
|
||||||
|
if (py_name == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
py_display_name = NULL;
|
||||||
|
py_display_name = PyUnicode_FromWideChar(
|
||||||
|
lpService[i].lpDisplayName, wcslen(lpService[i].lpDisplayName));
|
||||||
|
if (py_display_name == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// Construct the result.
|
||||||
|
py_tuple = Py_BuildValue("(OO)", py_name, py_display_name);
|
||||||
|
if (py_tuple == NULL)
|
||||||
|
goto error;
|
||||||
|
if (PyList_Append(py_retlist, py_tuple))
|
||||||
|
goto error;
|
||||||
|
Py_DECREF(py_display_name);
|
||||||
|
Py_DECREF(py_name);
|
||||||
|
Py_DECREF(py_tuple);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free resources.
|
||||||
|
CloseServiceHandle(sc);
|
||||||
|
free(lpService);
|
||||||
|
return py_retlist;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_DECREF(py_name);
|
||||||
|
Py_XDECREF(py_display_name);
|
||||||
|
Py_XDECREF(py_tuple);
|
||||||
|
Py_DECREF(py_retlist);
|
||||||
|
if (sc != NULL)
|
||||||
|
CloseServiceHandle(sc);
|
||||||
|
if (lpService != NULL)
|
||||||
|
free(lpService);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get service config information. Returns:
|
||||||
|
* - display_name
|
||||||
|
* - binpath
|
||||||
|
* - username
|
||||||
|
* - startup_type
|
||||||
|
*/
|
||||||
|
PyObject *
|
||||||
|
psutil_winservice_query_config(PyObject *self, PyObject *args) {
|
||||||
|
char *service_name;
|
||||||
|
SC_HANDLE hService = NULL;
|
||||||
|
BOOL ok;
|
||||||
|
DWORD bytesNeeded = 0;
|
||||||
|
DWORD resumeHandle = 0;
|
||||||
|
DWORD dwBytes = 0;
|
||||||
|
QUERY_SERVICE_CONFIGW *qsc = NULL;
|
||||||
|
PyObject *py_tuple = NULL;
|
||||||
|
PyObject *py_unicode_display_name = NULL;
|
||||||
|
PyObject *py_unicode_binpath = NULL;
|
||||||
|
PyObject *py_unicode_username = NULL;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &service_name))
|
||||||
|
return NULL;
|
||||||
|
hService = psutil_get_service_handler(
|
||||||
|
service_name, SC_MANAGER_ENUMERATE_SERVICE, SERVICE_QUERY_CONFIG);
|
||||||
|
if (hService == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// First call to QueryServiceConfigW() is necessary to get the
|
||||||
|
// right size.
|
||||||
|
bytesNeeded = 0;
|
||||||
|
QueryServiceConfigW(hService, NULL, 0, &bytesNeeded);
|
||||||
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||||
|
PyErr_SetFromWindowsErr(0);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
qsc = (QUERY_SERVICE_CONFIGW *)malloc(bytesNeeded);
|
||||||
|
ok = QueryServiceConfigW(hService, qsc, bytesNeeded, &bytesNeeded);
|
||||||
|
if (ok == 0) {
|
||||||
|
PyErr_SetFromWindowsErr(0);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get unicode display name.
|
||||||
|
py_unicode_display_name = PyUnicode_FromWideChar(
|
||||||
|
qsc->lpDisplayName, wcslen(qsc->lpDisplayName));
|
||||||
|
if (py_unicode_display_name == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// Get unicode bin path.
|
||||||
|
py_unicode_binpath = PyUnicode_FromWideChar(
|
||||||
|
qsc->lpBinaryPathName, wcslen(qsc->lpBinaryPathName));
|
||||||
|
if (py_unicode_binpath == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// Get unicode username.
|
||||||
|
py_unicode_username = PyUnicode_FromWideChar(
|
||||||
|
qsc->lpServiceStartName, wcslen(qsc->lpServiceStartName));
|
||||||
|
if (py_unicode_username == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// Construct result tuple.
|
||||||
|
py_tuple = Py_BuildValue(
|
||||||
|
"(OOOs)",
|
||||||
|
py_unicode_display_name,
|
||||||
|
py_unicode_binpath,
|
||||||
|
py_unicode_username,
|
||||||
|
get_startup_string(qsc->dwStartType) // startup
|
||||||
|
);
|
||||||
|
if (py_tuple == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// Free resources.
|
||||||
|
Py_DECREF(py_unicode_display_name);
|
||||||
|
Py_DECREF(py_unicode_binpath);
|
||||||
|
Py_DECREF(py_unicode_username);
|
||||||
|
free(qsc);
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
return py_tuple;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_unicode_display_name);
|
||||||
|
Py_XDECREF(py_unicode_binpath);
|
||||||
|
Py_XDECREF(py_unicode_username);
|
||||||
|
Py_XDECREF(py_tuple);
|
||||||
|
if (hService != NULL)
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
if (qsc != NULL)
|
||||||
|
free(qsc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get service status information. Returns:
|
||||||
|
* - status
|
||||||
|
* - pid
|
||||||
|
*/
|
||||||
|
PyObject *
|
||||||
|
psutil_winservice_query_status(PyObject *self, PyObject *args) {
|
||||||
|
char *service_name;
|
||||||
|
SC_HANDLE hService = NULL;
|
||||||
|
BOOL ok;
|
||||||
|
DWORD bytesNeeded = 0;
|
||||||
|
DWORD resumeHandle = 0;
|
||||||
|
DWORD dwBytes = 0;
|
||||||
|
SERVICE_STATUS_PROCESS *ssp = NULL;
|
||||||
|
PyObject *py_tuple = NULL;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &service_name))
|
||||||
|
return NULL;
|
||||||
|
hService = psutil_get_service_handler(
|
||||||
|
service_name, SC_MANAGER_ENUMERATE_SERVICE, SERVICE_QUERY_STATUS);
|
||||||
|
if (hService == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// First call to QueryServiceStatusEx() is necessary to get the
|
||||||
|
// right size.
|
||||||
|
QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, NULL, 0,
|
||||||
|
&bytesNeeded);
|
||||||
|
if (GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
|
||||||
|
// Also services.msc fails in the same manner, so we return an
|
||||||
|
// empty string.
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
return Py_BuildValue("s", "");
|
||||||
|
}
|
||||||
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||||
|
PyErr_SetFromWindowsErr(0);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ssp = (SERVICE_STATUS_PROCESS *)HeapAlloc(
|
||||||
|
GetProcessHeap(), 0, bytesNeeded);
|
||||||
|
if (ssp == NULL) {
|
||||||
|
PyErr_NoMemory();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actual call.
|
||||||
|
ok = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)ssp,
|
||||||
|
bytesNeeded, &bytesNeeded);
|
||||||
|
if (ok == 0) {
|
||||||
|
PyErr_SetFromWindowsErr(0);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
py_tuple = Py_BuildValue(
|
||||||
|
"(sk)",
|
||||||
|
get_state_string(ssp->dwCurrentState),
|
||||||
|
ssp->dwProcessId
|
||||||
|
);
|
||||||
|
if (py_tuple == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
HeapFree(GetProcessHeap(), 0, ssp);
|
||||||
|
return py_tuple;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(py_tuple);
|
||||||
|
if (hService != NULL)
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
if (ssp != NULL)
|
||||||
|
HeapFree(GetProcessHeap(), 0, ssp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get service description.
|
||||||
|
*/
|
||||||
|
PyObject *
|
||||||
|
psutil_winservice_query_descr(PyObject *self, PyObject *args) {
|
||||||
|
ENUM_SERVICE_STATUS_PROCESSW *lpService = NULL;
|
||||||
|
BOOL ok;
|
||||||
|
DWORD bytesNeeded = 0;
|
||||||
|
DWORD resumeHandle = 0;
|
||||||
|
DWORD dwBytes = 0;
|
||||||
|
SC_HANDLE hService = NULL;
|
||||||
|
SERVICE_DESCRIPTIONW *scd = NULL;
|
||||||
|
char *service_name;
|
||||||
|
PyObject *py_retstr = NULL;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &service_name))
|
||||||
|
return NULL;
|
||||||
|
hService = psutil_get_service_handler(
|
||||||
|
service_name, SC_MANAGER_ENUMERATE_SERVICE, SERVICE_QUERY_CONFIG);
|
||||||
|
if (hService == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// This first call to QueryServiceConfig2W() is necessary in order
|
||||||
|
// to get the right size.
|
||||||
|
bytesNeeded = 0;
|
||||||
|
QueryServiceConfig2W(hService, SERVICE_CONFIG_DESCRIPTION, NULL, 0,
|
||||||
|
&bytesNeeded);
|
||||||
|
if (GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
|
||||||
|
// Also services.msc fails in the same manner, so we return an
|
||||||
|
// empty string.
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
return Py_BuildValue("s", "");
|
||||||
|
}
|
||||||
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||||
|
PyErr_SetFromWindowsErr(0);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
scd = (SERVICE_DESCRIPTIONW *)malloc(bytesNeeded);
|
||||||
|
ok = QueryServiceConfig2W(hService, SERVICE_CONFIG_DESCRIPTION,
|
||||||
|
(LPBYTE)scd, bytesNeeded, &bytesNeeded);
|
||||||
|
if (ok == 0) {
|
||||||
|
PyErr_SetFromWindowsErr(0);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scd->lpDescription == NULL) {
|
||||||
|
py_retstr = Py_BuildValue("s", "");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
py_retstr = PyUnicode_FromWideChar(
|
||||||
|
scd->lpDescription, wcslen(scd->lpDescription));
|
||||||
|
}
|
||||||
|
if (!py_retstr)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
free(scd);
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
return py_retstr;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (hService != NULL)
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
if (lpService != NULL)
|
||||||
|
free(lpService);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start service.
|
||||||
|
* XXX - note: this is exposed but not used.
|
||||||
|
*/
|
||||||
|
PyObject *
|
||||||
|
psutil_winservice_start(PyObject *self, PyObject *args) {
|
||||||
|
char *service_name;
|
||||||
|
BOOL ok;
|
||||||
|
SC_HANDLE hService = NULL;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &service_name))
|
||||||
|
return NULL;
|
||||||
|
hService = psutil_get_service_handler(
|
||||||
|
service_name, SC_MANAGER_ALL_ACCESS, SERVICE_START);
|
||||||
|
if (hService == NULL) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ok = StartService(hService, 0, NULL);
|
||||||
|
if (ok == 0) {
|
||||||
|
PyErr_SetFromWindowsErr(0);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (hService != NULL)
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Stop service.
|
||||||
|
* XXX - note: this is exposed but not used.
|
||||||
|
*/
|
||||||
|
PyObject *
|
||||||
|
psutil_winservice_stop(PyObject *self, PyObject *args) {
|
||||||
|
char *service_name;
|
||||||
|
BOOL ok;
|
||||||
|
SC_HANDLE hService = NULL;
|
||||||
|
SERVICE_STATUS ssp;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "s", &service_name))
|
||||||
|
return NULL;
|
||||||
|
hService = psutil_get_service_handler(
|
||||||
|
service_name, SC_MANAGER_ALL_ACCESS, SERVICE_STOP);
|
||||||
|
if (hService == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
// Note: this can hang for 30 secs.
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
ok = ControlService(hService, SERVICE_CONTROL_STOP, &ssp);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
if (ok == 0) {
|
||||||
|
PyErr_SetFromWindowsErr(0);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
Py_RETURN_NONE;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (hService != NULL)
|
||||||
|
CloseServiceHandle(hService);
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||||
|
* Use of this source code is governed by a BSD-style license that can be
|
||||||
|
* found in the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
#include <Winsvc.h>
|
||||||
|
|
||||||
|
SC_HANDLE psutil_get_service_handle(
|
||||||
|
char service_name, DWORD scm_access, DWORD access);
|
||||||
|
PyObject *psutil_winservice_enumerate(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_winservice_query_config(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_winservice_query_status(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_winservice_query_descr(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_winservice_start(PyObject *self, PyObject *args);
|
||||||
|
PyObject *psutil_winservice_stop(PyObject *self, PyObject *args);
|
|
@ -0,0 +1,23 @@
|
||||||
|
Instructions for running tests
|
||||||
|
==============================
|
||||||
|
|
||||||
|
* There are two ways of running tests. As a "user", if psutil is already
|
||||||
|
installed and you just want to test it works::
|
||||||
|
|
||||||
|
python -m psutil.tests --install-deps # install test deps
|
||||||
|
python -m psutil.tests
|
||||||
|
|
||||||
|
As a "developer", if you have a copy of the source code and you whish to hack
|
||||||
|
on psutil::
|
||||||
|
|
||||||
|
make setup-dev-env # install test deps (+ other things)
|
||||||
|
make test
|
||||||
|
|
||||||
|
* To run tests on all supported Python versions install tox
|
||||||
|
(``pip install tox``) then run ``tox`` from within psutil root directory.
|
||||||
|
|
||||||
|
* Every time a commit is pushed tests are automatically run on Travis
|
||||||
|
(Linux, OSX) and appveyor (Windows):
|
||||||
|
|
||||||
|
* Travis builds: https://travis-ci.org/giampaolo/psutil
|
||||||
|
* AppVeyor builds: https://ci.appveyor.com/project/giampaolo/psutil
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,96 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
|
# found in the LICENSE file.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Run unit tests. This is invoked by:
|
||||||
|
|
||||||
|
$ python -m psutil.tests
|
||||||
|
"""
|
||||||
|
|
||||||
|
import contextlib
|
||||||
|
import optparse
|
||||||
|
import os
|
||||||
|
import ssl
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
try:
|
||||||
|
from urllib.request import urlopen # py3
|
||||||
|
except ImportError:
|
||||||
|
from urllib2 import urlopen
|
||||||
|
|
||||||
|
from psutil.tests import PYTHON_EXE
|
||||||
|
from psutil.tests import run_suite
|
||||||
|
|
||||||
|
|
||||||
|
HERE = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py"
|
||||||
|
TEST_DEPS = []
|
||||||
|
if sys.version_info[:2] == (2, 6):
|
||||||
|
TEST_DEPS.extend(["ipaddress", "unittest2", "argparse", "mock==1.0.1"])
|
||||||
|
elif sys.version_info[:2] == (2, 7) or sys.version_info[:2] <= (3, 2):
|
||||||
|
TEST_DEPS.extend(["ipaddress", "mock"])
|
||||||
|
elif sys.version_info[:2] == (3, 3):
|
||||||
|
TEST_DEPS.extend(["ipaddress"])
|
||||||
|
|
||||||
|
|
||||||
|
def install_pip():
|
||||||
|
try:
|
||||||
|
import pip # NOQA
|
||||||
|
except ImportError:
|
||||||
|
f = tempfile.NamedTemporaryFile(suffix='.py')
|
||||||
|
with contextlib.closing(f):
|
||||||
|
print("downloading %s to %s" % (GET_PIP_URL, f.name))
|
||||||
|
if hasattr(ssl, '_create_unverified_context'):
|
||||||
|
ctx = ssl._create_unverified_context()
|
||||||
|
else:
|
||||||
|
ctx = None
|
||||||
|
kwargs = dict(context=ctx) if ctx else {}
|
||||||
|
req = urlopen(GET_PIP_URL, **kwargs)
|
||||||
|
data = req.read()
|
||||||
|
f.write(data)
|
||||||
|
f.flush()
|
||||||
|
|
||||||
|
print("installing pip")
|
||||||
|
code = os.system('%s %s --user' % (PYTHON_EXE, f.name))
|
||||||
|
return code
|
||||||
|
|
||||||
|
|
||||||
|
def install_test_deps(deps=None):
|
||||||
|
"""Install test dependencies via pip."""
|
||||||
|
if deps is None:
|
||||||
|
deps = TEST_DEPS
|
||||||
|
deps = set(deps)
|
||||||
|
if deps:
|
||||||
|
is_venv = hasattr(sys, 'real_prefix')
|
||||||
|
opts = "--user" if not is_venv else ""
|
||||||
|
install_pip()
|
||||||
|
code = os.system('%s -m pip install %s --upgrade %s' % (
|
||||||
|
PYTHON_EXE, opts, " ".join(deps)))
|
||||||
|
return code
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
usage = "%s -m psutil.tests [opts]" % PYTHON_EXE
|
||||||
|
parser = optparse.OptionParser(usage=usage, description="run unit tests")
|
||||||
|
parser.add_option("-i", "--install-deps",
|
||||||
|
action="store_true", default=False,
|
||||||
|
help="don't print status messages to stdout")
|
||||||
|
|
||||||
|
opts, args = parser.parse_args()
|
||||||
|
if opts.install_deps:
|
||||||
|
install_pip()
|
||||||
|
install_test_deps()
|
||||||
|
else:
|
||||||
|
for dep in TEST_DEPS:
|
||||||
|
try:
|
||||||
|
__import__(dep.split("==")[0])
|
||||||
|
except ImportError:
|
||||||
|
sys.exit("%r lib is not installed; run %s -m psutil.tests "
|
||||||
|
"--install-deps" % (dep, PYTHON_EXE))
|
||||||
|
run_suite()
|
||||||
|
|
||||||
|
|
||||||
|
main()
|
|
@ -0,0 +1,489 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
|
# found in the LICENSE file.
|
||||||
|
|
||||||
|
# TODO: (FreeBSD) add test for comparing connections with 'sockstat' cmd.
|
||||||
|
|
||||||
|
|
||||||
|
"""Tests specific to all BSD platforms."""
|
||||||
|
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
|
import psutil
|
||||||
|
from psutil import BSD
|
||||||
|
from psutil import FREEBSD
|
||||||
|
from psutil import NETBSD
|
||||||
|
from psutil import OPENBSD
|
||||||
|
from psutil.tests import get_test_subprocess
|
||||||
|
from psutil.tests import HAS_BATTERY
|
||||||
|
from psutil.tests import MEMORY_TOLERANCE
|
||||||
|
from psutil.tests import reap_children
|
||||||
|
from psutil.tests import retry_before_failing
|
||||||
|
from psutil.tests import run_test_module_by_name
|
||||||
|
from psutil.tests import sh
|
||||||
|
from psutil.tests import unittest
|
||||||
|
from psutil.tests import which
|
||||||
|
|
||||||
|
|
||||||
|
if BSD:
|
||||||
|
PAGESIZE = os.sysconf("SC_PAGE_SIZE")
|
||||||
|
if os.getuid() == 0: # muse requires root privileges
|
||||||
|
MUSE_AVAILABLE = which('muse')
|
||||||
|
else:
|
||||||
|
MUSE_AVAILABLE = False
|
||||||
|
else:
|
||||||
|
MUSE_AVAILABLE = False
|
||||||
|
|
||||||
|
|
||||||
|
def sysctl(cmdline):
|
||||||
|
"""Expects a sysctl command with an argument and parse the result
|
||||||
|
returning only the value of interest.
|
||||||
|
"""
|
||||||
|
result = sh("sysctl " + cmdline)
|
||||||
|
if FREEBSD:
|
||||||
|
result = result[result.find(": ") + 2:]
|
||||||
|
elif OPENBSD or NETBSD:
|
||||||
|
result = result[result.find("=") + 1:]
|
||||||
|
try:
|
||||||
|
return int(result)
|
||||||
|
except ValueError:
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def muse(field):
|
||||||
|
"""Thin wrapper around 'muse' cmdline utility."""
|
||||||
|
out = sh('muse')
|
||||||
|
for line in out.split('\n'):
|
||||||
|
if line.startswith(field):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ValueError("line not found")
|
||||||
|
return int(line.split()[1])
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- All BSD*
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(not BSD, "BSD only")
|
||||||
|
class BSDSpecificTestCase(unittest.TestCase):
|
||||||
|
"""Generic tests common to all BSD variants."""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
cls.pid = get_test_subprocess().pid
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
reap_children()
|
||||||
|
|
||||||
|
@unittest.skipIf(NETBSD, "-o lstart doesn't work on NETBSD")
|
||||||
|
def test_process_create_time(self):
|
||||||
|
output = sh("ps -o lstart -p %s" % self.pid)
|
||||||
|
start_ps = output.replace('STARTED', '').strip()
|
||||||
|
start_psutil = psutil.Process(self.pid).create_time()
|
||||||
|
start_psutil = time.strftime("%a %b %e %H:%M:%S %Y",
|
||||||
|
time.localtime(start_psutil))
|
||||||
|
self.assertEqual(start_ps, start_psutil)
|
||||||
|
|
||||||
|
def test_disks(self):
|
||||||
|
# test psutil.disk_usage() and psutil.disk_partitions()
|
||||||
|
# against "df -a"
|
||||||
|
def df(path):
|
||||||
|
out = sh('df -k "%s"' % path).strip()
|
||||||
|
lines = out.split('\n')
|
||||||
|
lines.pop(0)
|
||||||
|
line = lines.pop(0)
|
||||||
|
dev, total, used, free = line.split()[:4]
|
||||||
|
if dev == 'none':
|
||||||
|
dev = ''
|
||||||
|
total = int(total) * 1024
|
||||||
|
used = int(used) * 1024
|
||||||
|
free = int(free) * 1024
|
||||||
|
return dev, total, used, free
|
||||||
|
|
||||||
|
for part in psutil.disk_partitions(all=False):
|
||||||
|
usage = psutil.disk_usage(part.mountpoint)
|
||||||
|
dev, total, used, free = df(part.mountpoint)
|
||||||
|
self.assertEqual(part.device, dev)
|
||||||
|
self.assertEqual(usage.total, total)
|
||||||
|
# 10 MB tollerance
|
||||||
|
if abs(usage.free - free) > 10 * 1024 * 1024:
|
||||||
|
self.fail("psutil=%s, df=%s" % (usage.free, free))
|
||||||
|
if abs(usage.used - used) > 10 * 1024 * 1024:
|
||||||
|
self.fail("psutil=%s, df=%s" % (usage.used, used))
|
||||||
|
|
||||||
|
@unittest.skipIf(not which('sysctl'), "sysctl cmd not available")
|
||||||
|
def test_cpu_count_logical(self):
|
||||||
|
syst = sysctl("hw.ncpu")
|
||||||
|
self.assertEqual(psutil.cpu_count(logical=True), syst)
|
||||||
|
|
||||||
|
@unittest.skipIf(not which('sysctl'), "sysctl cmd not available")
|
||||||
|
def test_virtual_memory_total(self):
|
||||||
|
num = sysctl('hw.physmem')
|
||||||
|
self.assertEqual(num, psutil.virtual_memory().total)
|
||||||
|
|
||||||
|
def test_net_if_stats(self):
|
||||||
|
for name, stats in psutil.net_if_stats().items():
|
||||||
|
try:
|
||||||
|
out = sh("ifconfig %s" % name)
|
||||||
|
except RuntimeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.assertEqual(stats.isup, 'RUNNING' in out, msg=out)
|
||||||
|
if "mtu" in out:
|
||||||
|
self.assertEqual(stats.mtu,
|
||||||
|
int(re.findall(r'mtu (\d+)', out)[0]))
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- FreeBSD
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(not FREEBSD, "FREEBSD only")
|
||||||
|
class FreeBSDSpecificTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
cls.pid = get_test_subprocess().pid
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
reap_children()
|
||||||
|
|
||||||
|
@retry_before_failing()
|
||||||
|
def test_proc_memory_maps(self):
|
||||||
|
out = sh('procstat -v %s' % self.pid)
|
||||||
|
maps = psutil.Process(self.pid).memory_maps(grouped=False)
|
||||||
|
lines = out.split('\n')[1:]
|
||||||
|
while lines:
|
||||||
|
line = lines.pop()
|
||||||
|
fields = line.split()
|
||||||
|
_, start, stop, perms, res = fields[:5]
|
||||||
|
map = maps.pop()
|
||||||
|
self.assertEqual("%s-%s" % (start, stop), map.addr)
|
||||||
|
self.assertEqual(int(res), map.rss)
|
||||||
|
if not map.path.startswith('['):
|
||||||
|
self.assertEqual(fields[10], map.path)
|
||||||
|
|
||||||
|
def test_proc_exe(self):
|
||||||
|
out = sh('procstat -b %s' % self.pid)
|
||||||
|
self.assertEqual(psutil.Process(self.pid).exe(),
|
||||||
|
out.split('\n')[1].split()[-1])
|
||||||
|
|
||||||
|
def test_proc_cmdline(self):
|
||||||
|
out = sh('procstat -c %s' % self.pid)
|
||||||
|
self.assertEqual(' '.join(psutil.Process(self.pid).cmdline()),
|
||||||
|
' '.join(out.split('\n')[1].split()[2:]))
|
||||||
|
|
||||||
|
def test_proc_uids_gids(self):
|
||||||
|
out = sh('procstat -s %s' % self.pid)
|
||||||
|
euid, ruid, suid, egid, rgid, sgid = out.split('\n')[1].split()[2:8]
|
||||||
|
p = psutil.Process(self.pid)
|
||||||
|
uids = p.uids()
|
||||||
|
gids = p.gids()
|
||||||
|
self.assertEqual(uids.real, int(ruid))
|
||||||
|
self.assertEqual(uids.effective, int(euid))
|
||||||
|
self.assertEqual(uids.saved, int(suid))
|
||||||
|
self.assertEqual(gids.real, int(rgid))
|
||||||
|
self.assertEqual(gids.effective, int(egid))
|
||||||
|
self.assertEqual(gids.saved, int(sgid))
|
||||||
|
|
||||||
|
@retry_before_failing()
|
||||||
|
def test_proc_ctx_switches(self):
|
||||||
|
tested = []
|
||||||
|
out = sh('procstat -r %s' % self.pid)
|
||||||
|
p = psutil.Process(self.pid)
|
||||||
|
for line in out.split('\n'):
|
||||||
|
line = line.lower().strip()
|
||||||
|
if ' voluntary context' in line:
|
||||||
|
pstat_value = int(line.split()[-1])
|
||||||
|
psutil_value = p.num_ctx_switches().voluntary
|
||||||
|
self.assertEqual(pstat_value, psutil_value)
|
||||||
|
tested.append(None)
|
||||||
|
elif ' involuntary context' in line:
|
||||||
|
pstat_value = int(line.split()[-1])
|
||||||
|
psutil_value = p.num_ctx_switches().involuntary
|
||||||
|
self.assertEqual(pstat_value, psutil_value)
|
||||||
|
tested.append(None)
|
||||||
|
if len(tested) != 2:
|
||||||
|
raise RuntimeError("couldn't find lines match in procstat out")
|
||||||
|
|
||||||
|
@retry_before_failing()
|
||||||
|
def test_proc_cpu_times(self):
|
||||||
|
tested = []
|
||||||
|
out = sh('procstat -r %s' % self.pid)
|
||||||
|
p = psutil.Process(self.pid)
|
||||||
|
for line in out.split('\n'):
|
||||||
|
line = line.lower().strip()
|
||||||
|
if 'user time' in line:
|
||||||
|
pstat_value = float('0.' + line.split()[-1].split('.')[-1])
|
||||||
|
psutil_value = p.cpu_times().user
|
||||||
|
self.assertEqual(pstat_value, psutil_value)
|
||||||
|
tested.append(None)
|
||||||
|
elif 'system time' in line:
|
||||||
|
pstat_value = float('0.' + line.split()[-1].split('.')[-1])
|
||||||
|
psutil_value = p.cpu_times().system
|
||||||
|
self.assertEqual(pstat_value, psutil_value)
|
||||||
|
tested.append(None)
|
||||||
|
if len(tested) != 2:
|
||||||
|
raise RuntimeError("couldn't find lines match in procstat out")
|
||||||
|
|
||||||
|
# --- virtual_memory(); tests against sysctl
|
||||||
|
|
||||||
|
@retry_before_failing()
|
||||||
|
def test_vmem_active(self):
|
||||||
|
syst = sysctl("vm.stats.vm.v_active_count") * PAGESIZE
|
||||||
|
self.assertAlmostEqual(psutil.virtual_memory().active, syst,
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
@retry_before_failing()
|
||||||
|
def test_vmem_inactive(self):
|
||||||
|
syst = sysctl("vm.stats.vm.v_inactive_count") * PAGESIZE
|
||||||
|
self.assertAlmostEqual(psutil.virtual_memory().inactive, syst,
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
@retry_before_failing()
|
||||||
|
def test_vmem_wired(self):
|
||||||
|
syst = sysctl("vm.stats.vm.v_wire_count") * PAGESIZE
|
||||||
|
self.assertAlmostEqual(psutil.virtual_memory().wired, syst,
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
@retry_before_failing()
|
||||||
|
def test_vmem_cached(self):
|
||||||
|
syst = sysctl("vm.stats.vm.v_cache_count") * PAGESIZE
|
||||||
|
self.assertAlmostEqual(psutil.virtual_memory().cached, syst,
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
@retry_before_failing()
|
||||||
|
def test_vmem_free(self):
|
||||||
|
syst = sysctl("vm.stats.vm.v_free_count") * PAGESIZE
|
||||||
|
self.assertAlmostEqual(psutil.virtual_memory().free, syst,
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
@retry_before_failing()
|
||||||
|
def test_vmem_buffers(self):
|
||||||
|
syst = sysctl("vfs.bufspace")
|
||||||
|
self.assertAlmostEqual(psutil.virtual_memory().buffers, syst,
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
# --- virtual_memory(); tests against muse
|
||||||
|
|
||||||
|
@unittest.skipIf(not MUSE_AVAILABLE, "muse not installed")
|
||||||
|
def test_muse_vmem_total(self):
|
||||||
|
num = muse('Total')
|
||||||
|
self.assertEqual(psutil.virtual_memory().total, num)
|
||||||
|
|
||||||
|
@unittest.skipIf(not MUSE_AVAILABLE, "muse not installed")
|
||||||
|
@retry_before_failing()
|
||||||
|
def test_muse_vmem_active(self):
|
||||||
|
num = muse('Active')
|
||||||
|
self.assertAlmostEqual(psutil.virtual_memory().active, num,
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
@unittest.skipIf(not MUSE_AVAILABLE, "muse not installed")
|
||||||
|
@retry_before_failing()
|
||||||
|
def test_muse_vmem_inactive(self):
|
||||||
|
num = muse('Inactive')
|
||||||
|
self.assertAlmostEqual(psutil.virtual_memory().inactive, num,
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
@unittest.skipIf(not MUSE_AVAILABLE, "muse not installed")
|
||||||
|
@retry_before_failing()
|
||||||
|
def test_muse_vmem_wired(self):
|
||||||
|
num = muse('Wired')
|
||||||
|
self.assertAlmostEqual(psutil.virtual_memory().wired, num,
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
@unittest.skipIf(not MUSE_AVAILABLE, "muse not installed")
|
||||||
|
@retry_before_failing()
|
||||||
|
def test_muse_vmem_cached(self):
|
||||||
|
num = muse('Cache')
|
||||||
|
self.assertAlmostEqual(psutil.virtual_memory().cached, num,
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
@unittest.skipIf(not MUSE_AVAILABLE, "muse not installed")
|
||||||
|
@retry_before_failing()
|
||||||
|
def test_muse_vmem_free(self):
|
||||||
|
num = muse('Free')
|
||||||
|
self.assertAlmostEqual(psutil.virtual_memory().free, num,
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
@unittest.skipIf(not MUSE_AVAILABLE, "muse not installed")
|
||||||
|
@retry_before_failing()
|
||||||
|
def test_muse_vmem_buffers(self):
|
||||||
|
num = muse('Buffer')
|
||||||
|
self.assertAlmostEqual(psutil.virtual_memory().buffers, num,
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
def test_cpu_stats_ctx_switches(self):
|
||||||
|
self.assertAlmostEqual(psutil.cpu_stats().ctx_switches,
|
||||||
|
sysctl('vm.stats.sys.v_swtch'), delta=1000)
|
||||||
|
|
||||||
|
def test_cpu_stats_interrupts(self):
|
||||||
|
self.assertAlmostEqual(psutil.cpu_stats().interrupts,
|
||||||
|
sysctl('vm.stats.sys.v_intr'), delta=1000)
|
||||||
|
|
||||||
|
def test_cpu_stats_soft_interrupts(self):
|
||||||
|
self.assertAlmostEqual(psutil.cpu_stats().soft_interrupts,
|
||||||
|
sysctl('vm.stats.sys.v_soft'), delta=1000)
|
||||||
|
|
||||||
|
def test_cpu_stats_syscalls(self):
|
||||||
|
self.assertAlmostEqual(psutil.cpu_stats().syscalls,
|
||||||
|
sysctl('vm.stats.sys.v_syscall'), delta=1000)
|
||||||
|
|
||||||
|
# def test_cpu_stats_traps(self):
|
||||||
|
# self.assertAlmostEqual(psutil.cpu_stats().traps,
|
||||||
|
# sysctl('vm.stats.sys.v_trap'), delta=1000)
|
||||||
|
|
||||||
|
# --- others
|
||||||
|
|
||||||
|
def test_boot_time(self):
|
||||||
|
s = sysctl('sysctl kern.boottime')
|
||||||
|
s = s[s.find(" sec = ") + 7:]
|
||||||
|
s = s[:s.find(',')]
|
||||||
|
btime = int(s)
|
||||||
|
self.assertEqual(btime, psutil.boot_time())
|
||||||
|
|
||||||
|
# --- sensors_battery
|
||||||
|
|
||||||
|
@unittest.skipIf(not HAS_BATTERY, "no battery")
|
||||||
|
def test_sensors_battery(self):
|
||||||
|
def secs2hours(secs):
|
||||||
|
m, s = divmod(secs, 60)
|
||||||
|
h, m = divmod(m, 60)
|
||||||
|
return "%d:%02d" % (h, m)
|
||||||
|
|
||||||
|
out = sh("acpiconf -i 0")
|
||||||
|
fields = dict([(x.split('\t')[0], x.split('\t')[-1])
|
||||||
|
for x in out.split("\n")])
|
||||||
|
metrics = psutil.sensors_battery()
|
||||||
|
percent = int(fields['Remaining capacity:'].replace('%', ''))
|
||||||
|
remaining_time = fields['Remaining time:']
|
||||||
|
self.assertEqual(metrics.percent, percent)
|
||||||
|
if remaining_time == 'unknown':
|
||||||
|
self.assertEqual(metrics.secsleft, psutil.POWER_TIME_UNLIMITED)
|
||||||
|
else:
|
||||||
|
self.assertEqual(secs2hours(metrics.secsleft), remaining_time)
|
||||||
|
|
||||||
|
@unittest.skipIf(not HAS_BATTERY, "no battery")
|
||||||
|
def test_sensors_battery_against_sysctl(self):
|
||||||
|
self.assertEqual(psutil.sensors_battery().percent,
|
||||||
|
sysctl("hw.acpi.battery.life"))
|
||||||
|
self.assertEqual(psutil.sensors_battery().power_plugged,
|
||||||
|
sysctl("hw.acpi.acline") == 1)
|
||||||
|
secsleft = psutil.sensors_battery().secsleft
|
||||||
|
if secsleft < 0:
|
||||||
|
self.assertEqual(sysctl("hw.acpi.battery.time"), -1)
|
||||||
|
else:
|
||||||
|
self.assertEqual(secsleft, sysctl("hw.acpi.battery.time") * 60)
|
||||||
|
|
||||||
|
@unittest.skipIf(HAS_BATTERY, "has battery")
|
||||||
|
def test_sensors_battery_no_battery(self):
|
||||||
|
# If no battery is present one of these calls is supposed
|
||||||
|
# to fail, see:
|
||||||
|
# https://github.com/giampaolo/psutil/issues/1074
|
||||||
|
with self.assertRaises(RuntimeError):
|
||||||
|
sysctl("hw.acpi.battery.life")
|
||||||
|
sysctl("hw.acpi.battery.time")
|
||||||
|
sysctl("hw.acpi.acline")
|
||||||
|
self.assertIsNone(psutil.sensors_battery())
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- OpenBSD
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(not OPENBSD, "OPENBSD only")
|
||||||
|
class OpenBSDSpecificTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_boot_time(self):
|
||||||
|
s = sysctl('kern.boottime')
|
||||||
|
sys_bt = datetime.datetime.strptime(s, "%a %b %d %H:%M:%S %Y")
|
||||||
|
psutil_bt = datetime.datetime.fromtimestamp(psutil.boot_time())
|
||||||
|
self.assertEqual(sys_bt, psutil_bt)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================================
|
||||||
|
# --- NetBSD
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipIf(not NETBSD, "NETBSD only")
|
||||||
|
class NetBSDSpecificTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_meminfo(look_for):
|
||||||
|
with open('/proc/meminfo', 'rb') as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith(look_for):
|
||||||
|
return int(line.split()[1]) * 1024
|
||||||
|
raise ValueError("can't find %s" % look_for)
|
||||||
|
|
||||||
|
def test_vmem_total(self):
|
||||||
|
self.assertEqual(
|
||||||
|
psutil.virtual_memory().total, self.parse_meminfo("MemTotal:"))
|
||||||
|
|
||||||
|
def test_vmem_free(self):
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
psutil.virtual_memory().free, self.parse_meminfo("MemFree:"),
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
def test_vmem_buffers(self):
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
psutil.virtual_memory().buffers, self.parse_meminfo("Buffers:"),
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
def test_vmem_shared(self):
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
psutil.virtual_memory().shared, self.parse_meminfo("MemShared:"),
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
def test_swapmem_total(self):
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
psutil.swap_memory().total, self.parse_meminfo("SwapTotal:"),
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
def test_swapmem_free(self):
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
psutil.swap_memory().free, self.parse_meminfo("SwapFree:"),
|
||||||
|
delta=MEMORY_TOLERANCE)
|
||||||
|
|
||||||
|
def test_swapmem_used(self):
|
||||||
|
smem = psutil.swap_memory()
|
||||||
|
self.assertEqual(smem.used, smem.total - smem.free)
|
||||||
|
|
||||||
|
def test_cpu_stats_interrupts(self):
|
||||||
|
with open('/proc/stat', 'rb') as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith(b'intr'):
|
||||||
|
interrupts = int(line.split()[1])
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ValueError("couldn't find line")
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
psutil.cpu_stats().interrupts, interrupts, delta=1000)
|
||||||
|
|
||||||
|
def test_cpu_stats_ctx_switches(self):
|
||||||
|
with open('/proc/stat', 'rb') as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith(b'ctxt'):
|
||||||
|
ctx_switches = int(line.split()[1])
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
raise ValueError("couldn't find line")
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
psutil.cpu_stats().ctx_switches, ctx_switches, delta=1000)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
run_test_module_by_name(__file__)
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче