Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

fcntl(2)

FieldValue
Numbers (x64 / i386 / arm64-generic / arm32)fcntl 72 / 55 / 25 / 55; fcntl64 - / 221 / - / 221 (per-call table below)
Since (kernel)fcntl 1.0; fcntl64 2.4 (32-bit large-file lock variant)
Man pageman2/fcntl.2 (fcntl64.2 is an .so alias of it)
glibc wrapperfcntl() declared in <fcntl.h>, variadic third argument; host glibc 2.41 exports fcntl64@@GLIBC_2.28 (nm -D) – on 64-bit off_t architectures fcntl64 is exported as an alias so old binaries bind; F_* command constants in bits/fcntl-linux.h
Aliases coveredfcntl64
Ledger IDSC-fcntl, SC-fcntl64

Numbers by call, from the ledger and cross-checked against the cached kernel tables (syscall_64.tbl, syscall_32.tbl, syscall_arm.tbl, syscall_generic.tbl):

Callx64i386g64arm32Since
fcntl725525551.0
fcntl64-221-2212.4

fcntl64 is the i386/arm32 variant of the locking commands with 64-bit lock-offset fields (struct flock64); the kernel maps the F_GETLK/F_SETLK/F_SETLKW group onto the *64 forms when the caller is a 32-bit process with large-file support (man2/fcntl.2; ledger SC-fcntl64).

Purpose

fcntl() is the multiplexer for descriptor-level operations: cmd selects one of several unrelated groups. The duplication group makes descriptors (F_DUPFD picks a number >= arg, unlike dup2’s exact target; F_DUPFD_CLOEXEC adds close-on-exec atomically). The descriptor-flags group reads and writes FD_CLOEXEC (F_GETFD/F_SETFD) – per-descriptor state, unlike the file status flags of F_GETFL/F_SETFL, which live on the shared open file description and can only partly be changed after open. The locking group places advisory byte-range locks: traditional process-associated locks (F_SETLK/F_SETLKW/F_GETLK with struct flock) and the Linux-only open file description locks (F_OFD_SETLK/F_OFD_SETLKW/F_OFD_GETLK, 3.15), whose association with the open file description fixes the process-associated model’s close-releases-everything and threads-share-locks hazards. Remaining groups manage signal-driven I/O ownership, leases, dnotify, pipe capacity, memfd seals, and write-lifetime hints. Probe support for a new command at runtime by calling it and checking for EINVAL (man2/fcntl.2).

Synopsis

#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */);

Arguments and behavior

cmd groups (values from /usr/include/x86_64-linux-gnu/bits/fcntl-linux.h, glibc 2.41; “since” from man2/fcntl.2):

CommandValueSincearg and behavior
F_DUPFD01.0int: lowest free descriptor >= arg; EMFILE at the limit; EINVAL for arg < 0 or above the maximum
F_GETFD11.0void: return descriptor flags (arg ignored)
F_SETFD21.0int: set descriptor flags; only defined bit is FD_CLOEXEC
F_GETFL31.0void: return access mode + file status flags
F_SETFL41.0int: set status flags; on Linux only O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, O_NONBLOCK can change; access mode and O_CREAT/O_EXCL/O_NOCTTY/O_TRUNC ignored; O_DSYNC/O_SYNC immutable after open
F_GETLK51.0struct flock *: test; fills l_type F_UNLCK if free, else one conflicting lock (l_pid -1 for an OFD conflict)
F_SETLK61.0struct flock *: acquire (F_RDLCK/F_WRLCK) or release (F_UNLCK); conflict fails EACCES or EAGAIN
F_SETLKW71.0struct flock *: as F_SETLK but block; kernel detects deadlocks and fails one waiter EDEADLK; interrupted waiting gives EINTR
F_SETOWN81.0int: process (positive) or process group (negative) to get SIGIO/SIGURG; needs O_ASYNC via F_SETFL; permission check uses the caller’s saved credentials
F_GETOWN91.0void: return the SIGIO/SIGURG owner
F_SETSIG101.0int: signal to deliver instead of SIGIO; 0 restores SIGIO; nonzero with SA_SIGINFO delivers si_fd
F_GETSIG111.0void: return the configured signal (0 means SIGIO)
F_GETLK64 / F_SETLK64 / F_SETLKW6412 / 13 / 142.464-bit lock-offset forms used on 32-bit ABIs
F_SETOWN_EX / F_GETOWN_EX15 / 162.6.32struct f_owner_ex *: target a thread, process, or process group (F_OWNER_TID/PID/PGRP)
F_OFD_GETLK / F_OFD_SETLK / F_OFD_SETLKW36 / 37 / 383.15struct flock *: open file description locks; l_pid must be 0 on input; no deadlock detection in the current implementation
F_SETLEASE10242.4int F_RDLCK/F_WRLCK/F_UNLCK: take or drop a read/write lease; unprivileged callers need matching file UID, otherwise CAP_LEASE
F_GETLEASE10252.4void: current lease type
F_NOTIFY10262.4int: DN_* directory-change notification, one-shot unless DN_MULTISHOT; superseded by inotify (2.6.13)
F_DUPFD_QUERY1027(header, newer than cached man page)int: test whether two descriptors refer to the same open file description
F_DUPFD_CLOEXEC10302.6.24int: as F_DUPFD with close-on-exec set
F_SETPIPE_SZ / F_GETPIPE_SZ1031 / 10322.6.35int / void: pipe capacity in bytes; unprivileged range [page size, /proc/sys/fs/pipe-max-size], CAP_SYS_RESOURCE may exceed; EBUSY if shrinking below used space; kernel may round up to a power-of-two page multiple and returns the actual size
F_ADD_SEALS10333.17int: add seals (F_SEAL_* below) to the inode; fd must be writable; EPERM if F_SEAL_SEAL already set; EBUSY for F_SEAL_WRITE with a writable shared mapping
F_GET_SEALS10343.17void: current seal mask, 0 if none; EINVAL if the filesystem does not support sealing
F_GET_RW_HINT / F_SET_RW_HINT1035 / 10364.13uint64_t : read/write lifetime hint on the inode (RWH_WRITE_LIFE_ values)
F_GET_FILE_RW_HINT / F_SET_FILE_RW_HINT1037 / 10384.13uint64_t *: same hint on the open file description

