4.20 The Descriptor Store

A service may hand file descriptors to the manager and get them back after a restart it did not choose. This is what lets a stateful daemon — one holding a listening socket, say — restart without dropping what it already had.

The manager MUST support a per-service maximum, which MAY be zero. Zero disables the store for that service, and a service MUST NOT assume a store exists.

4.20.1 Storing #

On an authenticated datagram carrying FDSTORE=1 with descriptors attached, the manager MUST:

  1. If the store is disabled for this service, close the descriptors and record the rejection.
  2. If the store already holds its maximum, close the descriptors and record the rejection. It MUST NOT evict an existing entry — a full store is full, and silently discarding something the service is relying on to survive a restart would be worse than refusing the new one.
  3. Store them under the value of FDNAME if present and non-empty, and under the name stored otherwise.
  4. Note FDPOLL=0 if present.

A datagram MAY carry several descriptors. Each becomes its own entry under the one name, and each is independently subject to the maximum — so a datagram carrying more than will fit has some stored and the rest closed.

Several entries MAY share a name.

FDPOLL=0 asks the manager not to monitor the descriptors for error conditions. A manager MAY monitor stored descriptors and remove ones that have become invalid; a manager that does not MUST still accept the field.

4.20.2 Removing #

FDSTOREREMOVE=1 with FDNAME MUST remove every entry of that name and close its descriptors. A name matching nothing is a no-op and MUST NOT be an error.

FDSTOREREMOVE=1 without FDNAME MUST be treated as a malformed line, rejecting the whole datagram (§4.17). A remove with no name has no defined meaning, and the alternative readings — remove everything, remove the default name, do nothing — are far enough apart that guessing between them silently is worse than refusing.

4.20.3 Returning them #

When the service starts again, the manager MUST pass the stored descriptors to the new process:

  1. Placed consecutively, starting at descriptor 3, with close-on-exec cleared.
  2. LISTEN_FDS set to the number of descriptors passed.
  3. LISTEN_FDNAMES set to the names, colon-separated, in the same order as the descriptor numbers.
  4. LISTEN_PID set to the new process's own PID.
  5. The store cleared.

LISTEN_PID is what lets a service verify that the variables are addressed to it rather than inherited from an ancestor. A conforming client checks it against its own PID before trusting LISTEN_FDS, and treats a mismatch as meaning no descriptors were passed — so a manager that omits it hands descriptors to a service that will not take them.

All four variables MUST be absent when no descriptors are passed, and the manager MUST NOT allow any of them to be set by a configurable environment layer. A LISTEN_FDS reaching a service that was passed nothing points its descriptor-adopting code at whatever happens to be at descriptor 3.

Descriptors are returned to the service's main process only. A hook or a probe MUST NOT receive them.

The store MUST be cleared once the descriptors have been passed. The manager MUST NOT clear it when a start attempt fails before that point — the descriptors are still the service's, and the next attempt should get them.

4.20.4 When the store is emptied #

The manager MUST clear the store, closing its descriptors, when:

  • the service is stopped deliberately — by a client, or as part of a system shutdown; or
  • the service's definition is withdrawn and its entry is finally discarded.

The manager MUST NOT clear it on a restart the service did not ask for — a crash, or a restart policy acting on one. That case is the entire purpose of the mechanism: the descriptors survive exactly the restart the service could not prepare for.

Edit this page