Read your procs' args
Sometimes you need to know what your
processes' arguments were, exactly.
ps
gives you a space separated list of arguments, getargv
can give you them ␀ separated.
If all you need is to see the arguments passed to your process
ps
is often good enough, it can show you what you want unless the
process was started with argv[0] set to an empty string, which
is unusual, though still supported by the kernel. In the case where argv[0]
is an empty string, ps
(from 10.3-14.6) will emit one or more environment variables
which were not part of the process' arguments (one for each leading empty argument).
If you need to parse the arguments passed to a process however,
that's when you'll need to use getargv
. Arguments to a process can contain
any series of bytes aside from ␀, which means that arguments can contain
spaces. In order to parse the arguments the same way that the process received
them, you need to process ␀ separated byte arrays. On BSDs and Linuxen that is provided
by the /proc/$PID/cmdline procfs path, Solaris has pargs
,
on macOS you need getargv
.
Idiomatic flags and no cruft
getargv
has five flags, three of which are purely information about itself. You use the standard -0 flag to print arguments ␀ separated, the -s flag to strip leading arguments, the -v flag to print getargv
's version, and either of -h or -? to print a usage string. That's it, that's the whole interface.
By doing one thing, and doing it well, getargv
is as fast as it can be
getargv
runs in approx 0.6 ㎳ on an M2 MacBook Air as measured by hyperfine
. It does this by utilizing a zero-copy single-scan algorithm to run in O(n)
time where n is the length of the arguments passed to the process you are inspecting, in Bytes. getargv
allocates at-most one relatively small block of memory, and stops reading the buffer once it finds the end of the process' arguments. getargv
also prints the arguments to stdout using pointers back to the original buffer, without copying.
I've spent a lot of time making getargv
able to handle edge cases
getargv
can handle the case where the process you are inspecting has an empty or missing argv[0].
getargv
can handle the process you are inspecting having been called with empty arguments in all positions.
getargv
can handle the case where the process you are inspecting has no arguments at all.
getargv
knows that the PID_MAX differs based on the macOS version, and checks accordingly.
getargv
handles being called with incorrect arguments, and prints helpful error messages.
The KERN_PROCARGS2 sysctl
does not differentiate between a PID not existing or your user not having permission to examine it, getargv
does.