Вы должны убедиться, что STDOUT_FILENO
не открывается в режиме добавления, или вторая splice(2)
не будет работать, как описано в его manpage :
EINVAL
Целевой файл открывается в режиме добавления.
И да, это произойдет, даже если это так, где флаг O_APPEND
не должен иметь никакого значения, что очень похоже на ошибка . Или, по крайней мере, неприятность, тем более что splice
не волнует, когда в сокете или канале установлен флаг O_APPEND
.
Попробуйте запустить вашу программу как
./your_program file >/dev/tty
или #include <fcntl.h>
и добавьте это в начале вашей функции main()
:
if(isatty(1)) fcntl(1, F_SETFL, fcntl(1, F_GETFL) & ~O_APPEND);
Обратите внимание, что флаг O_APPEND
может привести к случайному включению на вашем терминале: чтобы проверить, включен ли он, посмотрите на /proc/<pid>/fdinfo/<fd>
:
$ grep flags /proc/self/fdinfo/1
flags: 0102002
^ here it is
Один любопытный пример программы, которая включает флаг O_APPEND
на своем стандартном выводе: GNU make ; -)
$ strace -e trace=fcntl make
fcntl(1, F_GETFL) = 0x48002 (flags O_RDWR|O_LARGEFILE|O_NOATIME)
fcntl(1, F_SETFL, O_RDWR|O_APPEND|O_LARGEFILE|O_NOATIME) = 0
...
Контрольный пример, scat.c
:
/*
* a simple program which copies its input to its output via splice(2)
* if given a '1' argument, it will turn the O_APPEND flag on stdout
* if given a '0' argument, it will turn it off
* otherwise it will leave it as it is
*/
#define _GNU_SOURCE 1
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <err.h>
int main(int ac, char **av){
ssize_t z; int fl;
if(ac > 1){
if((fl = fcntl(1, F_GETFL)) == -1) err(1, "fcntl(1, getfl)");
if(atoi(av[1])) fl |= O_APPEND;
else fl &= ~O_APPEND;
if(fcntl(1, F_SETFL, fl)) err(1, "fcntl(1, setfl, %x)", fl);
}
while((z = splice(0, 0, 1, 0, 65536, 0)))
if(z < 0) err(1, "splice");
}
$ cc -Wall scat.c -o scat
$ echo yup | ./scat
yup
$ echo yup | ./scat 1
scat: splice: Invalid argument
$ echo yup | ./scat
scat: splice: Invalid argument
$ echo yup | ./scat 0
yup
$ echo yup | ./scat
yup
OK с выводом трубы или розетки:
$ echo yup | ./scat 1 | cat
yup
$ nc -l -p 9999 &
[4] 23952
$ echo yup | ./scat 1 | nc -q0 localhost 9999
yup
[4]- Done nc -l -p 9999