libproc¶
Contents:
Low-level bindings to libproc.dylib¶
Introduction¶
This module contains descriptions and wrappers around interesting parts of the libproc.dylib shared library. This library exposes internal kernel data about processes of OS X. It was developed and tested on OS X 10.7.5, using i386 architecture.
Many aspects were traced manually from xnu source code as this library is severely undocumented.
Low-level API¶
The entire action of this library revolves around the function
__proc_info()
which is a simple wrapper around a system call. The signature
of the function is as follows (Internal private prototype taken from
libproc.c
):
int
__proc_info(
int callnum, // One of _PROC_CALLNUM_xxx constants below.
int pid, // Varies per callnum, see below.
int flavor, // Ditto.
uint64_t arg, // Ditto, sometimes unused.
void *buffer, // Output buffer.
int buffersize // Size of output buffer.
);
The only low level API is __proc_info()
itself.
The behavior of this function depends on the first argument, callnum, which is typical of many kernel interfaces. Unfortunately distinct values of callnum do not have any official names (in the source code they are simply hard-coded constants. I have used a convention _PROC_CALLNUM_xxx where xxx is derived from the name of the kernel function multiplexed by that value.
The values I have made are:
PROC_CALLNUM_LISTPIDS = 1
PROC_CALLNUM_PIDINFO = 2
PROC_CALLNUM_PIDFDINFO = 3
PROC_CALLNUM_KERNMSGBUF = 4
PROC_CALLNUM_SETCONTROL = 5
PROC_CALLNUM_PIDFILEPORTINFO = 6
You can verify them by looking at proc_info_internal()
in the xnu source
code: xnu/bsd/kern/proc_info.c
.
Whenever this function is called with NULL value for buffer, it will compute and return the correct size of the buffer to pass. Looking at the source code of the system call it makes some conservative estimates but I suspect it is still racy (a fork bomb might make the value invalid between the first and second calls).
Callnum 1¶
Note
This callnum has a liproc-only alias of PROC_CALLNUM_LISTPIDS
When callnum is PROC_CALLNUM_LISTPIDS
then the function
obtains a list of process identifiers that match some criteria.
The remaining arguments have the following meaning:
- pid:
Contains the type of process list to obtain. The possible values are one of PROC_xxx constants listed below.
PROC_ALL_PIDS
:- Return the full process table.
PROC_PGRP_ONLY
:- Return a list of processes that have a given process group ID
PROC_TTY_ONLY
:- Return a list of processes that are attached to a given TTY
PROC_UID_ONLY
:- Return a list of processes that have a given user ID.
PROC_RUID_ONLY
:- Return a list of processes that have a given real user ID.
PROC_PPID_ONLY
:- Return a list of processes that are children of a given process.
- flavor:
- Contains the optional filtering argument for the processes that are returned. The value passed here is compared against the desired property of each process. The only exception is PROC_ALL_PIDS where no filtering takes place.
- arg:
- This parameter is unused.
- buffer:
This parameter is the pointer to the output buffer. The buffer is an array of
ctypes.c_int
of appropriate size (as determined by the size of the process table).As a convention, you can pass a None value (which maps to a NULL pointer) to ask the kernel for the size of the buffer. Correct buffer size in bytes is then returned by the call.
- buf_size:
- Size of the buffer, in bytes.
The return value is either the number of bytes needed or the number of bytes written to the buffer (see the discussion of buffer argument above).
Callnum 2¶
Note
This callnum has a liproc-only alias of PROC_CALLNUM_PIDINFO
This callnum is currently undocumented.
Callnum 3¶
Note
This callnum has a liproc-only alias of PROC_CALLNUM_PIDFDINFO
This callnum is currently undocumented.
Callnum 4¶
Note
This callnum has a liproc-only alias of PROC_CALLNUM_KERNMSGBUF
This callnum is currently undocumented.
Callnum 5¶
Note
This callnum has a liproc-only alias of PROC_CALLNUM_SETCONTROL
This callnum is currently undocumented.
Callnum 6¶
Note
This callnum has a liproc-only alias of PROC_CALLNUM_PIDFILEPORTINFO
This callnum is currently undocumented.
Installation¶
Linux Distributions and Windows¶
Libproc is designed to work on OS X as it takes advantage of the kernel features unique to the xnu kernel. You cannot use it on any other platform.
Typically you want to use libproc in a platform-dependent version of your application or library or use a higher-level library that hides this complexity away from your code.
Contributing¶
Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.
You can contribute in many ways:
Types of Contributions¶
Report Bugs¶
Report bugs at https://github.com/zyga/libproc/issues.
If you are reporting a bug, please include:
- Your operating system name and version.
- Any details about your local setup that might be helpful in troubleshooting.
- Detailed steps to reproduce the bug.
Fix Bugs¶
Look through the GitHub issues for bugs. Anything tagged with “bug” is open to whoever wants to implement it.
Implement Features¶
Look through the GitHub issues for features. Anything tagged with “feature” is open to whoever wants to implement it.
Write Documentation¶
Libproc could always use more documentation, whether as part of the official libproc docs, in docstrings, or even on the web in blog posts, articles, and such.
Submit Feedback¶
The best way to send feedback is to file an issue at https://github.com/zyga/libproc/issues.
If you are proposing a feature:
- Explain in detail how it would work.
- Keep the scope as narrow as possible, to make it easier to implement.
- Remember that this is a volunteer-driven project, and that contributions are welcome :)
Get Started!¶
Ready to contribute? Here’s how to set up libproc for local development.
Fork the libproc repo on GitHub.
Clone your fork locally:
$ git clone git@github.com:your_name_here/libproc.git
Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:
$ mkvirtualenv libproc $ cd libproc/ $ python setup.py develop
Create a branch for local development:
$ git checkout -b name-of-your-bugfix-or-feature
Now you can make your changes locally.
When you’re done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:
$ flake8 proc.py $ python setup.py test $ tox
To get flake8 and tox, just pip install them into your virtualenv.
Commit your changes and push your branch to GitHub:
$ git add . $ git commit -m "Your detailed description of your changes." $ git push origin name-of-your-bugfix-or-feature
Submit a pull request through the GitHub website.
Pull Request Guidelines¶
Before you submit a pull request, check that it meets these guidelines:
- The pull request should include tests.
- If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.rst.
- The pull request should work for Python 2.7, 3.2, 3.3, and 3.4, and 3.5 Check https://travis-ci.org/zyga/libproc/pull_requests and make sure that the tests pass for all supported Python versions.
Credits¶
Development Lead¶
- Zygmunt Krynicki <me@zygoon.pl>
Contributors¶
None yet. Why not be the first?
History¶
0.2 (2015-09-20)¶
- Initial version exposing just callnum 1
(
PROC_CALLNUM_LISTPIDS
) along with pythonic wrappers and comprehensive demonstration tool (exampes/listpids.py
)
Code Reference¶
libproc
¶
Low-level bindings to libproc.dylib.
This module exposes only one function, proc_info(). Please refer to the documentation directory for explanation on how to use it correctly.
Note
That the only low-level binding is the proc_info() function itself. All of the other functions are pure-python wrappers around it that don’t require the caller to handle ctypes.
-
libproc.
proc_info
(callnum, pid, flavor, arg, buffer, buf_size)¶ The proc_info() low-level system call.
The python3-style signature of proc_info() is:
__proc_info( callnum: ctypes.c_int, pid: ctypes.c_int, flavor: ctypes.c_int, arg: ctypes.c_uint64, buffer: ctypes.c_void_p, buf_size: ctypes.c_int ) -> ctypes.c_int
There is also an error checker that raises
OSError
if the underlying call fails. This is easy to do if the buffer is handled incorrectly or callnum or pid are invalid.This function uses multiplexing on callnum to invoke distinct kernel functions. Please look at the PROC_CALLNUM_xxx family of constants for details.
-
libproc.
PROC_CALLNUM_LISTPIDS
= 1¶ Value of __proc_info(callnum, ...), returns a list of PIDs.
-
libproc.
PROC_CALLNUM_PIDINFO
= 2¶ Undocumented.
-
libproc.
PROC_CALLNUM_PIDFDINFO
= 3¶ Undocumented.
-
libproc.
PROC_CALLNUM_KERNMSGBUF
= 4¶ Undocumented.
-
libproc.
PROC_CALLNUM_SETCONTROL
= 5¶ Undocumented.
-
libproc.
PROC_CALLNUM_PIDFILEPORTINFO
= 6¶ Undocumented.
-
libproc.
PROC_ALL_PIDS
= 1¶ When called with callnum 1, return all processes
-
libproc.
PROC_PGRP_ONLY
= 2¶ When called with callnum 1, return all processes in a given group
-
libproc.
PROC_TTY_ONLY
= 3¶ When called with callnum 1, return all processes attached to a given tty
-
libproc.
PROC_UID_ONLY
= 4¶ When called with callnum 1, return all processes with the given UID
-
libproc.
PROC_RUID_ONLY
= 5¶ When called with callnum 1, return all processes with the given RUID
-
libproc.
PROC_PPID_ONLY
= 6¶ When called with callnum 1, return all processes with the given PPID
-
libproc.
get_all_pids
()[source]¶ Get a list of all process IDs.
Returns: A list of all the process IDs on this system. Raises OSError: If the underlying system call fails.
-
libproc.
get_pids_for_uid
(uid)[source]¶ Get a list of PIDs (process IDs) with the specific user ID.
Parameters: uid – The UID to look for. Returns: A list of matching PIDs. Raises OSError: If the underlying system call fails.
-
libproc.
get_pids_for_ruid
(ruid)[source]¶ Get a list of PIDs (process IDs) with the specific real user ID.
Parameters: ruid – The RUID to look for. Returns: A list of matching PIDs. Raises OSError: If the underlying system call fails.
-
libproc.
get_pids_for_ppid
(ppid)[source]¶ Get a list of PIDs (process IDs) with the specific parent PID.
Parameters: ppid – The parent process ID to look for. Returns: A list of matching PIDs. Raises OSError: If the underlying system call fails.