---
name: "pdfork"
section: "2"
platform: "freebsd"
package: "base"
version: "16.0-CURRENT-20261027-61c70dc16a79"
release: "FreeBSD 16.0-CURRENT (2026-10-27)"
platforms: ["freebsd"]
url: "https://new.carta.tech/pddupfd"
---

# pdfork(2)

System calls to manage process descriptors

Part of [pddupfd(2)](/pddupfd/2.md).

## NAME

**pdfork**, **pdrfork**, **pdopenpid**, **pdgetpid**, **pdkill**, **pdwait**, **pddupfd** – System calls to manage process descriptors

## LIBRARY

Standard C Library (libc, -lc)

## SYNOPSIS

**#include \<sys/procdesc.h\>**

*pid\_t*\

**pdfork**(*int \*fdp*, *int pdflags*);

*pid\_t*\

**pdrfork**(*int \*fdp*, *int pdflags*, *int rfflags*);

*int*\

**pdopenpid**(*pid\_t pid*, *int pdflags*);

*int*\

**pdgetpid**(*int fd*, *pid\_t \*pidp*);

*int*\

**pdkill**(*int fd*, *int signum*);

*int*\

**pdwait**(*int fd*, *int \*status*, *int options*, *struct \_\_wrusage \*wrusage*, *struct \_\_siginfo \*info*);

*int*\

**pddupfd**(*int fd*, *int remotefd*, *int flags*);

*int*\

**pdptrace**(*int req*, *int fd*, *int lwpid*, *void \*addr*, *int data*);

## DESCRIPTION

Process descriptors are special file descriptors that represent processes, and are created using **pdfork**(), a variant of [fork(2)](/fork/2.md), which, if successful, returns a process descriptor in the integer pointed to by *fdp*. Processes created via **pdfork**() will not cause SIGCHLD on termination. **pdfork**() can accept the *pdflags:*

- PD\_DAEMON

  Instead of the default terminate-on-close behaviour, allow the process to live until it is explicitly killed with [kill(2)](/kill/2.md).

  This option is not permitted in [capsicum(4)](/capsicum/4.md) capability mode (see [cap\_enter(2)](/cap_enter/2.md)).

  Note: the option changes the behavior of [close(2)](/close/2.md) for the process descriptor returned by the operation. If there is another process descriptor for the same process, created without specifying the PD\_DAEMON flag, closing that descriptor kills the process.

- PD\_CLOEXEC

  Set close-on-exec on process descriptor.

- PD\_NOWAITPID

  The parent cannot obtain the child's status with [waitpid(2)](/waitpid/2.md).

  A consequence of not setting the flag is that the child' zombie is not reaped until the [waitpid(2)](/waitpid/2.md) call is performed on the child' PID. Setting the kern.pdfork\_implicit\_nowaitpid sysctl MIB to true makes the system behave as if the flag is always passed.

- PD\_PTRACE\_CAP

  Enable pdptrace(2) requests on the resulting file descriptor. Otherwise the descriptor cannot be used to debug the child process. See [rights(4)](/rights/4.md) for the description of the CAP\_PTRACE capability.

The **pdrfork**() system call is a variant of **pdfork**() that also takes the *rfflags* argument to control sharing of process resources between the caller and the new process. Like **pdfork**(), the function writes the process descriptor referencing the created process into the location pointed to by the *fdp* argument. See [rfork(2)](/rfork/2.md) for a description of the possible *rfflag* flags. The **pdrfork**() system call requires that both the *RFPROC* and *RFPROCDESC* flags, or *RFSPAWN* flag are specified.

The **pdopenpid**() function opens the process descriptor for the process specified by the argument *pid*. It takes the same flags in the *pdflags* argument as **pdfork**(). The caller must have permission to debug the target process in order for **pdopenpid**() to succeed. Zombie processes cannot be opened.

There might be more that one file descriptor referencing the process. After the zombie is reaped, calls to **pdwait**() specifying any file descriptors for the same process fail with the ESRCH error.

