When stracing dd (from gnu coreutils) I found something that surprised me:
openat(AT_FDCWD, "/dev/zero", O_RDONLY) = 3
dup2(3, 0) = 0
close(3) = 0
lseek(0, 0, SEEK_CUR) = 0
openat(AT_FDCWD, "/dev/null", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
dup2(3, 1) = 1
close(3) = 0
mmap(NULL, 1060864, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x681e58939000
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1048576) = 1048576
write(1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1048576) = 1048576
read(0, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1048576) = 1048576
write(1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 1048576) = 1048576
close(0) = 0
close(1) = 0
dd opens the files which it should read from / write to and then uses dup2 to change the filedescriptor to the filedescriptors 0 (stdin) and 1 (stdout).
I looked up the code to see if this is done by human or compiler optimization and it is indeed there:
static int
ifd_reopen (int desired_fd, char const *file, int flag, mode_t mode)
{
int ret;
do
{
process_signals ();
ret = fd_reopen (desired_fd, file, flag, mode);
}
while (ret < 0 && errno == EINTR);
return ret;
}
// ...
if (input_file == NULL)
{
input_file = _("standard input");
set_fd_flags (STDIN_FILENO, input_flags, input_file);
}
else
{
if (ifd_reopen (STDIN_FILENO, input_file, O_RDONLY | input_flags, 0) < 0)
die (EXIT_FAILURE, errno, _("failed to open %s"),
quoteaf (input_file));
}
In the following code they use STDIN_FILENO (and STDOUT_FILENO) no matter if dd is told to read from stdin or an file. But the same could have been achieved by simply storing the fd in some variable and use this. Using 2 additional syscalls and a bunch of code just to save 1 int seems not reasonable. So what's the benefit or reusing the fd's of stdin/stdout?