Skip to main content
Clarify page size and equality, thanks Chris Davies!
Source Link
Stephen Kitt
  • 480.9k
  • 59
  • 1.2k
  • 1.4k

The first things to note is that device files are allowed to not support seek; perhaps surprisingly, seeking on such files succeeds without moving the position in the file.

Before version 9.6, coreutils tail would try to seek from the end, and calculate an end position based on the position after seeking (however many bytes were requested after the position). Thus with /dev/zero, it would decide it needed to read from position 0 to n. It would then look at the amount of data to read to determine how to read it: if less than a page (in your case 4,096 bytes) or less, it would pipe until the end of the file; if more than a page, it would dump the required number of bytes. Crucially, piping here keeps reading until the end of the file, which never happens! So reading more than a page’s worth of data completes, whereas reading a page or less loops forever.

This was reported as a bug in 2024, with the same expectation as you — that the command should loop. However it was fixed in 9.6 so that reading from such devices never loops.

The first things to note is that device files are allowed to not support seek; perhaps surprisingly, seeking on such files succeeds without moving the position in the file.

Before version 9.6, coreutils tail would try to seek from the end, and calculate an end position based on the position after seeking (however many bytes were requested after the position). Thus with /dev/zero, it would decide it needed to read from position 0 to n. It would then look at the amount of data to read to determine how to read it: if less than a page, it would pipe until the end of the file; if more than a page, it would dump the required number of bytes. Crucially, piping here keeps reading until the end of the file, which never happens! So reading more than a page’s worth of data completes, whereas reading a page or less loops forever.

This was reported as a bug in 2024, with the same expectation as you — that the command should loop. However it was fixed in 9.6 so that reading from such devices never loops.

The first things to note is that device files are allowed to not support seek; perhaps surprisingly, seeking on such files succeeds without moving the position in the file.

Before version 9.6, coreutils tail would try to seek from the end, and calculate an end position based on the position after seeking (however many bytes were requested after the position). Thus with /dev/zero, it would decide it needed to read from position 0 to n. It would then look at the amount of data to read to determine how to read it: if a page (in your case 4,096 bytes) or less, it would pipe until the end of the file; if more than a page, it would dump the required number of bytes. Crucially, piping here keeps reading until the end of the file, which never happens! So reading more than a page’s worth of data completes, whereas reading a page or less loops forever.

This was reported as a bug in 2024, with the same expectation as you — that the command should loop. However it was fixed in 9.6 so that reading from such devices never loops.

Clarify the expectations.
Source Link
Stephen Kitt
  • 480.9k
  • 59
  • 1.2k
  • 1.4k

The first things to note is that device files are allowed to not support seek; perhaps surprisingly, seeking on such files succeeds without moving the position in the file.

Before version 9.6, coreutils tail would try to seek from the end, and calculate an end position based on the position after seeking (however many bytes were requested after the position). Thus with /dev/zero, it would decide it needed to read from position 0 to n. It would then look at the amount of data to read to determine how to read it: if less than a page, it would pipe until the end of the file; if more than a page, it would dump the required number of bytes. Crucially, piping here keeps reading until the end of the file, which never happens! So reading more than a page’s worth of data completes, whereas reading a page or less loops forever.

This was reported as a bug in 2024 and, with the same expectation as you — that the command should loop. However it was fixed in 9.6 so that reading from such devices never loops.

The first things to note is that device files are allowed to not support seek; perhaps surprisingly, seeking on such files succeeds without moving the position in the file.

Before version 9.6, coreutils tail would try to seek from the end, and calculate an end position based on the position after seeking (however many bytes were requested after the position). Thus with /dev/zero, it would decide it needed to read from position 0 to n. It would then look at the amount of data to read to determine how to read it: if less than a page, it would pipe until the end of the file; if more than a page, it would dump the required number of bytes. Crucially, piping here keeps reading until the end of the file, which never happens! So reading more than a page’s worth of data completes, whereas reading a page or less loops forever.

This was reported as a bug in 2024 and fixed in 9.6 so that reading from such devices never loops.

The first things to note is that device files are allowed to not support seek; perhaps surprisingly, seeking on such files succeeds without moving the position in the file.

Before version 9.6, coreutils tail would try to seek from the end, and calculate an end position based on the position after seeking (however many bytes were requested after the position). Thus with /dev/zero, it would decide it needed to read from position 0 to n. It would then look at the amount of data to read to determine how to read it: if less than a page, it would pipe until the end of the file; if more than a page, it would dump the required number of bytes. Crucially, piping here keeps reading until the end of the file, which never happens! So reading more than a page’s worth of data completes, whereas reading a page or less loops forever.

This was reported as a bug in 2024, with the same expectation as you — that the command should loop. However it was fixed in 9.6 so that reading from such devices never loops.

Source Link
Stephen Kitt
  • 480.9k
  • 59
  • 1.2k
  • 1.4k

The first things to note is that device files are allowed to not support seek; perhaps surprisingly, seeking on such files succeeds without moving the position in the file.

Before version 9.6, coreutils tail would try to seek from the end, and calculate an end position based on the position after seeking (however many bytes were requested after the position). Thus with /dev/zero, it would decide it needed to read from position 0 to n. It would then look at the amount of data to read to determine how to read it: if less than a page, it would pipe until the end of the file; if more than a page, it would dump the required number of bytes. Crucially, piping here keeps reading until the end of the file, which never happens! So reading more than a page’s worth of data completes, whereas reading a page or less loops forever.

This was reported as a bug in 2024 and fixed in 9.6 so that reading from such devices never loops.