The **pdopenpid**() system call is allowed in the capability mode (see [capsicum(4)](/capsicum/4.md)) when the target process is the child of the calling process, or when the calling process is the debugger of the target process. The debugger is attached to its target by [ptrace(2)](/ptrace/2.md), pdptrace(2), or by other means, e.g., by debugging the target process' parent with the follow-on-fork mode enabled.

**pdgetpid**() queries the process ID (PID) in the process descriptor *fd*.

**pdkill**() is functionally identical to [kill(2)](/kill/2.md), except that it accepts a process descriptor, *fd*, rather than a PID.

The **pdwait**() system call allows the calling thread to wait and retrieve the status information on the process referenced by the *fd* process descriptor. See the description of the [wait6(2)](/wait6/2.md) system call for the behavior specification.

The **pddupfd**() function allows the caller to duplicate a file descriptor across the process boundaries. The function returns the new file descriptor that points to the same file as the file descriptor *remotefd* in the process specified by the *fd* process descriptor. The returned file descriptor has the O\_CLOEXEC flag set. The *flags* argument is reserved and must be zero. Certain file descriptor types cannot be copied this way, namely kqueues.

The **pdptrace**() function enables execution of [ptrace(2)](/ptrace/2.md) requests on the process specified by the process descriptor *fd*.

In addition to the arguments taken by the [ptrace(2)](/ptrace/2.md), system call, the *lwpid* thread identifier can designate the thread on which the request must operate. The *lwpid* argument can be specified as -1 if the call is not thread-specific, or kernel is allowed to select some thread on its own.

Unlike the [ptrace(2)](/ptrace/2.md) implementation, **pdptrace**() does not clear the errno variable before executing the system call.

### Interaction of Process Descriptors and Xr WAITPID 2

The **pdwait**() system call may be called on a process descriptor an unlimited number of times. In particular, it does not reap the target process, even if that process has exited. Each time, it returns the same status.

- If the process was forked with **pdfork**(), and the PD\_NOWAITPID flag was specified, then the process is automatically reaped after the last process descriptor referencing that process is closed. No [waitpid(2)](/waitpid/2.md) call (or a call from the same family of the wait functions which operate on PIDs) are needed to reap the zombie process.

- If the process was created by **pdfork**(), and the PD\_NOWAITPID flag was not specified, then after exiting, the process will not be reaped until the parent or reaper has called [waitpid(2)](/waitpid/2.md) and all process descriptors referencing the process are closed.

- If the process was created by the [fork(2)](/fork/2.md) system call (which does not allocate a process descriptor for the child), and later the process was opened by **pdopenpid**(), then a [waitpid(2)](/waitpid/2.md) call from the parent is needed to reap the exited child.

In any case, the PID of the process is not reused until its zombie is reaped, and all its process descriptors are closed.

A debugger attached by [ptrace(2)](/ptrace/2.md) can execute the **waitpid**() calls against the alive target regardless of the way the target process was forked.

### Interaction of Process Descriptors with other System Calls

The following system calls also have effects specific to process descriptors:

[fstat(2)](/fstat/2.md) queries status of a process descriptor; currently only the *st\_mode*, *st\_birthtime*, *st\_atime*, *st\_ctime* and *st\_mtime* fields are defined. If the owner read, write, and execute bits are set then the process represented by the process descriptor is still alive.

[poll(2)](/poll/2.md) and [select(2)](/select/2.md) allow waiting for process state transitions; currently only POLLHUP is defined, and will be raised when the process dies. Process state transitions can also be monitored using [kqueue(2)](/kqueue/2.md) filter EVFILT\_PROCDESC; currently only NOTE\_EXIT is implemented.

[close(2)](/close/2.md) will close the process descriptor unless PD\_DAEMON is set; if the process is still alive and this is the last reference to the process descriptor, the process will be terminated with the signal SIGKILL. The PID of the referenced process is not reused until the process descriptor is closed, whether or not the zombie process is reaped by **pdwait**(), wait6, or similar system calls.

## RETURN VALUES

**pdfork**() and **pdrfork**() return a PID, 0 or -1, as [fork(2)](/fork/2.md) does.

**pdopenpid**(), **pdgetpid**(), **pdkill**(), **pdwait**(), and **pddupfd**() return 0 on success and -1 on failure.

