Home / Alt manpages / proc_pid_fdinfo(5)

  • proc_pid_fdinfo(5)
  • File format
  • linux

Read Descriptor Detail from /proc/pid/fdinfo

/proc/<pid>/fdinfo goes one level deeper than a plain descriptor listing, down to the file offset and open flags. The examples use Linux 6.8.0-139-generic and the locally installed Linux man-pages 6.7 package.

Allow about ten minutes. You need a shell and a mounted /proc filesystem. The workflow is read-only and normally needs no elevated privileges: it does not close a descriptor, change a flag, signal a process or alter a file.

1. Confirm the procfs entry

Each process has a directory named by its process ID. Its fdinfo subdirectory holds one file per open descriptor, named by the descriptor number. Start with your own shell, where permission is least surprising:

$ test -d /proc/self/fdinfo && echo fdinfo-is-available
fdinfo-is-available
$ printf 'shell PID: %s\n' "$$"
shell PID: 28417

The PID differs on every run. /proc/self is the right spelling when the command reading the file should inspect itself. Use /proc/PID to inspect another process, replacing PID with digits from your system.

2. List descriptors before reading one

List the numeric entries to see which descriptors exist:

$ find /proc/self/fdinfo -maxdepth 1 -type f -printf '%f\n' | sort -n
0
1
2
9

Your list depends on the shell, terminal and inherited descriptors. Do not assume descriptor 3 or 9 exists. A descriptor can disappear between listing and reading if the process closes it, so a brief No such file or directory failure is normal for a busy process.

Checkpoint

Pick a number that appeared in your own listing. The next command uses 0, since standard input is normally present.

$ cat /proc/self/fdinfo/0
pos:\t0
flags:\t0100000
mnt_id:\t26

Values are host-specific. The shape to look for is a decimal pos, an octal flags value and a mount ID. A terminal, pipe or redirected file produces different numbers.

3. Read the common fields

  • pos is the current file offset for regular files and directories, decimal, and it changes as the process reads or writes.
  • flags is octal, combining the file access mode with the status flags from open(2). If close-on-exec is currently set, the value also includes O_CLOEXEC.
  • mnt_id identifies the mount containing the file, present since Linux 3.15.

Read a known descriptor repeatedly when you are checking a live process:

$ while IFS= read -r line; do printf '%s\n' "$line"; done < /proc/self/fdinfo/0
pos:\t0
flags:\t0100000
mnt_id:\t26

This reads a snapshot of the pseudo-file. It does not lock the descriptor or freeze the process. For a coherent application-level view, collect the process's own diagnostics or trace its behaviour, do not treat two separate reads as one transaction.

4. Correlate a mount ID without changing anything

mnt_id is an identifier, not a path. To see the corresponding mount entry, search the target process's mountinfo file:

$ mount_id=26
$ awk -v id="$mount_id" '$1 == id { print }' /proc/self/mountinfo
26  ... - ext4 /dev/nvme0n1p3 rw,relatime

The full line contains namespace and mount relationships before the separator, followed by the filesystem type and mount options. The example is abbreviated because the device and mount options belong to the host. No matching line usually means a copied number is wrong, or you are reading a different process's files: different mount namespaces can legitimately show different mount tables.

5. Recognise descriptor-specific records

The common fields are not the whole interface. The kernel adds records according to what the descriptor refers to.

  • Epoll: lines beginning with tfd identify watched descriptors; events and data are hexadecimal.
  • Eventfd: an eventfd-count value.
  • Signalfd: a hexadecimal sigmask.
  • Inotify and fanotify: records describing watches or marks, which can include inode, device and file-handle fields.
  • Timerfd: clock ID, expiration count, last set-time flags, next expiry and interval, with time pairs given as seconds and nanoseconds. For example:
pos:    0
flags:  02004002
mnt_id: 13
clockid: 0
ticks: 0
settime flags: 03
it_value: (7695568592, 640020877)
it_interval: (0, 0)

Do not parse every line as a key and a decimal value. The record format varies by descriptor type, and several fields are hexadecimal or structured tuples. Identify the kind of descriptor first, from the program or its /proc/PID/fd symbolic link, then apply the matching section of proc_pid_fdinfo(5).

6. Handle permissions and changing processes

fdinfo files are readable only by the process owner. Reading your own process is the simplest test. For another user's process, the read can fail even when the PID is correct:

$ cat /proc/OTHER_PID/fdinfo/0
cat: /proc/OTHER_PID/fdinfo/0: Permission denied

Replace OTHER_PID only with a real PID when testing.

Warning

Do not reach for sudo as a reflex. Elevated access may be restricted by the system's ptrace policy, and reading a sensitive process can expose operational details. Get authorisation before inspecting another user's process, and avoid copying descriptor data into tickets or logs where it might reveal file or device state.

A PID can also be reused after a process exits. If the target matters, record its command name and start time, and repeat the identity check close to the read. A descriptor number is meaningful only inside its own process: descriptor 4 in one process has no relationship to descriptor 4 in another.

Done means

  • Confirmed that /proc/self/fdinfo is available.
  • Listed existing descriptors instead of guessing a number.
  • Read pos, octal flags and mnt_id without confusing them with application data.
  • Know the extra records that epoll, eventfd, signalfd, inotify, fanotify and timerfd add.
  • Can explain a permission failure without assuming the PID or descriptor is wrong.
  • Changed nothing: no descriptor, process, service or persistent configuration was touched.