3

Output from strace for non-empty stdin:

execve("./cat", ["./cat"], 0x7fff610af090 /* 37 vars */) = 0 sendfile(1, 0, NULL, 1048576) = 4 sendfile(1, 0, NULL, 1048576) = 0 close(0) = 0 exit(0) = ? +++ exited with 0 +++ 

Output from strace for empty stdin:

execve("./cat", ["./cat"], 0x7fff610af090 /* 37 vars */) = 0 sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument) sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument) sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument) sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument) sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument) sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument) sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument) sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument) sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument) sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument) sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument) sendfile(1, 0, NULL, 1048576) = -1 EINVAL (Invalid argument) ... 

uname -a:5.3.8-arch1-1 #1 SMP PREEMPT @1572357769 x86_64 GNU/Linux

6
  • Did you also update GNU coreutils? Commented Nov 3, 2019 at 16:23
  • I did sudo pacman -Syu --noconfirm, so I think everything got updated. Commented Nov 3, 2019 at 16:34
  • EINVAL looks about the right error if one of the fd's isn't open. Is there a question in here? Commented Nov 3, 2019 at 16:43
  • Shouldn't stdin be open by default? If not how can I force program to open stdin? Commented Nov 3, 2019 at 16:44
  • How was that second command started? Commented Nov 3, 2019 at 17:11

1 Answer 1

0

That seems to be the intended behavior of the sendfile call. Let me cite Linus Torvalds:

sendfile() on purpose only works on things that use the page cache. EINVAL is basically sendfile's way of saying "I would fall back on doing a read+write, so you might as well do it yourself in user space because it might actually be more efficient that way".
(https://yarchive.net/comp/linux/sendfile.html)

So, sendfile will work with stdin only if the kernel knows that stdin is actually a file, not pipe, block device, or anything else.

I wrote a simple program to check it myself:

#include <stdio.h> #include <sys/sendfile.h> int main() { sendfile(fileno(stdout), fileno(stdin), NULL, 8); perror("sendfile failed"); } 

Running it with various redirections clearly shows that the sendfile call is successful only if the input is directly bound to a regular file, empty or not:

$ ./sendfile-test sendfile failed: Invalid argument $ ./sendfile-test < empty.txt sendfile failed: Success $ ./sendfile-test < non-empty.txt (...) sendfile failed: Success $ ./sendfile-test < /dev/null sendfile failed: Invalid argument $ cat empty.txt | ./sendfile-test sendfile failed: Invalid argument $ cat non-empty.txt | ./sendfile-test sendfile failed: Invalid argument $ cat /dev/null | ./sendfile-test sendfile failed: Invalid argument 

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.