## ERRORS

These functions may return the same error numbers as their PID-based equivalents (e.g. **pdfork**() may return the same error numbers as [fork(2)](/fork/2.md)), with the following additions:

- \[EFAULT\]

  The copyout of the resulting file descriptor value to the memory pointed to by *fdp* failed.

  Note that the child process was already created when this condition is detected, and the child continues execution, same as the parent. If this error must be handled, it is advisable to memoize the **getpid**() result before the call to **pdfork**() or **pdrfork**(), and compare it to the value returned by **getpid**() after, to see if code is executing in parent or child.

- \[EINVAL\]

  The signal number given to **pdkill**() is invalid.

- \[ENOTCAPABLE\]

  The process descriptor being operated on has insufficient rights (e.g. CAP\_PDKILL for **pdkill**()).

- \[EINVAL\]

  The **pdwait**() function is called with reserved bits set in *options*.

The **pdopenpid**() might return the same errors as [open(2)](/open/2.md), related to the file descriptor allocation problems, as well as the following specific errors:

- \[EINVAL\]

  The *flags* argument has reserved bits set.

- \[ECAPMODE\]

  **pdopenpid**() is called by the process in capability mode.

- \[EBUSY\]

  The process specified by the *pid* argument already terminated.

- \[ESRCH\]

  The process specified by the *pid* argument does not exist, or the caller does not have enough privileges to open the process.

- \[EMFILE\]

  The calling process already reached its limit for open file descriptors.

  Current implementation installs the opened process descriptor into the calling process's file descriptors table. If the descriptor cannot be installed, the process descriptor is closed, which executes all actions performed by [close(2)](/close/2.md) on it.

The **pddupfd**() returns the following errors:

- \[EINVAL\]

  The *flags* argument is not zero.

- \[EINVAL\]

  The file descriptor *fd* is not a process file descriptor.

- \[ESRCH\]

  The process specified by the file descriptor *fd* exited.

- \[EBADF\]

  The file descriptor *remotefd* is not a valid file descriptor in the specified process.

- \[ENOENT\]

  The specified process does not have a file descriptor table.

- \[EOPNOTSUPP\]

  *remotefd* refers to a file that cannot be duplicated across a process boundary, such as a kqueue.

The **pdptrace**() system call returns the same errors as [ptrace(2)](/ptrace/2.md), as well as the following specific errors:

- \[ECAPMODE\]

  The process issuing the **pdptrace**() call is in capability mode, and the security.bsd.allow\_ptrace\_in\_cap\_mode tunable is set to false.

- \[ENOTCAPABLE\]

  The process called **pdptrace**() on the process descriptor that does not have the CAP\_PTRACE capability enabled.

## SEE ALSO

[close(2)](/close/2.md), [fork(2)](/fork/2.md), [fstat(2)](/fstat/2.md), [kill(2)](/kill/2.md), [kqueue(2)](/kqueue/2.md), [poll(2)](/poll/2.md), [wait4(2)](/wait4/2.md), [capsicum(4)](/capsicum/4.md), [procdesc(4)](/procdesc/4.md)

## HISTORY

The **pdfork**(), **pdgetpid**(), and **pdkill**() system calls first appeared in FreeBSD 9.0. The **pdrfork**() and **pdwait**() system calls first appeared in FreeBSD 15.1. The **pdopenpid**() and **pddupfd**() system calls first appeared in FreeBSD 16.0.

Support for process descriptors mode was developed as part of the TrustedBSD Project.

## AUTHORS

These functions and the capability facility were created by Robert N. M. Watson ⟨*rwatson@FreeBSD.org*⟩ and Jonathan Anderson ⟨*jonathan@FreeBSD.org*⟩ at the University of Cambridge Computer Laboratory with support from a grant from Google, Inc. The **pdrfork**() and **pdwait**() functions were developed by Konstantin Belousov ⟨*kib@FreeBSD.org*⟩ with input from Alan Somers ⟨*asomers@FreeBSD.org*⟩. The **pdopenpid**(), **pddupfd**(), and **pdptrace**() functions were developed by Konstantin Belousov ⟨*kib@FreeBSD.org*⟩.
