read(2)

๐ŸŒธ read(2) โ€” or, "bestie, get me those bytes" ๐ŸŒธ

okay so this is the read(2) page from the Linux man-pages โ€” you know, the manual's abbr is read(2) and it lives in the System Calls Manual section. it's the libc party. let's get into it ๐Ÿ’–


โœจ NAME โœจ

read โ€” read from a file descriptor

๐Ÿ“š LIBRARY ๐Ÿ“š

Standard C library (libc, -lc) โ€” like, the normal one, no extra linking drama ๐Ÿ’…

๐ŸŽ€ SYNOPSIS ๐ŸŽ€

#include <unistd.h>

ssize_t read(size_t count;
             int fd, void buf[count], size_t count);

yes bestie that's literally how it's printed, don't come for me ๐Ÿ™ˆ

๐Ÿฆ‹ DESCRIPTION ๐Ÿฆ‹

so read() tries to read up to count bytes out of the file descriptor fd, and dumps them into the buffer that starts at buf. that's the whole gig. iconic. โœจ

on files that support seeking, the read kicks off at the file offset, and then the file offset gets bumped up by however many bytes were actually read. and if the file offset is sitting at or past the end of the file? then nothing gets read, and read() just returns zero. end of story, no bytes, bye ๐Ÿ‘‘

if count is zero, read() may still spot the errors listed below. but if there are no errors โ€” or if read() doesn't even bother checking for errors โ€” then a read() with a count of 0 returns zero and does literally nothing else. zero effort, zero consequences, main character energy ๐Ÿ’€

and per POSIX.1: if count is bigger than SSIZE_MAX, the result is implementation-defined ๐Ÿ˜ญ โ€” for the upper limit on Linux, scroll down to NOTES, bestie.


๐ŸŒˆ RETURN VALUE ๐ŸŒˆ

on success you get back the number of bytes read (and if that number is zero, that means end of file ๐Ÿฅบ), and the file position gets advanced by that same number.

and listen โ€” it is NOT an error if that number is smaller than the number of bytes you asked for. totally normal, happens all the time, e.g. because fewer bytes are actually available right now (maybe you're close to end-of-file, maybe you're reading from a pipe, maybe it's a terminal), or because read() got interrupted by a signal. see also NOTES, bestie.

on error, -1 comes back and errno gets set to tell you what went wrong. in that case, whether the file position (if there even is one) changes is left unspecified โ€” so like, don't count on it. ๐Ÿ™ˆ


๐Ÿ’€ ERRORS ๐Ÿ’€

okay here's the whole roster, no skips:

  • EAGAIN โ€” the fd fd points at a file that is not a socket and it's been marked nonblocking (O_NONBLOCK), and the read would block. for more on the O_NONBLOCK flag, go peep open(2).
  • EAGAIN or EWOULDBLOCK โ€” the fd fd points at a socket and it's been marked nonblocking (O_NONBLOCK), and the read would block. POSIX.1-2001 says either of these errors is allowed here, and it does not require the two constants to have the same value โ€” so if you want your app to be portable, check for both possibilities, periodt.
  • EBADF โ€” fd is not a valid file descriptor, or it's not open for reading. sorry babe, no reading privileges ๐Ÿšซ
  • EFAULT โ€” buf is outside your accessible address space. that memory is not yours, bestie, don't touch it.
  • EINTR โ€” the call got interrupted by a signal before any data was read. see signal(7) for the lore.
  • EINVAL โ€” fd is attached to an object that's unsuitable for reading. OR: the file was opened with the O_DIRECT flag, and either the address given in buf, the value given in count, or the file offset is not suitably aligned. (alignment girlies, you know who you are ๐Ÿ’…)
  • EINVAL โ€” fd was created by a call to timerfd_create(2) and you handed read() a buffer of the wrong size. see timerfd_create(2) for more.
  • EIO โ€” I/O error. this one shows up, for example, when the process is in a background process group, tries to read from its controlling terminal, and either it's ignoring or blocking SIGTTIN, or its process group is orphaned ๐Ÿ˜ญ. it can also happen when there's a low-level I/O error while reading from a disk or a tape. and one more possible cause of EIO on networked filesystems: an advisory lock had been taken out on the file descriptor and that lock got lost. see the Lost locks section of fcntl(2) for the details.
  • EISDIR โ€” fd refers to a directory. bestie, that's a folder, not a file ๐Ÿ“
  • Other errors may occur, depending on the object connected to fd โ€” so like, surprises are possible. stay safe out there โœจ

โญ STANDARDS โญ

POSIX.1-2008. certified. ๐Ÿ‘‘

๐Ÿงš HISTORY ๐Ÿงš

SVr4, 4.3BSD, POSIX.1-2001. ancient lineage, still slaying ๐ŸŽ€


๐Ÿ”ฅ NOTES ๐Ÿ”ฅ

on Linux, read() (and its similar system calls) will transfer at most 0x7ffff000 (2,147,479,552) bytes, and it returns the number of bytes it actually transferred. and yes, this holds on both 32-bit and 64-bit systems, no cap. ๐Ÿซถ

on NFS filesystems, reading small amounts of data will update the timestamp only the first time โ€” subsequent calls might not do it. why? client side attribute caching, bestie: most (if not all) NFS clients leave st_atime (the last file access time) updates up to the server, and client-side reads that get satisfied out of the client's cache will not cause st_atime updates on the server, because there were no server-side reads at all. you can get UNIX semantics back by disabling client-side attribute caching, but in most situations that will substantially increase server load and decrease performance. so, like, pick your struggle ๐Ÿ™ˆ


๐Ÿ› BUGS ๐Ÿ›

according to POSIX.1-2008/SUSv4 Section XSI 2.9.7 ("Thread Interactions with Regular File Operations"):

All of the following functions shall be atomic with respect to each other in the effects specified in POSIX.1-2008 when they operate on regular files or symbolic links: ...

among the APIs listed after that are read() and readv(2). and among the effects that should be atomic across threads (and processes) are updates of the file offset. however โ€” before Linux 3.14, this was not the case ๐Ÿ˜ญ. if two processes sharing an open file description (see open(2)) performed a read() (or readv(2)) at the same time, then the I/O operations were not atomic when it came to updating the file offset, and the result was that the reads in the two processes might (incorrectly!) overlap in the blocks of data they got. this problem was fixed in Linux 3.14. so if you're on something older than thatโ€ฆ thoughts and prayers ๐Ÿ’€


๐Ÿ‘‘ SEE ALSO ๐Ÿ‘‘

close(2), fcntl(2), ioctl(2), lseek(2), open(2), pread(2), readdir(2), readlink(2), readv(2), select(2), write(2), fread(3)


and that's the whole page, bestie, no notes ๐Ÿ’– this was Linux man-pages 6.20, dated 2026-02-08, and yes the page itself is literally called read(2). go read some bytes. drink water. mwah ๐Ÿซถโœจ๐ŸŽ€

๐Ÿ“ฆ where this page comes from
  • arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
  • nixpkgs unstable: man-pages 6.20
  • ๐Ÿ“œ the page's license: Linux-man-pages-copyleft
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms