NAME
piddler - Display all process table, open files, and network connections for a PID.
SYNOPSIS
piddler [-a] [-c] [-d] [-e <int>] [-f] [-j] [-l <int>] [-m] [-n] [--nc] [-p] [-r] [-t] [-u] [-E] [-H] <PID>[,<PID>...]
piddler [-h|--help]
piddler [-v|--version]
FLAGS
-a
Show a_inodes.
-c
Do not show pipe chains.
-d
Do not dedup.
-e <int>
How many commands to show for the far end of a pipe, FIFO, unix socket, or shared memory object and how many PIDs to show for any one of those commands, with whatever is left off noted as a count.
Zero or less shows all of them.
Defaults to 0, showing all of them.
-f
Do not show named pipes, which is to say the FIFOs sitting on the file system rather than the anonymous pipes -p covers.
-j
Show what the process has been shut away in under its own section, that being every parameter of the jail it is in on FreeBSD, as per "JAILS", and the cgroups and namespaces it is in on Linux, as per "CONTAINERS".
-l <int>
How long a command may be in a pipe chain before it is truncated, with ... tacked onto the end of it to show that it was.
ps auxw(4821) | grep -i --line-buffered --color=auto...(4822)
Zero or less does not truncate at all.
Only the pipe chains are touched, the commands shown for the far end of a endpoint having a length of their own.
Defaults to 0, not truncating at all.
-m
Show memory mapped libraries of the REG type.
-n
Do not resolve PTR addresses
--nc
Disable color.
The double dash matters here. Flag bundling is on for the single character flags, so -nc is taken for -n -c rather than this.
-p
Do not show anonymous pipes, the sort a shell makes when it strings two commands together.
Linux hands these the FIFO type rather than one of their own, naming them pipe instead of after a path the way a named one is, which is what tells the two apart there.
-r
Show VREG / files.
-t
Show shared libraries.
-u
Do not show unix sockets.
-E
Do not resolve pipe, FIFO, unix socket, and SHM peers.
-H
Do not humanize sizes.
ENVIRONMENTAL VARIABLES
These are used for XORing the corresponding flags. So setting one to 1 has the same effect as passing the flag, and passing the flag as well XORs it back off.
The exceptions are PIDDLER_peer_max and PIDDLER_pipe_chain_command_length, which take a value rather than being toggles, so they just set the default for the flag they belong to and passing that flag overrides it.
NO_COLOR
If set to a non-empty value, color will be disabled, the same as --nc.
PIDDLER_a_inode
If set to 1, a_inode types will be shown, the same as -a.
PIDDLER_dont_fifo
If set to 1, FIFOs will not be shown, the same as -f.
PIDDLER_jail_info
If set to 1, the jail a process is in, or the cgroups and namespaces on Linux, will be shown, the same as -j.
PIDDLER_memreglib
If set to 1, memory mapped libraries with the type REG will be shown, the same as -m.
PIDDLER_txt
If set to 1, libraries with the TXT type will be shown, the same as -t.
PIDDLER_dont_pipe
If set to 1, pipes will not be shown, the same as -p.
PIDDLER_dont_pipe_chains
If set to 1, pipe chains will not be shown, the same as -c.
PIDDLER_pipe_chain_command_length
Sets how long a command may be in a pipe chain before it is truncated, the same as -l, which overrides it when passed.
PIDDLER_dont_unix
If set to 1, unix sockets will not be shown, the same as -u.
PIDDLER_dont_peers
If set to 1, pipe, FIFO, unix socket, and SHM peers will not be resolved, the same as -E.
PIDDLER_peer_max
Sets how many peers will be shown, the same as -e, which overrides it when passed.
PIDDLER_dont_human_size
If set to 1, sizes will be printed as the raw number of bytes, the same as -H.
PIDDLER_vregroot
If set to 1, VREG / will be shown, the same as -r.
PIDDLER_dont_dedup
If set to 1, duplicate file handles are not removed, the same as -d.
PIDDLER_dont_resolv
If set to 1, PTR addresses will not be resolved for network connections, the same as -n.
PIPE CHAINS
By default a section is shown for the pipelines the process is a part of, with the commands printed in the order the data flows through them. -c turns this off.
PIPE CHAINS
ps auxw(4821) | grep foo(4822) | wc -l(4823)
Commands are truncated as per -l. Any process that can not be looked up, such as one belonging to another user when not running as root, is shown as a ?. A process may sit on more than one pipe, so at most 16 lines are shown for any one of them.
Only a pipe with the one process writing and the one reading is a link in a pipeline, that being what a shell makes when it strings two commands together. Two processes each running a pipe at the other are talking both ways, which is the one channel between them rather than two pipelines pointed opposite ways.
firefox(7375) <-> firefox -contentproc...(24844)
Anything else is left as the one pipe it is, printed as whatever is writing to it against whatever is reading, rather than being strung into a pipeline it is not. A worker pool sharing a queue out among its workers is the usual sort.
python process.py(8007) | python process.py(8007), inherited(94645, 94646, + 5 more)
A process forked off of one already holding a pipe is handed a copy of it whether it has any use for it or not, and a pool that forks a worker at a time ends up with every worker holding a end of every pipe made before it. Those are printed as inherited so they are not taken for something that was given the pipe to use.
Tying the two ends of a pipe together requires a system wide lsof, so it is only run for processes that actually have a pipe open, and only once no matter how many PIDs are given.
The direction of a pipe is taken from the r and w access characters when lsof reports them. Systems such as FreeBSD report pipes as being open read/write instead, in which case the descriptor number is used, 0 being the input and 1 and 2 being the output. On those systems that means only pipes on stdin, stdout, and stderr may be chained together.
PIPE, FIFO, UNIX SOCKET, AND SHM PEERS
The command holding the far end of a pipe, FIFO, unix socket, or shared memory object is appended to the one in question, so -p, -f, and -u decide whether it is seen at all for those. -E turns just this off.
7u unix 0xfffff80022630400 0 ->0xfffff80022635000 (dbus-daemon --session(51092))
14u unix 0xfffff80052dee800 0 /tmp/dbus-nWRW4XDDoD (xfce4-panel(63471))
3r FIFO 0xe6 0t0 299839014 /tmp/testfifo (cat(12593))
17u SHM 288876 0 (firefox -contentproc...(7375, 24844, 32640, + 26 more))
The far end is found either by way of the endpoint this one points at, by way of whatever points at this one, or by way of what else has the same one open. The second is what covers the unix sockets lsof names after the path they are bound to, such as the accepted end of a connection, and the third the FIFOs, shared memory objects, and pipes that both ends hold the same object for.
Commands longer than 40 characters are truncated. A endpoint whose far end can not be looked up, such as one held by another user's process when not running as root, is shown as a ?. Nothing is shown for one that has no far end to speak of, such as a unix socket that is only bound and listening or a FIFO no one else has open.
A endpoint may be held by any number of other processes, such as a shared memory object inherited across a pile of forks, so the PIDs are gathered up under the command they are running, with -e capping how many of each are printed.
Tying the two ends together requires a system wide lsof, which is only done when a pipe, FIFO, unix socket, or shared memory object is actually going to be printed, and only once no matter how many PIDs are given.
Unix sockets are tied together either by way of a lsof that points at the far end of one, as FreeBSD does, or by way of lsof +E, which is what is used on Linux. A build of lsof with no +E to it just leaves them without a far end to speak of, everything else carrying on as it was.
SHARED MEMORY
The total size of the shared memory a process holds is shown with the rest of the memory bits. A object held on more than one FD is counted the once, the object being what takes up the memory rather than the handle on it.
Total SHM 1.076M
FreeBSD and the like hand these a SHM type of their own. Linux has no such type, giving them the same REG every other file gets, so there they are picked out by name instead.
/dev/shm/* POSIX objects, which live on a tmpfs
/SYSV* SysV segments, which are named after their key
/memfd:* the anonymous ones made by memfd_create
The TYPE column is whatever lsof called it either way, so these read as REG on Linux rather than SHM.
Every one of them is deduped and has its peers looked up in the same manner as any other, so what else holds a object is shown for it as per "PIPE, FIFO, UNIX SOCKET, AND SHM PEERS" and the ones that print the same are rolled up as per "FILE HANDLE DEDUPING".
JAILS
On FreeBSD, any process with a JID other than 0 has the jail it is in looked up, showing the name of it with the number after it in the same manner as the UID and GID.
jid test(1) test.example.org /jails/test
The hostname and path are only tacked on when they have anything to add, the first being more often than not just the name over again and the second nothing worth mentioning for a jail sharing the file system it was started from. Just the number is shown for a jail that can not be looked up, such as one that has gone away since the process table was read.
-j adds a section with every parameter of the jail in it, which is the lot of what jls reports for one.
JAIL ARG VALUE
host.hostname test.example.org
jid 1
name test
path /jails/test
persist true
The lookup takes a run of jls, which is only done for a process that is in a jail, and only once per jail no matter how many PIDs are given.
CONTAINERS
Linux has no jails, shutting a process away with cgroups and namespaces instead, so that is what is shown in their place there.
The cgroup a process is in is shown with the rest of its info, that being what names the systemd unit or the container it belongs to. Nothing is shown for one left sitting in the root cgroup it started in, such as a kernel thread.
Cgroup /system.slice/postgresql@17-main.service
Every namespace it does not share with PID 1 is shown as well, those being what it has been shut away from the rest of the system in. A process sharing the lot of them has nothing to say here.
Namespaces mnt, net, pid, uts
When the cgroup names a container, the runtime that started it is shown with the ID after it, in the same manner as the UID and GID. The long hash a runtime hands a container is cut down to the first dozen characters, which is how everything else prints them.
Container docker(3f2a1b8c9d4e)
The runtimes below are the ones picked out. Anything else still has its cgroup and namespaces shown, just with no name put to it.
docker
podman
containerd
crio
lxc
machine systemd-nspawn and the like
CGROUP LIMITS
What the cgroup is using of what it is allowed is shown along with it, each line being left off when it has nothing to say, be it a limit that was never set or a controller that was never turned on for it.
Cgroup mem 98.304k / 33.554M peak 33.554M
Cgroup cpu quota 0.1, used 26, throttled 2604 for 4:05
Cgroup pids 1 / 50
Cgroup events oom_kill 1, oom 1, max 879
Cgroup pressure cpu 74.00/77.31, memory 0.15/2.73
All of it covers the whole cgroup rather than the one process, so a unit that started a dozen of them reports what the lot are using between them. Cgroup mem takes in the page cache on top of the anonymous memory as well, so it is not the RSS over again and will read higher than it for anything that has been through a pile of files.
The limit is only shown when there is one, memory.max falling back to the softer memory.high with high after it. Cgroup cpu is only shown for a cgroup that is either capped or being held back, the time it has used saying no more than the process table already does otherwise, and its quota is the share of a single core it works out to. Cgroup events and Cgroup pressure only turn up when something actually happened, everything sitting at zero having nothing to report.
None of it is read for a process in the root cgroup, which has nothing of its own to report, nor for one whose cgroup can not be found under the mount point, that being what a process in a cgroup namespace of its own looks like from outside of it. Reading the root for one of those would hand back the whole system's numbers as though they belonged to the process.
Only the v2 hierarchy is read. A system still running v1 alone has its cgroup paths shown as ever, just with none of this alongside them.
-j
-j adds a section with every cgroup and namespace in it, the ones not shared with PID 1 being called out, followed by the knobs of the cgroup itself and what else is sitting in it.
CONTAINER ARG VALUE
cgroup /piddler-test
ns:mnt 4026532643 private
ns:net 4026531833
cgroup.controllers cpuset cpu io memory pids
cgroup.procs 1 sh -c while :; do :; done(369709)
memory.current 90.112k
memory.max 33.554M
pids.max 50
cpu.max 10000 100000
cpu.stat:nr_throttled 2829
memory.events:oom_kill 1
cpu.pressure:some avg10=85.84 avg60=79.75 avg300=47.38
cgroup.procs is everything sitting in the cgroup, gathered up under the command each of them is running and capped in the same manner as the peers of a endpoint, as per -e. cgroup.controllers is what says why any of the rest are missing, a knob only being there for a controller that was turned on.
The memory.stat lines break memory.current down into where it actually went, which is what says how much of a cgroup is its own anonymous memory and how much is page cache it has read through, the two often being nothing alike.
memory.current 40.747M
memory.stat:anon 3.871M
memory.stat:file 29.131M
memory.stat:shmem 12.263M
There are a great many of these, so only the handful worth reading through are printed, and only the ones with something in them at that. memory.stat:shmem is all the tmpfs and shared memory charged to the cgroup, which is not the Total SHM shown with the process info, that being the shared memory objects the one process has open as per "SHARED MEMORY".
All of it is read from /proc and the cgroup mount, so there is nothing to run for it the way there is for a jail. The namespaces of a process belonging to another user are kept from everyone but root, so those go unshown when it is not root doing the asking.
FILE HANDLE DEDUPING
By default it checks if file handles are open in the same mode more than once. If it finds one of these + is appended to the value in the FD column.
The following are also RW filehandles.
u
uw
ur
Shared memory objects are rolled up as well, as per "SHARED MEMORY". A process may hold a great many that print the same, anonymous ones having nothing to tell them apart but their size and what else holds them, so only the first of them is printed, with the number left off tacked onto the FD. -d turns this off along with the rest of the deduping.
40u+43 SHM 262.144k