F_DUPFD_QUERY and F_SEAL_EXEC (0x0020) are present in the installed glibc 2.41 headers but not described in the cached 2021 man2/fcntl.2; they are header-sourced here and their kernel since-versions are unverified in this session.

Seal values (bits/fcntl-linux.h, __USE_GNU): F_SEAL_SEAL 0x0001 (no further seals), F_SEAL_SHRINK 0x0002 (no truncate/shrink), F_SEAL_GROW 0x0004 (no growth), F_SEAL_WRITE 0x0008 (no content modification), F_SEAL_FUTURE_WRITE 0x0010 (5.1: no new writable mappings or writes, existing mappings keep write access). Seals exist only on memfd_create() files (MFD_ALLOW_SEALING); they are inode properties shared by all descriptors and can never be removed, only added.

Return value and errors

Success value depends on cmd: a new descriptor (F_DUPFD*), the flags/owner/signal/lease/seal mask/pipe capacity for the F_GET* forms, and 0 for the rest. On error, -1 and errno: EACCES or EAGAIN (lock conflict), EAGAIN (mandatory lock with O_NONBLOCK, or file mapped by another process), EBADF (fd not open; F_SETLK/F_SETLKW with a lock type the open mode does not permit), EBUSY (F_SETPIPE_SZ below used space; F_ADD_SEALS with writable shared mapping), EDEADLK (F_SETLKW deadlock detected), EFAULT (lock outside address space), EINTR (F_SETLKW/F_OFD_SETLKW waiting; F_GETLK/F_SETLK/F_OFD_GETLK/F_OFD_SETLKW interrupted before completing, mostly on NFS), EINVAL (unknown cmd; unrecognized seal bit; sealing unsupported; F_DUPFD arg out of range; F_SETSIG invalid signal; F_OFD_* with nonzero l_pid), EMFILE (F_DUPFD limit), ENOLCK (lock table full or remote protocol failure), ENOTDIR (F_NOTIFY on a non-directory), EPERM (clearing O_APPEND on an append-only file; F_SETPIPE_SZ pipe-limit cases; F_ADD_SEALS on a read-only fd or with F_SEAL_SEAL set).

Flags and constants

  • FD_CLOEXEC is the only defined descriptor flag (F_GETFD/F_SETFD).
  • F_SETFL’s changeable set is fixed at O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, O_NONBLOCK (man2/fcntl.2); everything else needs open()/fcntl F_DUPFD dance or a new descriptor.
  • struct flock: l_type (F_RDLCK 1 / F_WRLCK 2 / F_UNLCK 3), l_whence (SEEK_* of lseek.md), l_start, l_len (0 means to end of file, growing with it; negative l_len supported since 2.4.21/2.5.49), l_pid (result field for F_GETLK/F_OFD_GETLK).
  • Locks and reads/writes: read locks need a read-open fd, write locks a write-open fd; locks are advisory by default; mandatory locking requires fs “mand” mount option plus set-GID-no-exec permission bits, is unreliable (man page warning), and was optional via CONFIG_MANDATORY_FILE_LOCKING since 4.5: the option is still present in fs/Kconfig at kernel tag v5.14 and absent at v5.15 and in master (tag-probed this session), so recent kernels dropped the feature.
  • Lost locks: NFS lock loss makes later read()/write() fail EIO until the lock is removed or the fd closed (since 3.12 at least for NFSv4); Linux has no SIGLOST.

Security and notes

  • F_SETFD race: setting FD_CLOEXEC with F_SETFD while another thread runs fork()+execve() can leak the descriptor; use O_CLOEXEC at open()/dup3()/F_DUPFD_CLOEXEC time (man2/fcntl.2; open.md, dup.md).
  • Process-associated lock hazards: closing any fd for a file drops all of that process’s locks on it (a library function that opens and closes a file can silently drop your locks), and threads share the locks; F_OFD_* fixes both, and OFD locks conflict with traditional locks even within one process. Locks are not inherited across fork but survive execve; OFD locks are inherited across fork and released on the last close of the description. stdio buffering makes record locking over stdio(3) unreliable.
  • F_SETOWN permission model: signal delivery is checked like kill(2) using credentials saved at F_SETOWN time; failure silently discards the signal. POSIX specifies F_GETOWN/F_SETOWN only for SIGURG on sockets; SIGIO is not POSIX-specified.
  • Leases: a conflicting open()/truncate() blocks and signals the lease holder (SIGIO by default, F_SETSIG to change); after /proc/sys/fs/lease-break-time seconds the kernel breaks the lease forcibly.

References

  • man2/fcntl.2 in the cached man-pages tree (dated 2021-03-22); .so alias fcntl64.2.
  • Constants: /usr/include/x86_64-linux-gnu/bits/fcntl-linux.h (commands, seals, hints); /usr/include/asm-generic/fcntl.h (lock types).
  • Syscalls ledger rows SC-fcntl, SC-fcntl64; siblings dup, open, readv; domain hub.