--- name: fileno signature: 'fileno FILEHANDLE' signatures: - 'fileno FILEHANDLE' - 'fileno DIRHANDLE' since: 5.0 status: documented categories: ["I/O"] --- ```{index} single: fileno; Perl built-in ``` *[I/O](../perlfunc-by-category)* # fileno Return the OS-level file descriptor number behind a filehandle. `fileno` looks past Perl's buffered filehandle abstraction and gives you the raw integer descriptor the kernel uses. It is the bridge between Perl I/O and system calls that speak descriptors directly — [`select`](select), [`POSIX::dup2`](../../POSIX/dup2), `fcntl`, or anything in `IO::Poll` / `IO::Select`. On a directory handle it asks the same question against `dirfd(3)`, which not every platform provides. ## Synopsis ```perl fileno FILEHANDLE fileno DIRHANDLE fileno EXPR # EXPR evaluated as an indirect handle ``` ## What you get back - An integer `>= 0` — the OS file descriptor — for a normal open handle backed by a real kernel object. - `-1` when the handle is open but has **no** real descriptor. This is what you get for in-memory handles created by [`open`](open) with a scalar reference as the third argument (`open my $fh, ">", \$buf`). - [`undef`](undef) when the handle is closed, never opened, or — on a directory handle — when the platform lacks `dirfd(3)`. In the dirhandle case [`$!`](../perlvar) is set. The three return classes matter. Code that checks `fileno($fh)` for truth conflates "no such fd" with "fd number 0" (STDIN). Always compare explicitly: ```perl my $fd = fileno $fh; die "handle not open" unless defined $fd; die "handle has no real fd" if $fd == -1; ``` ## Global state it touches - [`$!`](../perlvar) — set when `fileno` on a directory handle fails because the platform has no `dirfd(3)` equivalent. `fileno` does not read or write any other I/O globals. It does not flush, it does not seek, it does not change the currently selected handle. ## Examples The common case — turn a Perl filehandle into the fd number a system call wants: ```perl open my $fh, "<", "/etc/hostname" or die $!; print fileno $fh, "\n"; # e.g. "3" ``` Standard handles always have fixed descriptors `0`, `1`, `2`: ```perl print fileno STDIN, "\n"; # 0 print fileno STDOUT, "\n"; # 1 print fileno STDERR, "\n"; # 2 ``` Check whether two handles are duplicates of the same underlying descriptor (the idiom from the upstream POD, adjusted for the `-1` case): ```perl if (fileno($this) != -1 && fileno($this) == fileno($that)) { print "\$this and \$that are dups\n"; } elsif (fileno($this) != -1 && fileno($that) != -1) { print "\$this and \$that have different " . "underlying file descriptors\n"; } else { print "at least one handle has no real file descriptor\n"; } ``` In-memory handles have no kernel object, so `fileno` returns `-1`: ```perl my $buf = ""; open my $mh, ">", \$buf or die $!; print fileno $mh, "\n"; # -1 ``` Build a descriptor bitmap for [`select`](select) — the textbook use for `fileno`: ```perl my $rin = ""; vec($rin, fileno($sock), 1) = 1; vec($rin, fileno(STDIN), 1) = 1; my $n = select(my $rout = $rin, undef, undef, 5.0); ``` Directory handles, where the platform supports `dirfd(3)`: ```perl opendir my $dh, "." or die $!; my $dfd = fileno $dh; if (defined $dfd) { # use with fstat, openat, fchdir, ... } else { warn "no dirfd on this platform: $!"; } ``` ## Edge cases - **Closed handle**: returns [`undef`](undef). No warning under `use warnings` — `fileno` is deliberately quiet so it can be used as a probe. - **Never-opened bareword**: `fileno NOSUCH` returns [`undef`](undef); strict mode will refuse the bareword at compile time unless it's declared. - **In-memory scalar handles**: return `-1`, not [`undef`](undef). Treating `-1` as "open but unusable for system calls" is the intended contract — the handle itself still works for [`print`](print), [`readline`](readline), etc. - **`fileno(-1)` trap**: an explicit `if (fileno $fh) { ... }` is a bug waiting to happen: `fd 0` is STDIN. Use `defined` and compare against `-1` explicitly. - **Indirect filehandle via expression**: if `FILEHANDLE` is any expression other than a bareword or simple scalar, its value is taken as an **indirect handle name** (a string), not as a handle object. To pass a handle held in a data structure, dereference first: ```perl fileno $handles[0]; # indirect: uses the string fileno ${ \$handles[0] }; # still wrong fileno $handles[0]->fileno; # wrong: calling a method on "" my $fh = $handles[0]; fileno $fh; # right ``` - **Directory handle on platforms without `dirfd(3)`**: returns [`undef`](undef) and sets [`$!`](../perlvar). Linux has `dirfd(3)`, so on pperl's supported targets this path is not exercised. - **Tied handles**: `fileno` calls the tie class's `FILENO` method if defined; otherwise returns [`undef`](undef). The tied class is responsible for returning a sensible value (`-1` for "no fd" is the convention). - **Dup'd handles**: two handles opened with [`open`](open) from the same underlying fd (e.g. `open my $copy, ">&", $orig`) return the **new** descriptor, not the original — the dup created a fresh fd. ## Differences from upstream Fully compatible with upstream Perl 5.42. ## See also - [`open`](open) — creates the filehandles that `fileno` inspects; the `>&` and `<&=` modes take descriptor numbers that round-trip through `fileno` - [`opendir`](opendir) — source of directory handles for the dirhandle form of `fileno` - [`close`](close) — after which `fileno` on the same handle returns [`undef`](undef) - [`select`](select) — the four-argument form consumes bitmaps built from `fileno` values - [`binmode`](binmode) — works on the PerlIO layer above the fd; `fileno` reaches beneath it