使用 splice 系统调用没有输出
No output using splice syscall
我有以下代码:
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char **argv) {
if(argc < 2) {
fputs("Error: You must provide an filename\n", stderr);
return 1;
}
FILE *handle = fopen(argv[1], "r");
if(!handle) {
perror("Error opening file:");
goto error;
}
int handle_fd = fileno(handle);
int filedes[2];
if(pipe(filedes)) {
perror("Error creating pipe:");
goto error;
}
while(1) {
ssize_t rc = splice(handle_fd, NULL, filedes[1], NULL, BUFSIZ, 0);
if(rc == -1) {
// Error occurred
perror("Error copying data:");
goto error;
} else if(rc == 0) {
break;
}
splice(filedes[0], NULL, STDOUT_FILENO, NULL, BUFSIZ, 0);
}
return 0;
error:
if(fclose(handle)) {
perror("Error closing file:");
}
return 1;
}
当我 运行 它时,我没有得到任何输出。 None 的 perror 调用也被触发,我不知道为什么它不起作用。
当我 运行 GDB 中的程序运行时,但是当 运行ning 只是从 shell
中简单显示时它不显示任何内容
您应该检查 STDOUT_FILENO
是否未在追加模式下打开,否则第二个 splice(2)
将失败,如其 manpage:
中所述
EINVAL
The target file is opened in append mode.
是的,即使它是一个 tty 也会发生这种情况,O_APPEND
标志应该没有任何区别,这看起来很像 bug。或者至少是一个麻烦,特别是因为 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
一个奇怪的例子是 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
可以将管道或套接字作为输出:
$ 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
我有以下代码:
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char **argv) {
if(argc < 2) {
fputs("Error: You must provide an filename\n", stderr);
return 1;
}
FILE *handle = fopen(argv[1], "r");
if(!handle) {
perror("Error opening file:");
goto error;
}
int handle_fd = fileno(handle);
int filedes[2];
if(pipe(filedes)) {
perror("Error creating pipe:");
goto error;
}
while(1) {
ssize_t rc = splice(handle_fd, NULL, filedes[1], NULL, BUFSIZ, 0);
if(rc == -1) {
// Error occurred
perror("Error copying data:");
goto error;
} else if(rc == 0) {
break;
}
splice(filedes[0], NULL, STDOUT_FILENO, NULL, BUFSIZ, 0);
}
return 0;
error:
if(fclose(handle)) {
perror("Error closing file:");
}
return 1;
}
当我 运行 它时,我没有得到任何输出。 None 的 perror 调用也被触发,我不知道为什么它不起作用。
当我 运行 GDB 中的程序运行时,但是当 运行ning 只是从 shell
中简单显示时它不显示任何内容您应该检查 STDOUT_FILENO
是否未在追加模式下打开,否则第二个 splice(2)
将失败,如其 manpage:
EINVAL
The target file is opened in append mode.
是的,即使它是一个 tty 也会发生这种情况,O_APPEND
标志应该没有任何区别,这看起来很像 bug。或者至少是一个麻烦,特别是因为 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
一个奇怪的例子是 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
可以将管道或套接字作为输出:
$ 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